On 1/21/26 5:17 PM, Jakub Jelinek wrote:
Hi!

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.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2026-01-21  Jakub Jelinek  <[email protected]>

        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.jj   2026-01-15 16:33:46.976098487 +0100
+++ gcc/cp/decl.cc      2026-01-20 16:24:42.229486191 +0100
@@ -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)

I don't think we need to check special_memfn_p, other functions can't be defaulted (and if they could they'd probably also be immediate-escalating).

OK without that.

+    check_consteval_only_fn (decl);
if (ctype == NULL_TREE || check)
      return decl;
@@ -16498,7 +16502,7 @@ grokdeclarator (const cp_declarator *dec
                               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 *dec
                           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,
--- gcc/testsuite/g++.dg/reflect/pr123404.C.jj  2026-01-20 16:41:27.222324537 
+0100
+++ gcc/testsuite/g++.dg/reflect/pr123404.C     2026-01-20 16:40:22.613427869 
+0100
@@ -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 ();
+}

        Jakub


Reply via email to