On 5/5/26 5:24 PM, Patrick Palka wrote:
On Tue, 5 May 2026, Jason Merrill wrote:
On 5/5/26 4:34 PM, Patrick Palka wrote:
On Tue, 5 May 2026, Jason Merrill wrote:
On 5/5/26 3:53 PM, Patrick Palka wrote:
On Tue, 5 May 2026, Jason Merrill wrote:
On 5/5/26 1:20 PM, Patrick Palka wrote:
+/* Recursive workhorse of consteval_only_p. Returns true if T is
definitely
+ consteval-only, false if it's definitely not, and unknown if we
saw
an
+ incomplete type and therefore don't know. */
+
+tristate
+consteval_only_p_walker::walk (tree t)
+{
+ t = TYPE_MAIN_VARIANT (t);
+
+ if (REFLECTION_TYPE_P (t))
+ return true;
+ else if (INDIRECT_TYPE_P (t))
+ return walk (TREE_TYPE (t));
+ else if (TREE_CODE (t) == ARRAY_TYPE)
+ return walk (TREE_TYPE (t));
+ else if (FUNC_OR_METHOD_TYPE_P (t))
+ {
+ tristate r = walk (TREE_TYPE (t));
+ for (tree parm = TYPE_ARG_TYPES (t);
+ parm != NULL_TREE && parm != void_list_node;
+ parm = TREE_CHAIN (parm))
+ {
+ if (r.is_true ())
+ break;
+ r = r || walk (TREE_VALUE (parm));
+ }
+ return r;
+ }
+ else if (RECORD_OR_UNION_TYPE_P (t))
+ {
+ if (tree *slot = hash_map_safe_get
(consteval_only_class_cache,
t))
+ return *slot == boolean_true_node;
+
+ if (class_seen.add (t))
+ {
+ /* Optimistically assume this already seen consteval-unknown
class
is
+ not consteval only, for sake of mutually recursive
classes. */
+ optimistic_p = true;
+ return false;
+ }
+ class_stack.safe_push (t);
+
+ tristate r = COMPLETE_TYPE_P (t) ? false : tristate::unknown
();
+ for (tree member = TYPE_FIELDS (t); member; member =
DECL_CHAIN
(member))
+ if (TREE_CODE (member) == FIELD_DECL)
+ {
+ r = r || walk (TREE_TYPE (member));
+ if (r.is_true ())
+ break;
+ }
+
+ if (!COMPLETE_TYPE_P (t))
+ /* Until the type is laid out, we can't trust that its
TYPE_FIELDS
+ won't change. */;
We might move the COMPLETE_TYPE check...
+ else if (r.is_true ())
+ hash_map_safe_put<hm_ggc> (consteval_only_class_cache,
+ t, boolean_true_node);
+ else if (r.is_false ()
...into another exception for the is_false case, since I don't think
the
TYPE_FIELDS can change in a way that would invalidate is_true().
Sadly, it can! prune_lambda_captures can remove consteval-only
TYPE_FIELDS (corresponding to folded-away captures) before the closure
type has been laid out, so if we'd cache the result now we'd get the
wrong answer after pruning.
Without this second COMPLETE_TYPE_P check we'd get a bogus error in
reflect/reflect_constant_array6.C due to treating the lambda as
consteval even after pruning.
Ah, lambdas, always keeping us on our toes. But then we could skip
walking
the fields at all if we're going to return unknown no matter what we see.
In that lambda case, where TYPE_FIELDS is set but TYPE_COMPLETE_P is
false, we won't always return unknown, we could return true if one of
its TYPE_FIELDS is consteval-only.
Hmm, we currently return true but don't cache it? So we could be returning
consteval-only about a type that later turns out not to be. That doesn't seem
better to me than just returning unknown.
Always returning unknown for !COMPLETE_TYPE_P class types seems to break <meta>:
/scratchpad/gcc-master-build/x86_64-pc-linux-gnu/libstdc++-v3/include/meta:117:7:
error: ‘consteval’ function ‘virtual consteval const char*
std::meta::exception::what() const’ overriding non-‘consteval’ function
117 | what() const noexcept override
| ^~~~
In file included from
/home/patrick/code/gcc-master/libstdc++-v3/libsupc++/new:43,
from
/scratchpad/gcc-master-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/stl_construct.h:59,
from
/scratchpad/gcc-master-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/char_traits.h:59,
from
/scratchpad/gcc-master-build/x86_64-pc-linux-gnu/libstdc++-v3/include/string:45,
from gcc/testsuite/g++.dg/reflect/reflect_constant_array6.C:5:
/scratchpad/gcc-master-build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/exception.h:83:5:
note: overridden function is ‘virtual constexpr const char*
std::exception::what() const’
83 | what() const _GLIBCXX_TXN_SAFE_DYN noexcept { return
"std::exception"; }
| ^~~~
Reduced:
struct exception {
virtual void foo();
};
struct meta_exception : exception {
decltype(^^int) *p;
consteval virtual void foo() { }
};
because check_for_override is called before the class is fully laid out
and COMPLETE_TYPE_P is not yet set, but we still need consteval_only_p
to return true at this point. That doesn't seem ideal :/
How about always returning unknown for closures, but returning/caching
true for other classes?
Jason