[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-14 Thread cvs-commit at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #41 from GCC Commits  ---
The master branch has been updated by Jonathan Wakely :

https://gcc.gnu.org/g:9b6b7fed78c5d3514a180f7ae9f7d86824f45735

commit r16-2228-g9b6b7fed78c5d3514a180f7ae9f7d86824f45735
Author: Jonathan Wakely 
Date:   Fri Jul 11 23:49:27 2025 +0100

libstdc++: Correct value of __cpp_lib_constexpr_exceptions [PR117785]

Only P3068R6 (Allowing exception throwing in constant-evaluation) is
implemented in the library so far, so the value of the
constexpr_exceptions feature test macro should be 202411L. Once we
support the library changes in P3378R2 (constexpr exception types) then
we can set the value to 202502L again.

libstdc++-v3/ChangeLog:

PR libstdc++/117785
* include/bits/version.def (constexpr_exceptions): Define
correct value.
* include/bits/version.h: Regenerate.
* libsupc++/exception: Check correct value.
* testsuite/18_support/exception/version.cc: New test.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #40 from Jason Merrill  ---
(In reply to Jakub Jelinek from comment #34)
> Anyway, will defer this to Jason, the change to only do what() printing if
> derived from std::exception was fairly small and can be always reverted if
> there is agreement on that.

My perspective is that what() in an exception isn't an established general
pattern based on name lookup like e.g. begin(), it's a convention of the
std::exception hierarchy.  So it seems a stretch to expect it to do something
similar for other thrown types.  But if the committee wants to move in that
direction I don't object.

(In reply to Hana Dusíková from comment #35)
> Btw another thing ... Jakub, how do you feel about disabling
> `-fno-exception` in consteval code or even constexpr code which doesn't
> result in codegen?

As I told Corentin when he asked a month ago, this seems like a lot more
trouble than it's worth.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #39 from Jakub Jelinek  ---
Sorry for screwing the value and I didn't see it should be in  too.
I think only P3378R2 adds it to the further headers.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #38 from Jonathan Wakely  ---
I'll fix that, thanks.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread hanicka at hanicka dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #37 from Hana Dusíková  ---
Btw I have noticed you touched the library, btu the feature test macro is
defined only in , not in  and also the value is 202502L,
which is only when , , ,  exceptions
will be constexpr (as specified P3378), if you don't have it it should be
202411L same as __cpp_constexpr_exceptions (as specified in P3068).

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #36 from Jakub Jelinek  ---
I think that would be weird, because it changes behavior between constant
evaluation and runtime.  And very hard to implement at least on the GCC side. 
The constant evaluation is on IL which already includes calls like
__cxa_throw_bad_array_new_length() or not depending on -fexceptions etc., plus
preprocessor flags like __cpp_exceptions are defined based on -fexceptions or
-fno-exceptions, so the code being parsed already might take into account
whether exceptions can or can't happen.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread hanicka at hanicka dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #35 from Hana Dusíková  ---
Btw another thing ... Jakub, how do you feel about disabling `-fno-exception`
in consteval code or even constexpr code which doesn't result in codegen?

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #34 from Jakub Jelinek  ---
It is true that trying to evaluate it just in case can do less harm than if it
is at runtime.  That said, e.g. with the constexpr printing it can print
different messages and a script can launch missiles or format disk if it sees
such messages in the compiler output.
Anyway, will defer this to Jason, the change to only do what() printing if
derived from std::exception was fairly small and can be always reverted if
there is agreement on that.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread hanicka at hanicka dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #33 from Hana Dusíková  ---
(In reply to Jonathan Wakely from comment #32)
> ... at compile-time does it matter if the what() function does something
> else? It can't launch missiles or format hard drives during consteval. The
> worst it can do is print garbage to the terminal, but a type derived from
> std::exception could do that too.

It doesn't, constant evaluation is finishing (same as checking for memory leak)
and you can still call the .what() on it, but there can't be any side-effect
and your program is already ill-formed.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #32 from Jonathan Wakely  ---
(In reply to Hana Dusíková from comment #28)
> (In reply to Jakub Jelinek from comment #27)
> > Jason Merrill asked for that during patch review:
> > https://gcc.gnu.org/pipermail/gcc-patches/2025-July/688997.html
> > "This will work for any class type with a what() method, which is 
> > different from vterminate.cc that only calls what() for a type derived 
> > from std::exception.  I think it makes sense to be consistent with that; 
> > a what() from an unrelated class might mean something different."

This is true, but thinking about it further ...

> Okay, what I tried (and failed to my limited knowledge of doing it lowlevel
> without AST present) is to allow any `constexpr const` overload of `what`
> without arguments which returns pointer to any char type or anything which
> has `.size()` and `.data()` returning pointer to any char type.

... at compile-time does it matter if the what() function does something else?
It can't launch missiles or format hard drives during consteval. The worst it
can do is print garbage to the terminal, but a type derived from std::exception
could do that too.

If the type wasn't intended to be used as an exception, it wouldn't have been
thrown by the program!


I suppose all the same arguments apply at runtime but executing arbitrary code
at runtime does seem more worrying, even though it's true that somebody could
do:

struct Evil : std::exception {
  const char* what() const override { system("rm -rf /"); }
};

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #31 from Jakub Jelinek  ---
what() is printed if derived from std::exception, constexpr, etc.
E.g.
/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/constexpr-eh9.C:108:23:   in
'constexpr' expansion of 'bar(1)'
/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/constexpr-eh9.C:82:1: error:
'std::terminate' called after throwing an exception of type 'S'; 'what()':
'this is S'
/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/constexpr-eh9.C:82:1: note: uncaught
exception exited from 'noexcept' function 'constexpr int bar(int)'
or
/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/constexpr-eh9.C:123:25: error: uncaught
exception of type 'T'; 'what()': 'hello, world'
Or it prints the content of the exception object, like:
/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/constexpr-eh9.C:110:23:   in
'constexpr' expansion of 'bar(3)'
/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/constexpr-eh9.C:82:1: error:
'std::terminate' called after throwing an exception 'U{1, -2, 42}'
/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/constexpr-eh9.C:82:1: note: uncaught
exception exited from 'noexcept' function 'constexpr int bar(int)'
or
/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/constexpr-eh9.C:125:25: error: uncaught
exception '42'
Or as last fallback it prints just the type
/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/constexpr-eh12.C:71:49: error: uncaught
exception of type 'E*'
This was e.g. when E is a class with int * member initialized by new int, in
that case printing the value is I think not what users want to see.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread hanicka at hanicka dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #30 from Hana Dusíková  ---
Core told me to take the note out because there is no exception in moment I'm
printing error, because it's not valid constant evaluation therefore invalid
program. Which seems legal technicality. Btw did you try to print content of
the type in case there is no `what()`? It can be helpful too.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #29 from Jakub Jelinek  ---
For std::exception or classes derived from it the standard documents what
what() means.  For other classes the standard doesn't say anything on those,
even if it has const char * return type and is constexpr it could do anything
else.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread hanicka at hanicka dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #28 from Hana Dusíková  ---
(In reply to Jakub Jelinek from comment #27)
> (In reply to Hana Dusíková from comment #26)
> > (In reply to Jakub Jelinek from comment #25)
> > > In the end this is done only for classes derived from std::exception, to
> > > match e.g. the verbose terminate handler at runtime.
> > 
> > I wonder why?
> 
> Jason Merrill asked for that during patch review:
> https://gcc.gnu.org/pipermail/gcc-patches/2025-July/688997.html
> "This will work for any class type with a what() method, which is 
> different from vterminate.cc that only calls what() for a type derived 
> from std::exception.  I think it makes sense to be consistent with that; 
> a what() from an unrelated class might mean something different."

Okay, what I tried (and failed to my limited knowledge of doing it lowlevel
without AST present) is to allow any `constexpr const` overload of `what`
without arguments which returns pointer to any char type or anything which has
`.size()` and `.data()` returning pointer to any char type. Because then I can
do the formatting only when `what()` is evaluated. But this interpretation of
wording is also correct.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #27 from Jakub Jelinek  ---
(In reply to Hana Dusíková from comment #26)
> (In reply to Jakub Jelinek from comment #25)
> > In the end this is done only for classes derived from std::exception, to
> > match e.g. the verbose terminate handler at runtime.
> 
> I wonder why?

Jason Merrill asked for that during patch review:
https://gcc.gnu.org/pipermail/gcc-patches/2025-July/688997.html
"This will work for any class type with a what() method, which is 
different from vterminate.cc that only calls what() for a type derived 
from std::exception.  I think it makes sense to be consistent with that; 
a what() from an unrelated class might mean something different."

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-11 Thread hanicka at hanicka dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #26 from Hana Dusíková  ---
(In reply to Jakub Jelinek from comment #25)
> In the end this is done only for classes derived from std::exception, to
> match e.g. the verbose terminate handler at runtime.

I wonder why? Is there technical reason? Originally I wanted to have a note in
[expr.const] to encourage compilers to look into `E.what()` and at least in my
prototype I'm aware of the type. Is something different in GCC's evaluator?

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-10 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #25 from Jakub Jelinek  ---
(In reply to Hana Dusíková from comment #1)
> It's not part of the wording as CWG told me to take it out. But it's very
> useful when an exception is not caught to call it's `.what()` and print
> resulting message as part of the error. If there is no `.what()` available,
> just print it structurally.

In the end this is done only for classes derived from std::exception, to match
e.g. the verbose terminate handler at runtime.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-10 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

Jakub Jelinek  changed:

   What|Removed |Added

   Target Milestone|--- |16.0
 Resolution|--- |FIXED
 Status|ASSIGNED|RESOLVED

--- Comment #24 from Jakub Jelinek  ---
Implemented for GCC 16.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-07-10 Thread cvs-commit at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #23 from GCC Commits  ---
The master branch has been updated by Jakub Jelinek :

https://gcc.gnu.org/g:baaee10123db6cf896283175b345d535b225defb

commit r16-2183-gbaaee10123db6cf896283175b345d535b225defb
Author: Jakub Jelinek 
Date:   Thu Jul 10 23:26:15 2025 +0200

c++, libstdc++: Implement C++26 P3068R5 - constexpr exceptions [PR117785]

The following patch implements the C++26 P3068R5 - constexpr exceptions
paper.

As the IL cxx_eval_constant* functions process already contains the low
level calls like __cxa_{allocate,free}_exception, __cxa_{,re}throw etc.,
the patch just makes 10 extern "C" __cxa_* functions magic builtins which
during constant evaluation pretend to be constexpr even when not declared
so and handle them directly, plus does the same for 3 std namespace
functions - std::uncaught_exceptions, std::current_exception and
std::rethrow_exception and adds one new FE builtin -
__builtin_eh_ptr_adjust_ref which the library can use instead of the
_M_addref and _M_release out of line methods (this one instead of
recognizing _M_* as magic too because those are clearly specific to
libstdc++ and e.g. libc++ could use something else).

The patch uses magic VAR_DECLs with heap_{uninit_,,deleted_}identifier
DECL_NAME like for operator new/delete for objects allocated with
__cxa_allocate_exception, just sets their DECL_LANG_SPECIFIC so that
we can track their reference count as well (with std::exception_ptr
the same exception object can be referenced multiple times and we want
to destruct and free only when it reaches zero refcount).

For uncaught exceptions being propagated, the patch uses new kind of
*jump_target, which is that magic VAR_DECL described above.
The largest change in the patch is making jump_target argument non-optional
in cxa_eval_constant_exception and all functions it calls that need it.
This is because exceptions can be thrown from pretty much everywhere, e.g.
binary expression can throw in either operand.  And the patch also adds
if (*jump_target) return NULL_TREE; or similar in many spots, so that we
don't crash because cxx_eval_constant_expression returned NULL_TREE
somewhere before actually trying to use it and so that we don't uselessly
dive into other operands etc.
Note, with statement expressions actually this was something we just didn't
handle correctly before, one can validly have:
  a = ({ if (x) return 42; 12; }) + b;
or in the other operand, or break/continue instead of return if it is
somewhere in a loop/switch; and it isn't ok to branch from one operand to
another one through some kind of goto.

On the potential_constant_expression_1 side, important change was to
set *jump_target conservatively on calls that could throw for C++26 (the
patch uses magic void_node for potential_constant_expression* instead of
VAR_DECL, so that we don't have to create new VAR_DECLs there uselessly).
Without that change, several methods in libstdc++ wouldn't work correctly.
I'm not sure what exactly potential_constant_expression_1 maps to in the
C++26 standard wording now and whether doing that is ok, because basically
after the first call to non-noexcept function it stops checking stuff.

And, in some spots where I know potential_constant_expression_1 didn't
check some subexpressions (e.g. the EH only cleanups or TRY_BLOCK handlers)
I've added *potential_constant_expression* calls during cxx_eval_constant*,
not sure if I need to do that because potential_constant_expression_1 is
very conservative and just doesn't recurse on subexpressions in many cases.

2025-07-10  Jakub Jelinek  

PR c++/117785
gcc/c-family/
* c-cppbuiltin.cc (c_cpp_builtins): Predefine
__cpp_constexpr_exceptions=202411L for C++26.
gcc/cp/
* constexpr.cc: Implement C++26 P3068R5 - constexpr exceptions.
(class constexpr_global_ctx): Add caught_exceptions and
uncaught_exceptions members.
(constexpr_global_ctx::constexpr_global_ctx): Initialize
uncaught_exceptions.
(returns, breaks, continues, switches): Move earlier.
(throws): New function.
(exception_what_str, diagnose_std_terminate,
diagnose_uncaught_exception): New functions.
(enum cxa_builtin): New type.
(cxx_cxa_builtin_fn_p, cxx_eval_cxa_builtin_fn): New functions.
(cxx_eval_builtin_function_call): Add jump_target argument.  Call
cxx_eval_cxa_builtin_fn for __builtin_eh_ptr_adjust_ref.  Adjust
cxx_eval_constant_expression calls, if it results in jmp_target,
set *jump_target to it and return.
(cxx_bind_parameters_in_call): Add jump_target argument.  Pass
it through to

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-30 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

Jakub Jelinek  changed:

   What|Removed |Added

  Attachment #61549|0   |1
is obsolete||

--- Comment #22 from Jakub Jelinek  ---
Created attachment 61554
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61554&action=edit
gcc16-pr117785-wip.patch

Another day of work, getting there.
Get now an ICE on the constexpr-eh13.C testcase and still need to run full
testsuite to see what else needs adjusting for -std=c++26, but the rest should
be implemented.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-29 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

Jakub Jelinek  changed:

   What|Removed |Added

  Attachment #61546|0   |1
is obsolete||

--- Comment #21 from Jakub Jelinek  ---
Created attachment 61549
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61549&action=edit
gcc16-pr117785-wip.patch

Further progress.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-29 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

Jakub Jelinek  changed:

   What|Removed |Added

  Attachment #61540|0   |1
is obsolete||

--- Comment #20 from Jakub Jelinek  ---
Created attachment 61546
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61546&action=edit
gcc16-pr117785-wip.patch

Further progress.

My current problem is with std::nested_exception (but guess arbitrary code
which uses std::current_exception () or perhaps std::uncaught_exceptions ()).
In the testcase I have (simplified):
try
  {
throw 42;
  }
catch (...)
  {
std::nested_exception c;
if (c.nested_ptr () == nullptr)
  return -1;
  }
and -1 is the return value I'm getting but don't expect.
The problem is that when parsing the c declaration, we try to constant evaluate
the constructor just in case it can be constructed without a call, and there
current_exception () returns { nullptr } because it isn't evaluated with an
active exception at that point.

Shall the two functions just give up when not manifestly constant-evaluated? 
Or non-strict?

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-28 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

Jakub Jelinek  changed:

   What|Removed |Added

  Attachment #61528|0   |1
is obsolete||

--- Comment #19 from Jakub Jelinek  ---
Created attachment 61540
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61540&action=edit
gcc16-pr117785-wip.patch

Further progress, still need to debug std::rethrow_exception, adjust testsuite
not yet tested for C++26 changes if throw appears (so far adjusted just the
C++20 dynamic_cast/typeid ones) and maybe add helper to evaluate what () and
print it in the diagnostics.
Also maybe add some flags on MUST_NOT_THROW_EXPR to differentiate the reasons
why it has been emitted into the IL and take it into account in the
diagnostics.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-28 Thread hanicka at hanicka dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #18 from Hana Dusíková  ---
(In reply to Jakub Jelinek from comment #16)
> So, the paper added also the new case to
> https://eel.is/c++draft/expr.const#10.27
> but
> https://eel.is/c++draft/expr.new#8.5
> has not been changed and still says that say new int[-1] in constexpr
> function is ill-formed.  So, when should one expect
> std::bad_array_new_length() to be actually thrown (except when throwing it
> manually)?

I don't think`-1` doesn't make it "potentially-evaluated core constant
expression".

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-28 Thread hanicka at hanicka dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #17 from Hana Dusíková  ---
(In reply to Jakub Jelinek from comment #16)
> So, the paper added also the new case to
> https://eel.is/c++draft/expr.const#10.27
> but
> https://eel.is/c++draft/expr.new#8.5
> has not been changed and still says that say new int[-1] in constexpr
> function is ill-formed.  So, when should one expect
> std::bad_array_new_length() to be actually thrown (except when throwing it
> manually)?

Only when you allocate size bigger than a limit of allocation.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-28 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #16 from Jakub Jelinek  ---
So, the paper added also the new case to
https://eel.is/c++draft/expr.const#10.27
but
https://eel.is/c++draft/expr.new#8.5
has not been changed and still says that say new int[-1] in constexpr function
is ill-formed.  So, when should one expect std::bad_array_new_length() to be
actually thrown (except when throwing it manually)?

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-27 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

Jakub Jelinek  changed:

   What|Removed |Added

  Attachment #61526|0   |1
is obsolete||

--- Comment #15 from Jakub Jelinek  ---
Created attachment 61528
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61528&action=edit
gcc16-pr117785-wip.patch

Ok, updated patch with no magic whatsoever for the library side except (to be
done next) exception_ptr, std::current_exception, std::uncaught_exceptions().

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-27 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #14 from Jason Merrill  ---
(In reply to Jakub Jelinek from comment #13)
> (In reply to Hana Dusíková from comment #12)
> > I'm using [[gnu::used]] to emit constexpr symbol so it can be part of
> > compatible interface.

Sure, that would work if you use a macro to only apply that attribute in the TU
where you want it emitted.  And perhaps gnu_inline instead in other TUs.

> I think we don't have a problem with exporting the ABI compatible symbols,
> those are compiled with -std=c++98 mostly.  The question is whether we want
> to pay the price of defining comdat vtables for all the exception subclasses
> in C++26.

Again, we'd only emit them if they're needed by something else.  And they're
pretty small compared to all the comdat templates we're already emitting (when
needed).  So perhaps we don't need to do anything else if we already have the
symbols for compatibility.

> I think #pragma interface could work if the exception subclasses are defined
> in separate headers, but unsure if it can work well for std::exception
> itself when it has also
> _GLIBCXX26_CONSTEXPR exception(const exception&) = default;
> _GLIBCXX26_CONSTEXPR exception& operator=(const exception&) = default;
> _GLIBCXX26_CONSTEXPR exception(exception&&) = default;
> _GLIBCXX26_CONSTEXPR exception& operator=(exception&&) = default;
> While one can't take address of the ctor (and perhaps it could be
> [[__gnu__::__always_inline__]] too just in case), I think for the assignment
> operator one could take pointer to member and let it be emitted out of line,
> but with #pragma interface that would require definition somewhere else
> (which is not the case).

Yeah, probably best not to go back to #pragma interface, though I think it's a
bug that #pragma interface affects explicitly defaulted functions when it
doesn't affect implicitly defaulted functions.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-27 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #13 from Jakub Jelinek  ---
(In reply to Hana Dusíková from comment #12)
> I'm using [[gnu::used]] to emit constexpr symbol so it can be part of
> compatible interface.

I think we don't have a problem with exporting the ABI compatible symbols,
those are compiled with -std=c++98 mostly.  The question is whether we want to
pay the price of defining comdat vtables for all the exception subclasses in
C++26.
I think #pragma interface could work if the exception subclasses are defined in
separate headers, but unsure if it can work well for std::exception itself when
it has also
_GLIBCXX26_CONSTEXPR exception(const exception&) = default;
_GLIBCXX26_CONSTEXPR exception& operator=(const exception&) = default;
_GLIBCXX26_CONSTEXPR exception(exception&&) = default;
_GLIBCXX26_CONSTEXPR exception& operator=(exception&&) = default;
While one can't take address of the ctor (and perhaps it could be
[[__gnu__::__always_inline__]] too just in case), I think for the assignment
operator one could take pointer to member and let it be emitted out of line,
but with #pragma interface that would require definition somewhere else (which
is not the case).

OT, I've tried your branch on godbolt and I see exceptions propagating there
through noexcept function boundaries - the baz (1) case in constexpr-eh2.C in
the above patch.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-27 Thread hanicka at hanicka dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #12 from Hana Dusíková  ---
I'm using [[gnu::used]] to emit constexpr symbol so it can be part of
compatible interface.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-27 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #11 from Jason Merrill  ---
(In reply to Jakub Jelinek from comment #7)
> where making the destructor constexpr and thus effectively inline would have
> terrible effects, virtual tables of exception and similar classes now
> emitted everywhere.

Well, everywhere they're needed. That doesn't sound so terrible, lots of other
things are COMDAT and it should be backward-compatible.  But it would indeed be
a change.

To avoid it we could use the ancient #pragma interface/implementation, if they
still work, or invent a mechanism for this general issue of constexprfication
making more things inline.

I'm reminded of the C++14 dance of declaring a static const data member outside
the class to cause it to be emitted; doing the same for an inline function is
ill-formed, but we could allow it as an extension, perhaps along with
gnu_inline on the inline definition?

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-27 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #10 from Jakub Jelinek  ---
Ok, so do we want some attribute for
std::{exception,bad_exception,bad_alloc,bad_cast,
bad_typeid,bad_weak_ptr,bad_function_call} and perhaps others which will
pretend they have a key function even if they don't?
Admittedly that would be quite easy to misuse, to use it properly one would
need to make sure the attribute is not used in exactly one translation unit
(easily done on the libstdc++ side by compiling those with -std=c++23 or
earlier).
I'll try to do magic for the exception_ptr methods now.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-27 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #9 from Jason Merrill  ---
I had been thinking thinking that exception_ptr would become compiler magic,
since it's unspecified by the standard, while std::exception would not, since
it's a standard class that is regularly derived from.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-27 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #8 from Jakub Jelinek  ---
Note, adding _GLIBCXX26_CONSTEXPR above for the defaulted or inline defined
methods is ok and they wouldn't need to be treated like magic builtins (though
I guess
exception_ptr copy ctor and dtor need special thought, because they call
_M_addref and _M_release which are defined out of line and those calls would
need to be done as magic.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-27 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #7 from Jakub Jelinek  ---
(In reply to Jason Merrill from comment #6)
> (In reply to Jakub Jelinek from comment #3)
> > Jonathan, thoughts on the library side?
> > E.g. std::uncaught_exceptions is just declared in the header, but if it
> > needs to be constexpr it needs some inline definition but for ABI reasons
> > better should call the original function.  std::current_exception is also
> > defined out of line, for constant evaluation it better use some helper
> > builtin which returns void * and construct exception_ptr from that.
> 
> Interesting echoes of gnu_inline in this situation.
> 
> You mention that you already treat some of the functions as magic builtins,
> is there a reason not to do that for these as well, and leave the library
> alone?

Right now the patch handles 10 __cxa_* extern "C" functions as magic builtins.
For most of them that was not easily avoidable because we already emit those in
the IL the constexpr evaluator uses.

Today I ran into:
--- libstdc++-v3/libsupc++/exception.h.jj   2025-04-08 14:10:30.519900011
+0200
+++ libstdc++-v3/libsupc++/exception.h  2025-05-27 15:25:32.521420068 +0200
@@ -61,13 +61,17 @@ namespace std _GLIBCXX_VISIBILITY(defaul
   class exception
   {
   public:
-exception() _GLIBCXX_NOTHROW { }
+_GLIBCXX26_CONSTEXPR exception() _GLIBCXX_NOTHROW { }
+#if __cplusplus >= 202100L
+constexpr virtual ~exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW {}
+#else
 virtual ~exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW;
+#endif
 #if __cplusplus >= 201103L
-exception(const exception&) = default;
-exception& operator=(const exception&) = default;
-exception(exception&&) = default;
-exception& operator=(exception&&) = default;
+_GLIBCXX26_CONSTEXPR exception(const exception&) = default;
+_GLIBCXX26_CONSTEXPR exception& operator=(const exception&) = default;
+_GLIBCXX26_CONSTEXPR exception(exception&&) = default;
+_GLIBCXX26_CONSTEXPR exception& operator=(exception&&) = default;
 #endif

 /** Returns a C-style character string describing the general cause

where making the destructor constexpr and thus effectively inline would have
terrible effects, virtual tables of exception and similar classes now emitted
everywhere.

So sure, if you'd be ok with treating e.g. std::exception::~exception (),
std::exception::what (), similarly for std::bad_exception, std::bad_alloc,
std::bad_cast, std::bad_typeid and then also std::uncaught_exceptions(),
std::current_exception(), std::rethrow_exception() and maybe others
as magic constexpr builtins, that would probably simplify stuff.  Though a
question is what libc++ will choose to do.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-27 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #6 from Jason Merrill  ---
(In reply to Jakub Jelinek from comment #3)
> Jonathan, thoughts on the library side?
> E.g. std::uncaught_exceptions is just declared in the header, but if it
> needs to be constexpr it needs some inline definition but for ABI reasons
> better should call the original function.  std::current_exception is also
> defined out of line, for constant evaluation it better use some helper
> builtin which returns void * and construct exception_ptr from that.

Interesting echoes of gnu_inline in this situation.

You mention that you already treat some of the functions as magic builtins, is
there a reason not to do that for these as well, and leave the library alone?

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-27 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

Jakub Jelinek  changed:

   What|Removed |Added

  Attachment #61521|0   |1
is obsolete||

--- Comment #5 from Jakub Jelinek  ---
Created attachment 61526
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61526&action=edit
gcc16-pr117785-wip.patch

Further progress.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-26 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

Jakub Jelinek  changed:

   What|Removed |Added

  Attachment #61493|0   |1
is obsolete||
   Assignee|unassigned at gcc dot gnu.org  |jakub at gcc dot gnu.org
 Status|NEW |ASSIGNED

--- Comment #4 from Jakub Jelinek  ---
Created attachment 61521
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61521&action=edit
gcc16-pr117785-wip.patch

Updated patch.  This can handle both throw expr; and throw; now and fixes
various bugs.
Next step will be to make jump_target argument no longer defaulted and handle
throws everywhere, then MUST_NOT_THROW_EXPR and then deal with the library side
helpers.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-22 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

Jakub Jelinek  changed:

   What|Removed |Added

 CC||jason at gcc dot gnu.org,
   ||redi at gcc dot gnu.org

--- Comment #3 from Jakub Jelinek  ---
Jonathan, thoughts on the library side?
E.g. std::uncaught_exceptions is just declared in the header, but if it needs
to be constexpr it needs some inline definition but for ABI reasons better
should call the original function.  std::current_exception is also defined out
of line, for constant evaluation it better use some helper builtin which
returns void * and construct exception_ptr from that.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-05-22 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

--- Comment #2 from Jakub Jelinek  ---
Created attachment 61493
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61493&action=edit
gcc16-pr117785-wip.patch

Very early WIP patch.
This can right now handle a trivial exception throwing + catching, e.g.
struct S { constexpr S (); constexpr S (const S &); constexpr ~S (); };
struct T : public S { constexpr T (); constexpr T (int); constexpr T (const T
&); constexpr ~T (); };
constexpr S::S () {}
constexpr S::S (const S &) {}
constexpr S::~S () {}
constexpr T::T () {}
constexpr T::T (int) {}
constexpr T::T (const T &) {}
constexpr T::~T () {}

constexpr int
foo ()
{
  try {
throw T (1);
  }
  catch (int &a)
  {
return 1;
  }
  catch (const S &b)
  {
return 2;
  }
  catch (...)
  {
return 3;
  }
  return 4;
}

constexpr int a = foo ();
static_assert (a == 2);

As the IL constexpr evaluation sees already uses calls to
__cxa_{allocate_exception,free_exception,throw,rethrow,begin_catch,end_catch}
I've implemented it so far as if they were magic constexpr builtins.
Guess for some parts of the library implementation we'll need to add further
builtins, but many of the libsupc++ headers have methods implemented out of
line in libsupc++.a/libstdc++.so, so not sure how to deal with their constexpr
definition when we want to call the out of line implementation with ABI
compatible name unless if consteval.
On the compiler side, I guess the largest task is probably to pass jump_target
unconditionally (so drop the default argument) and deal with throws
(jump_target) in tons of places - the existing "jumps" like
switch/break/continue/return were expected to happen only in statements, not
arbitrary subexpressions (although that actually isn't the case for say ({ if
(something) return; 42; }) in arbitrary subexpressions), but e.g. for binary
expressions too chose a random example we will need if (throws (jump_target))
return NULL_TREE; or so after evaluating the arguments before evaluating the
rest.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2025-02-17 Thread hanicka at hanicka dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

Hana Dusíková  changed:

   What|Removed |Added

 CC||hanicka at hanicka dot net

--- Comment #1 from Hana Dusíková  ---
It's not part of the wording as CWG told me to take it out. But it's very
useful when an exception is not caught to call it's `.what()` and print
resulting message as part of the error. If there is no `.what()` available,
just print it structurally.

https://compiler-explorer.com/z/Gn6xYbKoY

```c++
struct division_by_zero {
constexpr const char * what() const noexcept {
return "thou shall not divide by nothing 😱";
}
};

constexpr unsigned divide(unsigned a, unsigned b) {
if (b == 0) {
throw division_by_zero{};
}
return a / b;
}

constexpr auto v = divide(3, 0);
```

Gives this error in my prototype:
```c++
:14:16: error: constexpr variable 'v' must be initialized by a constant
expression
   14 | constexpr auto v = divide(3, 0);
  |^   
:9:9: note: unhandled exception: thou shall not divide by nothing 😱
9 | throw division_by_zero{};
  | ^
```

Even further (and I'm still working on it) would be good to implement extension
which takes anything convertible to `basic_string_view` and then print it.

Note P3560R0 "Error Handling in Reflection" has std::meta::exception type with
`u8string_view what()` member.

[Bug c++/117785] [C++26] P3068R5 - constexpr exceptions

2024-11-26 Thread mpolacek at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117785

Marek Polacek  changed:

   What|Removed |Added

 Status|UNCONFIRMED |NEW
 CC||mpolacek at gcc dot gnu.org
   Last reconfirmed||2024-11-26
 Ever confirmed|0   |1