[gcc r16-7060] c++: Don't error on non-consteval defaulted special members in consteval-only classes [PR123404]
Jakub Jelinek
jakub@gcc.gnu.org
Tue Jan 27 09:26:53 GMT 2026
https://gcc.gnu.org/g:de19477814821362e0a2b3c10fc1d7cf62be60cc
commit r16-7060-gde19477814821362e0a2b3c10fc1d7cf62be60cc
Author: Jakub Jelinek <jakub@redhat.com>
Date: Tue Jan 27 10:23:43 2026 +0100
c++: Don't error on non-consteval defaulted special members in consteval-only classes [PR123404]
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.
Diff:
---
gcc/cp/decl.cc | 14 +++++++-----
gcc/testsuite/g++.dg/reflect/pr123404.C | 39 +++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index f1ba57cd177e..3bbc28c913d8 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -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
index 000000000000..3f137b342217
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/pr123404.C
@@ -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 ();
+}
More information about the Gcc-cvs
mailing list