On Mon, May 04, 2026 at 09:25:06PM -0400, Patrick Palka wrote:
> + 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_set.add (t))
> + /* Handle struct A { A* p; } etc. */
> + return false;
> +
> + 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 || consteval_only_p_1 (TREE_TYPE (member), class_set);
> + if (r.is_true ())
> + break;
> + }
> +
> + if (COMPLETE_TYPE_P (t))
> + {
> + if (r.is_true ())
> + hash_map_safe_put<hm_ggc> (consteval_only_class_cache,
> + t, boolean_true_node);
> + else if (r.is_false ())
> + hash_map_safe_put<hm_ggc> (consteval_only_class_cache,
> + t, boolean_false_node);
> + }
> +
> + class_set.remove (t);
Doesn't the above stmt result in really bad compile time complexity?
If I have say
struct S1;
struct S2;
struct S3 { S2 *a; };
struct S4 { S3 *a; };
struct S5 { S4 *a; };
...
struct S9999 { S9998 *a; };
struct S2 { S9999 *a; S1 *b; };
then when asking if S2 is consteval-only, this will walk ~10000^2 types
rather than just ~10000 types. Wouldn't it be better to
class_set.add (t) and never remove, but if we trigger that return false;
in there, remember that we shouldn't cache r.is_false () results (perhaps
with the exception when this was the non-recursive call)?
Jakub