struct function_next_check : public traversing_visitor
{
functiondecl* current_function;
- set<functiondecl*>& function_next;
- function_next_check(set<functiondecl*>& fn)
- : current_function(0), function_next(fn) { }
+ function_next_check()
+ : current_function(0) { }
void visit_next_statement(next_statement*)
{
- function_next.insert(current_function);
+ current_function->has_next = true;
}
void visit_embeddedcode(embeddedcode* s)
{
if (s->code.find("STAP_NEXT;") != string::npos)
- function_next.insert(current_function);
+ current_function->has_next = true;
}
};
{
systemtap_session& s;
bool& relaxed_p;
- const set<functiondecl*>& function_next;
dead_overload_remover(systemtap_session& sess,
- bool& r,
- const set<functiondecl*>& fn)
- : s(sess), relaxed_p(r), function_next(fn) { }
+ bool& r)
+ : s(sess), relaxed_p(r) { }
void visit_functioncall(functioncall* e);
};
functiondecl* r = e->referents[fd];
// Note that this is not a sound inference but it suffices for most
- // cases. We simply use the presence of a 'next' statement as an indicator
+ // cases. It may be the case that there is a 'next' statement in the
+ // function that will never be executed by the control flow.
+ // We simply use the presence of a 'next' statement as an indicator
// of a potential fall through. Once a function can't be 'nexted' the
// remaining functions are unreachable.
- if (chained && function_next.find(r) != function_next.end())
+ if (chained && r->has_next)
reachable++;
else
chained = false;
static void semantic_pass_overload(systemtap_session& s, bool& relaxed_p)
{
set<functiondecl*> function_next;
- function_next_check fnc(function_next);
+ function_next_check fnc;
for (auto it = s.functions.begin(); it != s.functions.end(); ++it)
{
for (auto it = s.probes.begin(); it != s.probes.end(); ++it)
{
- dead_overload_remover ovr(s, relaxed_p, function_next);
+ dead_overload_remover ovr(s, relaxed_p);
(*it)->body->visit(&ovr);
}
for (auto it = s.functions.begin(); it != s.functions.end(); ++it)
{
- dead_overload_remover ovr(s, relaxed_p, function_next);
+ dead_overload_remover ovr(s, relaxed_p);
it->second->body->visit(&ovr);
}
}
yield = true;
}
- if (e->referents.size() > 1)
+ if (e->referents.size() > 1 && r != e->referents.back())
// branch to end of the enclosing statement-expression if one of the
// function alternatives is selected
o->newline() << "if (!c->next) goto fc_end_" << fc_counter << ";";
o->newline() << "fc_end_" << fc_counter++ << ":";
}
- // check for aborted return from function; this could happen from non-overloaded ones too
- o->newline() << "if (unlikely(c->next)) { c->last_error = \"all functions exhausted\"; goto out; }";
+ if (e->referents.back()->has_next)
+ // check for aborted return from function; this could happen from non-overloaded ones too
+ o->newline() << "if (unlikely(c->next)) { c->last_error = \"all functions exhausted\"; goto out; }";
// return result from retvalue slot NB: this must be last, for the
// enclosing statement-expression ({ ... }) to carry this value.