]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Don't error on non-consteval defaulted special members in consteval-only classes...
authorJakub Jelinek <jakub@redhat.com>
Tue, 27 Jan 2026 09:23:43 +0000 (10:23 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 27 Jan 2026 09:23:43 +0000 (10:23 +0100)
As discussed earlier, the following testcase is incorrectly rejected.
While check_consteval_only_fn -> immediate_escalating_function_p
knows that defaulted special members are immediate-scalating:
  /* -- a defaulted special member function that is not declared with the
        consteval specifier  */
  special_function_kind sfk = special_memfn_p (fn);
  if (sfk != sfk_none && DECL_DEFAULTED_FN (fn))
    return true;
it returns false anyway, because the call is too early and DECL_DEFAULTED_FN
is not set yet (unlike DECL_DELETED_FN).
For DECL_DEFAULTED_FN there is quite more code, involving diagnostics for
invalid uses of = delete etc. later in grokfield:
          else if (init == ridpointers[(int)RID_DEFAULT])
            {
              if (defaultable_fn_check (value))
                {
                  DECL_DEFAULTED_FN (value) = 1;
                  DECL_INITIALIZED_IN_CLASS_P (value) = 1;
                  DECL_DECLARED_INLINE_P (value) = 1;
                  /* grokfndecl set this to error_mark_node, but we want to
                     leave it unset until synthesize_method.  */
                  DECL_INITIAL (value) = NULL_TREE;
                }
            }
but that is after the
  else if (init == ridpointers[(int)RID_DEFAULT])
    initialized = SD_DEFAULTED;
...
  value = grokdeclarator (declarator, declspecs, FIELD, initialized, &attrlist);
call in the same function where grokdeclarator calls grokfndecl.

As for defaulted special member functions there is nothing to diagnose,
those are always immediate-escalating or explicitly consteval and neither
of those is diagnosed, the following patch just passes not just whether
a fn is deleted, but whole initialized, so both whether it is deleted or
defaulted, and just doesn't call check_consteval_only_fn in that case.
During pt.cc check_consteval_only_fn call DECL_DEFAULTED_FN is already set
before we test it.

2026-01-27  Jakub Jelinek  <jakub@redhat.com>

PR c++/123404
* decl.cc (grokfndecl): Replace bool deletedp argument with
int initialized.  Test initialized == SD_DELETED instead of deletedp.
Don't call check_consteval_only_fn for defaulted special member fns.
(grokdeclarator): Pass initialized rather than
initialized == SD_DELETED to grokfndecl.

* g++.dg/reflect/pr123404.C: New test.

gcc/cp/decl.cc
gcc/testsuite/g++.dg/reflect/pr123404.C [new file with mode: 0644]

index f1ba57cd177ee24c21cc6813e04a804034d57e92..3bbc28c913d8d6eaea6a0408be2440175a637e04 100644 (file)
@@ -12103,7 +12103,7 @@ grokfndecl (tree ctype,
            int friendp,
            int publicp,
            int inlinep,
-           bool deletedp,
+           int initialized,
            bool xobj_func_p,
            special_function_kind sfk,
            bool funcdef_flag,
@@ -12330,7 +12330,7 @@ grokfndecl (tree ctype,
     = !xobj_func_p && ctype && TREE_CODE (type) == FUNCTION_TYPE;
   DECL_FUNCTION_XOBJ_FLAG (decl) = xobj_func_p;
 
-  if (deletedp)
+  if (initialized == SD_DELETED)
     DECL_DELETED_FN (decl) = 1;
 
   if (ctype && funcdef_flag)
@@ -12679,7 +12679,11 @@ grokfndecl (tree ctype,
   if (DECL_CONSTRUCTOR_P (decl) && !grok_ctor_properties (ctype, decl))
     return NULL_TREE;
 
-  check_consteval_only_fn (decl);
+  /* Don't call check_consteval_only_fn for defaulted special member
+     functions.  Those are immediate-escalating functions but at this point
+     DECL_DEFAULTED_P has not been set.  */
+  if (initialized != SD_DEFAULTED || special_memfn_p (decl) == sfk_none)
+    check_consteval_only_fn (decl);
 
   if (ctype == NULL_TREE || check)
     return decl;
@@ -16498,7 +16502,7 @@ grokdeclarator (const cp_declarator *declarator,
                               friendp ? -1 : 0, friendp, publicp,
                               inlinep | (2 * constexpr_p) | (4 * concept_p)
                                       | (8 * consteval_p),
-                              initialized == SD_DELETED,
+                              initialized,
                               is_xobj_member_function, sfk,
                               funcdef_flag, late_return_type_p,
                               template_count, in_namespace,
@@ -16836,7 +16840,7 @@ grokdeclarator (const cp_declarator *declarator,
                           publicp,
                           inlinep | (2 * constexpr_p) | (4 * concept_p)
                                   | (8 * consteval_p),
-                          initialized == SD_DELETED,
+                          initialized,
                           is_xobj_member_function, sfk,
                           funcdef_flag,
                           late_return_type_p,
diff --git a/gcc/testsuite/g++.dg/reflect/pr123404.C b/gcc/testsuite/g++.dg/reflect/pr123404.C
new file mode 100644 (file)
index 0000000..3f137b3
--- /dev/null
@@ -0,0 +1,39 @@
+// PR c++/123404
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {
+  decltype (^^::) a = ^^::;
+  consteval S () {}
+  S (const S &) = default;                     // { dg-bogus "function of consteval-only type must be declared 'consteval'" }
+  S (S &&) = default;                          // { dg-bogus "function of consteval-only type must be declared 'consteval'" }
+  S &operator= (const S &) = default;          // { dg-bogus "function of consteval-only type must be declared 'consteval'" }
+  S &operator= (S &&) = default;               // { dg-bogus "function of consteval-only type must be declared 'consteval'" }
+  consteval const char *what () { return "what"; }
+};
+
+template <typename T, T V>
+struct U
+{
+  T a = V;
+  consteval U () {}
+  U (const U &) = default;                     // { dg-bogus "function of consteval-only type must be declared 'consteval'" }
+  U (U &&) = default;                          // { dg-bogus "function of consteval-only type must be declared 'consteval'" }
+  U &operator= (const U &) = default;          // { dg-bogus "function of consteval-only type must be declared 'consteval'" }
+  U &operator= (U &&) = default;               // { dg-bogus "function of consteval-only type must be declared 'consteval'" }
+  consteval const char *what () { return "what"; }
+};
+
+consteval
+{
+  S s;
+  S t;
+  t = s;
+  S u = t;
+  u.what ();
+  U <decltype (^^::), ^^::> v;
+  U <decltype (^^::), ^^::> w;
+  w = v;
+  U <decltype (^^::), ^^::> x = w;
+  x.what ();
+}