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

Reply via email to