From 688fdde2f18e3318ef7e9889fdb9b239b905dfc7 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 9 May 2023 18:48:11 -0400 Subject: [PATCH] c++: always check consteval address The restriction on the "permitted result of a constant expression" to not refer to an immediate function applies regardless of context. The previous code tried to only check in cases where we wouldn't get the check in cp_fold_r, but with the next patch I would need to add another case and it shouldn't be a problem to always check. We also shouldn't talk about immediate evaluation when we aren't dealing with one. gcc/cp/ChangeLog: * constexpr.cc (cxx_eval_outermost_constant_expr): Always check for address of immediate fn. (maybe_constant_init_1): Evaluate PTRMEM_CST. gcc/testsuite/ChangeLog: * g++.dg/DRs/dr2478.C: Handle -fimplicit-constexpr. * g++.dg/cpp23/consteval-if12.C: Adjust diagnostics. * g++.dg/cpp2a/consteval20.C: Likewise. * g++.dg/cpp2a/consteval24.C: Likewise. * g++.dg/cpp2a/srcloc20.C: Likewise. --- gcc/cp/constexpr.cc | 22 ++++++++++++++------- gcc/testsuite/g++.dg/DRs/dr2478.C | 17 +++++++++------- gcc/testsuite/g++.dg/cpp23/consteval-if12.C | 8 ++++---- gcc/testsuite/g++.dg/cpp2a/consteval20.C | 4 ++-- gcc/testsuite/g++.dg/cpp2a/consteval24.C | 8 ++++---- gcc/testsuite/g++.dg/cpp2a/srcloc20.C | 4 ++-- 6 files changed, 37 insertions(+), 26 deletions(-) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 987a536d515..7b8090625e8 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -8353,7 +8353,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, non_constant_p = true; } - if (!global_ctx.heap_vars.is_empty ()) + if (!non_constant_p && cxx_dialect >= cxx20 + && !global_ctx.heap_vars.is_empty ()) { tree heap_var = cp_walk_tree_without_duplicates (&r, find_heap_var_refs, NULL); @@ -8384,15 +8385,22 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, /* Check that immediate invocation does not return an expression referencing any immediate function decls. */ - if (is_consteval || in_immediate_context ()) + if (!non_constant_p && cxx_dialect >= cxx20) if (tree immediate_fndecl = cp_walk_tree_without_duplicates (&r, find_immediate_fndecl, NULL)) { if (!allow_non_constant && !non_constant_p) - error_at (cp_expr_loc_or_input_loc (t), - "immediate evaluation returns address of immediate " - "function %qD", immediate_fndecl); + { + if (is_consteval) + error_at (cp_expr_loc_or_input_loc (t), + "immediate evaluation returns address of immediate " + "function %qD", immediate_fndecl); + else + error_at (cp_expr_loc_or_input_loc (t), + "constant evaluation returns address of immediate " + "function %qD", immediate_fndecl); + } r = t; non_constant_p = true; } @@ -8795,8 +8803,8 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, t = TARGET_EXPR_INITIAL (t); if (!is_nondependent_static_init_expression (t)) /* Don't try to evaluate it. */; - else if (CONSTANT_CLASS_P (t) && allow_non_constant) - /* No evaluation needed. */; + else if (CONSTANT_CLASS_P (t) && TREE_CODE (t) != PTRMEM_CST) + /* No evaluation needed. PTRMEM_CST needs the immediate fn check. */; else { /* [basic.start.static] allows constant-initialization of variables with diff --git a/gcc/testsuite/g++.dg/DRs/dr2478.C b/gcc/testsuite/g++.dg/DRs/dr2478.C index 7e939ac6850..7f581cabb7b 100644 --- a/gcc/testsuite/g++.dg/DRs/dr2478.C +++ b/gcc/testsuite/g++.dg/DRs/dr2478.C @@ -1,11 +1,14 @@ // DR 2478 - Properties of explicit specializations of implicitly-instantiated class templates // { dg-do compile { target c++20 } } +// Defeat -fimplicit-constexpr +int ii; + template struct S { - int foo () { return 0; } + int foo () { return ii; } constexpr int bar () { return 0; } - int baz () { return 0; } + int baz () { return ii; } consteval int qux () { return 0; } constexpr S () {} static constinit T x; @@ -14,7 +17,7 @@ struct S { template T S::x = S ().foo (); // { dg-error "'constinit' variable 'S::x' does not have a constant initializer" } - // { dg-error "call to non-'constexpr' function" "" { target *-*-* } .-1 } + // { dg-error "call to non-'constexpr' function|called in a constant expression" "" { target *-*-* } .-1 } template T S::y = S ().foo (); @@ -49,14 +52,14 @@ S::qux () template <> long S::x = S ().foo (); // { dg-bogus "'constinit' variable 'S::x' does not have a constant initializer" "" { xfail *-*-* } } - // { dg-bogus "call to non-'constexpr' function" "" { xfail *-*-* } .-1 } + // { dg-bogus "call to non-'constexpr' function|called in a constant expression" "" { xfail *-*-* } .-1 } template <> constinit long S::y = S ().foo (); // { dg-error "'constinit' variable 'S::y' does not have a constant initializer" } - // { dg-error "call to non-'constexpr' function" "" { target *-*-* } .-1 } + // { dg-error "call to non-'constexpr' function|called in a constant expression" "" { target *-*-* } .-1 } constinit auto a = S ().foo (); // { dg-error "'constinit' variable 'a' does not have a constant initializer" } - // { dg-error "call to non-'constexpr' function" "" { target *-*-* } .-1 } + // { dg-error "call to non-'constexpr' function|called in a constant expression" "" { target *-*-* } .-1 } constinit auto b = S ().bar (); constinit auto c = S ().foo (); constinit auto d = S ().bar (); // { dg-error "'constinit' variable 'd' does not have a constant initializer" } @@ -65,7 +68,7 @@ constinit auto e = S ().baz (); constinit auto f = S ().qux (); // { dg-error "'constinit' variable 'f' does not have a constant initializer" } // { dg-error "call to non-'constexpr' function" "" { target *-*-* } .-1 } constinit auto g = S ().baz (); // { dg-error "'constinit' variable 'g' does not have a constant initializer" } - // { dg-error "call to non-'constexpr' function" "" { target *-*-* } .-1 } + // { dg-error "call to non-'constexpr' function|called in a constant expression" "" { target *-*-* } .-1 } constinit auto h = S ().qux (); auto i = S::x; auto j = S::x; diff --git a/gcc/testsuite/g++.dg/cpp23/consteval-if12.C b/gcc/testsuite/g++.dg/cpp23/consteval-if12.C index 7a47680e5d8..03de87c3e09 100644 --- a/gcc/testsuite/g++.dg/cpp23/consteval-if12.C +++ b/gcc/testsuite/g++.dg/cpp23/consteval-if12.C @@ -19,10 +19,10 @@ bar () { S s; if consteval { // { dg-warning "'if consteval' only available with" "" { target c++20_only } } - constexpr auto fn1 = foo; // { dg-error "immediate evaluation returns address of immediate function" } - constexpr auto fn2 = &foo; // { dg-error "immediate evaluation returns address of immediate function" } - constexpr auto fn3 = &S::foo; // { dg-error "immediate evaluation returns address of immediate function" } - constexpr auto fn4 = &S::bar; // { dg-error "immediate evaluation returns address of immediate function" } + constexpr auto fn1 = foo; // { dg-error "constant evaluation returns address of immediate function" } + constexpr auto fn2 = &foo; // { dg-error "constant evaluation returns address of immediate function" } + constexpr auto fn3 = &S::foo; // { dg-error "constant evaluation returns address of immediate function" } + constexpr auto fn4 = &S::bar; // { dg-error "constant evaluation returns address of immediate function" } constexpr auto fn5 = baz (); // { dg-error "immediate evaluation returns address of immediate function" } constexpr auto fn6 = qux (); // { dg-error "immediate evaluation returns address of immediate function" } constexpr auto fn7 = corge (); // { dg-error "immediate evaluation returns address of immediate function" } diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval20.C b/gcc/testsuite/g++.dg/cpp2a/consteval20.C index bd44712c535..ba3613318e6 100644 --- a/gcc/testsuite/g++.dg/cpp2a/consteval20.C +++ b/gcc/testsuite/g++.dg/cpp2a/consteval20.C @@ -11,12 +11,12 @@ int bar () { auto c = &S::foo; // { dg-error "taking address of an immediate function" } - constexpr auto d = &S::foo; // { dg-error "taking address of an immediate function" } + constexpr auto d = &S::foo; // { dg-error "constant evaluation returns address of immediate function" } static auto e = &S::foo; // { dg-error "taking address of an immediate function" } return (s.*&S::foo) (); // { dg-error "taking address of an immediate function" } } -constexpr auto a = &S::foo; // { dg-error "taking address of an immediate function" } +constexpr auto a = &S::foo; // { dg-error "constant evaluation returns address of immediate function" } auto b = &S::foo; // { dg-error "taking address of an immediate function" } consteval int diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval24.C b/gcc/testsuite/g++.dg/cpp2a/consteval24.C index 6d7034c5515..22a9657e4a1 100644 --- a/gcc/testsuite/g++.dg/cpp2a/consteval24.C +++ b/gcc/testsuite/g++.dg/cpp2a/consteval24.C @@ -17,10 +17,10 @@ consteval int bar () { S s; - constexpr auto fn1 = foo; // { dg-error "immediate evaluation returns address of immediate function" } - constexpr auto fn2 = &foo; // { dg-error "immediate evaluation returns address of immediate function" } - constexpr auto fn3 = &S::foo; // { dg-error "immediate evaluation returns address of immediate function" } - constexpr auto fn4 = &S::bar; // { dg-error "immediate evaluation returns address of immediate function" } + constexpr auto fn1 = foo; // { dg-error "constant evaluation returns address of immediate function" } + constexpr auto fn2 = &foo; // { dg-error "constant evaluation returns address of immediate function" } + constexpr auto fn3 = &S::foo; // { dg-error "constant evaluation returns address of immediate function" } + constexpr auto fn4 = &S::bar; // { dg-error "constant evaluation returns address of immediate function" } constexpr auto fn5 = baz (); // { dg-error "immediate evaluation returns address of immediate function" } constexpr auto fn6 = qux (); // { dg-error "immediate evaluation returns address of immediate function" } constexpr auto fn7 = corge (); // { dg-error "immediate evaluation returns address of immediate function" } diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc20.C b/gcc/testsuite/g++.dg/cpp2a/srcloc20.C index acdf5a6505f..e99f1dcf7c4 100644 --- a/gcc/testsuite/g++.dg/cpp2a/srcloc20.C +++ b/gcc/testsuite/g++.dg/cpp2a/srcloc20.C @@ -33,12 +33,12 @@ namespace std { using namespace std; auto a = source_location::current; // { dg-error "taking address of an immediate function" } -constexpr auto b = &source_location::current; // { dg-error "taking address of an immediate function" } +constexpr auto b = &source_location::current; // { dg-error "constant evaluation returns address of immediate function" } void foo () { auto c = &source_location::current; // { dg-error "taking address of an immediate function" } - constexpr auto d = source_location::current; // { dg-error "taking address of an immediate function" } + constexpr auto d = source_location::current; // { dg-error "constant evaluation returns address of immediate function" } static auto e = source_location::current; // { dg-error "taking address of an immediate function" } }