https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126508
Bug ID: 126508
Summary: Incorrect caching of constexpr functions which rethrow
Product: gcc
Version: 16.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: jakub at gcc dot gnu.org
Target Milestone: ---
constexpr int
foo ()
{
try
{
throw;
}
catch (const int x)
{
return x;
}
}
constexpr int
bar (int x)
{
try
{
throw x;
}
catch (...)
{
return foo ();
}
}
static_assert (bar (42) == 42);
static_assert (bar (43) == 43);
fails on the second assertion, because we cache the foo () result, even when it
has a hidden argument - the currently pending exception.
Currently we don't cache if the function calls any of the metafunctions, makes
some heap allocations which it doesn't deallocate or deletes something it
hasn't allocated, but I'm afraid rethrow is another case that shouldn't be
cached (unless we can prove that it was a rethrow of something thrown during
that function).
I guess examples of other cases that can depend on the state from the caller
are
__builtin_current_exception () and __builtin_uncaught_exceptions () (those will
again do something different depending on if the caller has uncaught or caught
exceptions).
Or perhaps also __builtin_eh_ptr_adjust_ref which can increment or decrement a
reference count of an exception.
One possibility is for all of those set ctx->global->metafns_called = true;
(even when it will be misnamed because of that).
Not caching anything if ctx->global.uncaught_exceptions ||
!ctx->global->caught_exceptions.is_empty () before the call, or both that
condition before the call and one of the problematic functions being called
during the call, would not work properly, because we could cache in a function
called when no exceptions are uncaught or caught and then use cached value in
some other cases where they are uncaught or caught.