]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: always check consteval address
authorJason Merrill <jason@redhat.com>
Tue, 9 May 2023 22:48:11 +0000 (18:48 -0400)
committerJason Merrill <jason@redhat.com>
Wed, 10 May 2023 15:09:56 +0000 (11:09 -0400)
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
gcc/testsuite/g++.dg/DRs/dr2478.C
gcc/testsuite/g++.dg/cpp23/consteval-if12.C
gcc/testsuite/g++.dg/cpp2a/consteval20.C
gcc/testsuite/g++.dg/cpp2a/consteval24.C
gcc/testsuite/g++.dg/cpp2a/srcloc20.C

index 987a536d515cee2425d547c7bd2d627676f14757..7b8090625e83a31d1c9e2fc55dae5fc6c21d246a 100644 (file)
@@ -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
index 7e939ac685018cef45b1bdb0e826da007956e604..7f581cabb7b0d764f7b9b3f9dc1ec855ac1ffcac 100644 (file)
@@ -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 <typename T>
 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 <typename T>
 T S<T>::x = S<T> ().foo ();    // { dg-error "'constinit' variable 'S<char>::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 <typename T>
 T S<T>::y = S<T> ().foo ();
@@ -49,14 +52,14 @@ S<char>::qux ()
 
 template <>
 long S<long>::x = S<long> ().foo ();   // { dg-bogus "'constinit' variable 'S<long int>::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<long>::y = S<long> ().foo (); // { dg-error "'constinit' variable 'S<long int>::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<char> ().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<char> ().bar ();
 constinit auto c = S<int> ().foo ();
 constinit auto d = S<int> ().bar ();   // { dg-error "'constinit' variable 'd' does not have a constant initializer" }
@@ -65,7 +68,7 @@ constinit auto e = S<char> ().baz ();
 constinit auto f = S<char> ().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<int> ().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<int> ().qux ();
 auto i = S<char>::x;
 auto j = S<int>::x;
index 7a47680e5d8bfb56ca516ac2340af17cf32ff6b9..03de87c3e09182a2127fbc80173fc9292225f282 100644 (file)
@@ -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" }
index bd44712c53516ac48f0f850b2b3715b764d86a2b..ba3613318e63a4cca47a1d9d6d8f8e17c4a50df3 100644 (file)
@@ -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
index 6d7034c5515e322c5a4ac102cace4da80434d3cd..22a9657e4a1623dbfdfd242255773c6eb44d613e 100644 (file)
@@ -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" }
index acdf5a6505fa56a7fb71b4380e0e5ffb594efeca..e99f1dcf7c45ea2f09aee5e34f34fdc630949d5b 100644 (file)
@@ -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" }
 }