https://gcc.gnu.org/g:5c6364b09a67de8d2237f65016ea1e3365a76e8d
commit r16-968-g5c6364b09a67de8d2237f65016ea1e3365a76e8d Author: Jason Merrill <ja...@redhat.com> Date: Thu May 29 12:21:28 2025 -0400 c++: C++17 constexpr lambda and goto/static We only want the error for these cases for functions explicitly declared constexpr, but we still want to set invalid_constexpr on C++17 lambdas so maybe_save_constexpr_fundef doesn't make them implicitly constexpr. The potential_constant_expression_1 change isn't necessary for this test, but still seems correct. gcc/cp/ChangeLog: * decl.cc (start_decl): Also set invalid_constexpr for maybe_constexpr_fn. * parser.cc (cp_parser_jump_statement): Likewise. * constexpr.cc (potential_constant_expression_1): Ignore goto to an artificial label. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/constexpr-lambda29.C: New test. Diff: --- gcc/cp/constexpr.cc | 3 +++ gcc/cp/decl.cc | 28 +++++++++++++++---------- gcc/cp/parser.cc | 7 ++++--- gcc/testsuite/g++.dg/cpp1z/constexpr-lambda29.C | 19 +++++++++++++++++ 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index fa754b9a176a..272fab328968 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -10979,6 +10979,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, *jump_target = *target; return true; } + if (DECL_ARTIFICIAL (*target)) + /* The user didn't write this goto, this isn't the problem. */ + return true; if (flags & tf_error) constexpr_error (loc, fundef_p, "%<goto%> is not a constant " "expression"); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index a9ef28bfd805..ec4b6298b11a 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -6198,22 +6198,28 @@ start_decl (const cp_declarator *declarator, } if (current_function_decl && VAR_P (decl) - && DECL_DECLARED_CONSTEXPR_P (current_function_decl) + && maybe_constexpr_fn (current_function_decl) && cxx_dialect < cxx23) { bool ok = false; if (CP_DECL_THREAD_LOCAL_P (decl) && !DECL_REALLY_EXTERN (decl)) - error_at (DECL_SOURCE_LOCATION (decl), - "%qD defined %<thread_local%> in %qs function only " - "available with %<-std=c++23%> or %<-std=gnu++23%>", decl, - DECL_IMMEDIATE_FUNCTION_P (current_function_decl) - ? "consteval" : "constexpr"); + { + if (DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + error_at (DECL_SOURCE_LOCATION (decl), + "%qD defined %<thread_local%> in %qs function only " + "available with %<-std=c++23%> or %<-std=gnu++23%>", decl, + DECL_IMMEDIATE_FUNCTION_P (current_function_decl) + ? "consteval" : "constexpr"); + } else if (TREE_STATIC (decl)) - error_at (DECL_SOURCE_LOCATION (decl), - "%qD defined %<static%> in %qs function only available " - "with %<-std=c++23%> or %<-std=gnu++23%>", decl, - DECL_IMMEDIATE_FUNCTION_P (current_function_decl) - ? "consteval" : "constexpr"); + { + if (DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + error_at (DECL_SOURCE_LOCATION (decl), + "%qD defined %<static%> in %qs function only available " + "with %<-std=c++23%> or %<-std=gnu++23%>", decl, + DECL_IMMEDIATE_FUNCTION_P (current_function_decl) + ? "consteval" : "constexpr"); + } else ok = true; if (!ok) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 3e39bf33fab0..091873cbe3a9 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -15431,11 +15431,12 @@ cp_parser_jump_statement (cp_parser* parser, tree &std_attrs) case RID_GOTO: if (parser->in_function_body - && DECL_DECLARED_CONSTEXPR_P (current_function_decl) + && maybe_constexpr_fn (current_function_decl) && cxx_dialect < cxx23) { - error ("%<goto%> in %<constexpr%> function only available with " - "%<-std=c++23%> or %<-std=gnu++23%>"); + if (DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + error ("%<goto%> in %<constexpr%> function only available with " + "%<-std=c++23%> or %<-std=gnu++23%>"); cp_function_chain->invalid_constexpr = true; } diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda29.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda29.C new file mode 100644 index 000000000000..9e661b6a55d4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda29.C @@ -0,0 +1,19 @@ +// Test that we don't make lambdas with goto/static implicitly constexpr +// when an explicitly constexpr function would be ill-formed. + +// { dg-do compile { target c++17 } } + +int main() +{ + constexpr int a = [] { + return 42; + goto label; + label: + return 142; + }(); // { dg-error "" "" { target c++20_down } } + + constexpr int b = [] { + return 42; + static int i; + }(); // { dg-error "" "" { target c++20_down } } +}