Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

I'm not sure if this is really the best approach in the end but should
fix the errors at least.

-- >8 --

The failure in the given PR occurs because when setting up an
imported vague-linkage variable, we currently call 'maybe_commonize_var'
which for -freflection checks 'consteval_only_p'.  Unfortunately this
latter function needs to call 'complete_type_p' which can perform
recursive loading of the (possibly yet-to-be-streamed) class type,
breaking modules assumptions.

It doesn't seem particularly easy to guarantee that the class type for a
variable will always have its definition be fully streamed before the
variable definition is, so as a workaround this patch introduces two new
flags on lang_type that can be used to skip the 'complete_type_p' call
and subsequent tree walk on the type definition if it has previously
been done.

This solves the issue because such a vague linkage variable in an
imported module will necessarily have had 'consteval_only_p' called on
it (for the same reason I haven't been able to remove it here), and so
we stream the cached result and can skip the recursive load opportunity.

One catch is that we also need to clear any existing cached results in
finish_struct, as it appears to be valid to call 'consteval_only_p' on
an incomplete type, and so caching this call would lead to incorrect
results after the type is completed.

        PR c++/122785

gcc/cp/ChangeLog:

        * class.cc (finish_struct): Clear cached consteval_only_p flag.
        * cp-tree.h (struct lang_type): New flags consteval_only and
        consteval_only_set.
        (CLASSTYPE_CONSTEVAL_ONLY_P): New accessor.
        (CLASSTYPE_CONSTEVAL_ONLY_P_SET): New accessor.
        * module.cc (trees_out::lang_type_bools): Stream the new flags.
        (trees_in::lang_type_bools): Likewise.
        (module_state_config::get_dialect): Note -freflection.
        * reflect.cc (consteval_only_p): Cache the result of this call,
        skip complete_type_p and the tree walk if a cached result is
        already available.

gcc/testsuite/ChangeLog:

        * g++.dg/modules/reflect-1_a.H: New test.
        * g++.dg/modules/reflect-1_b.C: New test.

Signed-off-by: Nathaniel Shead <[email protected]>
---
 gcc/cp/class.cc                            |  3 +++
 gcc/cp/cp-tree.h                           | 13 ++++++++++++-
 gcc/cp/module.cc                           |  5 +++++
 gcc/cp/reflect.cc                          | 16 +++++++++++++++-
 gcc/testsuite/g++.dg/modules/reflect-1_a.H | 11 +++++++++++
 gcc/testsuite/g++.dg/modules/reflect-1_b.C |  6 ++++++
 6 files changed, 52 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/reflect-1_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/reflect-1_b.C

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index faf42c7979d..409e18d8310 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -8330,6 +8330,9 @@ finish_struct (tree t, tree attributes)
 
   TYPE_BEING_DEFINED (t) = 0;
 
+  /* Clear our cached understanding of if this type was consteval-only.  */
+  CLASSTYPE_CONSTEVAL_ONLY_P_SET (t) = 0;
+
   if (current_class_type)
     popclass ();
   else
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index d7acfc8b7a3..88aceb8cf40 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2633,6 +2633,8 @@ struct GTY(()) lang_type {
   unsigned has_constexpr_ctor : 1;
   unsigned unique_obj_representations : 1;
   unsigned unique_obj_representations_set : 1;
+  unsigned consteval_only : 1;
+  unsigned consteval_only_set : 1;
   bool erroneous : 1;
   bool non_pod_aggregate : 1;
   bool non_aggregate_pod : 1;
@@ -2646,7 +2648,7 @@ struct GTY(()) lang_type {
   /* There are some bits left to fill out a 32-bit word.  Keep track
      of this by updating the size of this bitfield whenever you add or
      remove a flag.  */
-  unsigned dummy : 2;
+  /* unsigned dummy : 0;  */
 
   tree primary_base;
   vec<tree_pair_s, va_gc> *vcall_indices;
@@ -2891,6 +2893,15 @@ struct GTY(()) lang_type {
 #define CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET(NODE) \
   (LANG_TYPE_CLASS_CHECK (NODE)->unique_obj_representations_set)
 
+/* Nonzero means that this class type is consteval-only.  */
+#define CLASSTYPE_CONSTEVAL_ONLY_P(NODE) \
+  (LANG_TYPE_CLASS_CHECK (NODE)->consteval_only)
+
+/* Nonzero means that this class type has
+   CLASSTYPE_CONSTEVAL_ONLY_P computed.  */
+#define CLASSTYPE_CONSTEVAL_ONLY_P_SET(NODE) \
+  (LANG_TYPE_CLASS_CHECK (NODE)->consteval_only_set)
+
 /* Nonzero means that this class contains pod types whose default
    initialization is not a zero initialization (namely, pointers to
    data members).  */
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index c786519c1c0..8eb83b121fd 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -6314,6 +6314,8 @@ trees_out::lang_type_bools (tree t, bits_out& bits)
   WB (lang->has_constexpr_ctor);
   WB (lang->unique_obj_representations);
   WB (lang->unique_obj_representations_set);
+  WB (lang->consteval_only);
+  WB (lang->consteval_only_set);
   gcc_checking_assert (!lang->erroneous);
   WB (lang->non_pod_aggregate);
   WB (lang->non_aggregate_pod);
@@ -6387,6 +6389,8 @@ trees_in::lang_type_bools (tree t, bits_in& bits)
   RB (lang->has_constexpr_ctor);
   RB (lang->unique_obj_representations);
   RB (lang->unique_obj_representations_set);
+  RB (lang->consteval_only);
+  RB (lang->consteval_only_set);
   gcc_checking_assert (!lang->erroneous);
   RB (lang->non_pod_aggregate);
   RB (lang->non_aggregate_pod);
@@ -17136,6 +17140,7 @@ module_state_config::get_dialect ()
                      (cxx_dialect < cxx20 && flag_coroutines
                       ? "/coroutines" : ""),
                      flag_module_implicit_inline ? "/implicit-inline" : "",
+                     flag_reflection ? "/reflection" : "",
                      flag_contracts ? "/contracts" : "",
                      NULL);
 
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 8f85a6bab5d..a31675f9f68 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -8071,6 +8071,13 @@ consteval_only_p (tree t)
   if (!t)
     return false;
 
+  if (REFLECTION_TYPE_P (t))
+    return true;
+
+  /* If we've got a cached result, we have nothing further to do.  */
+  if (CLASS_TYPE_P (t) && CLASSTYPE_CONSTEVAL_ONLY_P_SET (t))
+    return CLASSTYPE_CONSTEVAL_ONLY_P (t);
+
   /* We need the complete type otherwise we'd have no fields for class
      templates and thus come up with zilch for things like
        template<typename T>
@@ -8080,7 +8087,14 @@ consteval_only_p (tree t)
 
   /* Classes with std::meta::info members are also consteval-only.  */
   hash_set<tree> visited;
-  return !!cp_walk_tree (&t, consteval_only_type_r, &visited, &visited);
+  bool result = cp_walk_tree (&t, consteval_only_type_r, &visited, &visited);
+
+  if (CLASS_TYPE_P (t))
+    {
+      CLASSTYPE_CONSTEVAL_ONLY_P_SET (t) = true;
+      CLASSTYPE_CONSTEVAL_ONLY_P (t) = result;
+    }
+  return result;
 }
 
 /* Detect if a consteval-only expression EXPR or a consteval-only
diff --git a/gcc/testsuite/g++.dg/modules/reflect-1_a.H 
b/gcc/testsuite/g++.dg/modules/reflect-1_a.H
new file mode 100644
index 00000000000..025f2e27ea1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/reflect-1_a.H
@@ -0,0 +1,11 @@
+// PR c++/122785
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-fmodule-header -freflection" }
+// { dg-module-cmi {} }
+
+struct S {
+  friend S foo();
+  S bar(int);
+};
+inline S s;
+template <typename T> decltype(s.bar(T{})) foo(T);
diff --git a/gcc/testsuite/g++.dg/modules/reflect-1_b.C 
b/gcc/testsuite/g++.dg/modules/reflect-1_b.C
new file mode 100644
index 00000000000..a3c5b67d09a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/reflect-1_b.C
@@ -0,0 +1,6 @@
+// PR c++/122785
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-fmodules -freflection" }
+
+import "reflect-1_a.H";
+using ::S;
-- 
2.51.0

Reply via email to