https://gcc.gnu.org/g:d91e9e992cf8edf7dfcbe5a2d1f4cb05a66d7640

commit r17-5510-gd91e9e992cf8edf7dfcbe5a2d1f4cb05a66d7640
Author: Marek Polacek <[email protected]>
Date:   Tue Oct 13 14:54:57 2026 -0400

    c++/reflection: use OPAQUE_TYPE for std::meta::info
    
    Currently, we use the LANG_TYPE node to represent the C++ Reflection
    type std::meta::info.  Unfortunately that doesn't work too well with
    streaming for LTO, see 126017.  Another problem was that the
    std::meta::info LANG_TYPE wasn't marked
    TYPE_CONTAINS_PLACEHOLDER_INTERNAL (127856).  Jakub suggested changing
    LANG_TYPE to OPAQUE_TYPE.  OPAQUE_TYPE was introduced in GCC 11 for
    PowerPC MMA __vector_pair/__vector_quad types.  Its description reads as
    pretty much what we want for std::meta::info.  One difference between
    the PowerPC MMA types and std::meta::info is that the latter has a
    scalar integer mode instead of MODE_OPAQUE, so it's possible to
    distinguish between them.
    
    I've checked rs6000_mangle_type and I don't think it needs any changes.
    
    Using OPAQUE_TYPE fixes both the LTO crashes and 127856.
    
            PR c++/126017
            PR c++/127856
    
    gcc/cp/ChangeLog:
    
            * cxx-pretty-print.cc (cxx_pretty_printer::simple_type_specifier)
            <case LANG_TYPE>: Rename to OPAQUE_TYPE.
            (cxx_pretty_printer::type_id) <case LANG_TYPE>: Likewise.
            * mangle.cc (write_type) <case LANG_TYPE>: Likewise.
            * module.cc (trees_out::type_node) <case LANG_TYPE>: Likewise.
            (trees_in::tree_node) <case LANG_TYPE>: Likewise.
            * name-lookup.cc (name_lookup::adl_type) <case LANG_TYPE>:
            Don't check REFLECTION_TYPE_P here.
            <case OPAQUE_TYPE>: New.
            * reflect.cc (init_reflection): Create an OPAQUE_TYPE node instead
            of a LANG_TYPE node.
            * tree.cc (type_has_unique_obj_representations) <case LANG_TYPE>:
            Rename to OPAQUE_TYPE.
    
    gcc/ChangeLog:
    
            * doc/generic.texi: Update OPAQUE_TYPE description.
            * dwarf2out.cc (gen_type_die_with_usage) <case OPAQUE_TYPE>: If
            SCALAR_INT_MODE_P, goto unspecified_type.
            * tree.cc (wide_int_to_tree_1) <case LANG_TYPE>: Rename to
            OPAQUE_TYPE.  Assert SCALAR_INT_MODE_P.
            (cache_integer_cst) <case LANG_TYPE>: Likewise.
            (verify_opaque_type): Allow SCALAR_INT_MODE_P mode.
            * tree.def (OPAQUE_TYPE): Update description.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/reflect/diag6.C: Adjust expected diagnostic.
            * g++.dg/reflect/init2.C: Likewise.
            * g++.dg/lto/pr126017_0.C: New test.
            * g++.dg/lto/pr126017_1.C: New test.
            * g++.dg/reflect/pr127856.C: New test.
            * g++.target/powerpc/reflection1.C: New test.
    
    Co-authored-by: Jakub Jelinek <[email protected]>
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 gcc/cp/cxx-pretty-print.cc                     |  4 ++--
 gcc/cp/mangle.cc                               |  2 +-
 gcc/cp/module.cc                               | 10 ++++++----
 gcc/cp/name-lookup.cc                          | 14 +++++++-------
 gcc/cp/reflect.cc                              |  2 +-
 gcc/cp/tree.cc                                 |  2 +-
 gcc/doc/generic.texi                           |  8 +++++---
 gcc/dwarf2out.cc                               |  6 +++++-
 gcc/testsuite/g++.dg/lto/pr126017_0.C          | 14 ++++++++++++++
 gcc/testsuite/g++.dg/lto/pr126017_1.C          | 22 ++++++++++++++++++++++
 gcc/testsuite/g++.dg/reflect/diag6.C           |  4 ++--
 gcc/testsuite/g++.dg/reflect/init2.C           |  2 +-
 gcc/testsuite/g++.dg/reflect/pr127856.C        | 11 +++++++++++
 gcc/testsuite/g++.target/powerpc/reflection1.C | 19 +++++++++++++++++++
 gcc/tree.cc                                    | 13 ++++++++++---
 gcc/tree.def                                   |  3 ++-
 16 files changed, 109 insertions(+), 27 deletions(-)

diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index f844039eb994..acf0e2b2da12 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -1442,7 +1442,7 @@ cxx_pretty_printer::simple_type_specifier (tree t)
       pp_cxx_trait (this, t);
       break;
 
-    case LANG_TYPE:
+    case OPAQUE_TYPE:
       if (REFLECTION_TYPE_P (t))
        {
          pp_cxx_ws_string (this, "std::meta::info");
@@ -1978,7 +1978,7 @@ cxx_pretty_printer::type_id (tree t)
       }
       break;
 
-    case LANG_TYPE:
+    case OPAQUE_TYPE:
       if (REFLECTION_TYPE_P (t))
        {
          pp_cxx_type_specifier_seq (this, t);
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 50af008c73b6..db194b8b3977 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -2770,7 +2770,7 @@ write_type (tree type)
              write_expression (PACK_INDEX_INDEX (type));
              break;
 
-           case LANG_TYPE:
+           case OPAQUE_TYPE:
              if (REFLECTION_TYPE_P (type))
                {
                  write_string ("Dm");
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 1fb2eab99f65..c07deff284e3 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -9890,8 +9890,10 @@ trees_out::type_node (tree type)
        }
       break;
 
-    case LANG_TYPE:
-      /* No additional data.  */
+    case OPAQUE_TYPE:
+      /* No additional data.  OPAQUE_TYPEs created by the rs6000 backend
+        are registered as built-in types and are recorded in fixed_trees
+        so they will not get here.  */
       gcc_checking_assert (REFLECTION_TYPE_P (type));
       break;
 
@@ -10746,10 +10748,10 @@ trees_in::tree_node (bool is_use)
            }
            break;
 
-         /* LANG_TYPE can be more things, but here we assume it represents
+         /* OPAQUE_TYPE can be more things, but here we assume it represents
             std::meta::info.  Unfortunately here it's not possible to check
             REFLECTION_TYPE_P.  */
-         case LANG_TYPE:
+         case OPAQUE_TYPE:
            if (!get_overrun ())
              res = meta_info_type_node;
            break;
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index f9a5fda7e1fc..9fd20c0cfd7e 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -1604,13 +1604,6 @@ name_lookup::adl_type (tree type)
       return;
 
     case LANG_TYPE:
-      if (REFLECTION_TYPE_P (type))
-       {
-         /* The namespace std::meta is an associated namespace of
-            std::meta::info.  */
-         adl_namespace (std_meta_node);
-         return;
-       }
       gcc_assert (type == unknown_type_node
                  || type == init_list_type_node);
       return;
@@ -1619,6 +1612,13 @@ name_lookup::adl_type (tree type)
       adl_type (PACK_EXPANSION_PATTERN (type));
       return;
 
+    case OPAQUE_TYPE:
+      if (REFLECTION_TYPE_P (type))
+       /* The namespace std::meta is an associated namespace of
+          std::meta::info.  */
+       adl_namespace (std_meta_node);
+      return;
+
     default:
       break;
     }
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 8bf518df64fa..fd430342de93 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -61,7 +61,7 @@ init_reflection ()
   /* The type std::meta::info is a scalar type for which equality and
      inequality are meaningful, but for which no ordering relation is
      defined.  */
-  meta_info_type_node = make_node (LANG_TYPE);
+  meta_info_type_node = make_node (OPAQUE_TYPE);
   /* Make it a complete type.  */
   TYPE_SIZE (meta_info_type_node) = bitsize_int (GET_MODE_BITSIZE (ptr_mode));
   TYPE_SIZE_UNIT (meta_info_type_node) = size_int (GET_MODE_SIZE (ptr_mode));
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 930694759656..ca77c611c1d7 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5175,7 +5175,7 @@ type_has_unique_obj_representations (const_tree t, bool 
explain/*=false*/)
        inform (loc, "%<std::nullptr_t%> has padding bits and no value bits");
       return false;
 
-    case LANG_TYPE:
+    case OPAQUE_TYPE:
       if (REFLECTION_TYPE_P (t))
        {
          if (explain)
diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi
index e61b151cd863..cc42ba85ac75 100644
--- a/gcc/doc/generic.texi
+++ b/gcc/doc/generic.texi
@@ -498,10 +498,12 @@ constants will be the type of enumeration type itself.
 
 @item OPAQUE_TYPE
 Used for things that have a @code{MODE_OPAQUE} mode class in the
-backend. Opaque types have a size and precision, and can be held in
-memory or registers. They are used when we do not want the compiler to
+backend.  Opaque types have a size and precision, and can be held in
+memory or registers.  They are used when we do not want the compiler to
 make assumptions about the availability of other operations as would
-happen with integer types.
+happen with integer types.  This type can also have a scalar integer
+mode; this is how the C++ front end represents the @code{std::meta::info}
+type.  The only @code{INTEGER_CST} of such a type is zero.
 
 @item BOOLEAN_TYPE
 Used to represent the @code{bool} type.
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index 5348f0aa7a0c..e8a6019f72e0 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -26992,8 +26992,12 @@ gen_type_die_with_usage (tree type, dw_die_ref 
context_die,
       gen_tagged_type_die (type, context_die, usage, reverse);
       return;
 
-    case VOID_TYPE:
     case OPAQUE_TYPE:
+      if (SCALAR_INT_MODE_P (TYPE_MODE (type)))
+       /* C++ std::meta::info type.  */
+       goto unspecified_type;
+      gcc_fallthrough ();
+    case VOID_TYPE:
     case INTEGER_TYPE:
     case REAL_TYPE:
     case FIXED_POINT_TYPE:
diff --git a/gcc/testsuite/g++.dg/lto/pr126017_0.C 
b/gcc/testsuite/g++.dg/lto/pr126017_0.C
new file mode 100644
index 000000000000..97a8e862ff90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126017_0.C
@@ -0,0 +1,14 @@
+// PR c++/126017
+// { dg-lto-do run }
+// { dg-lto-options { { -std=c++26 -O2 -flto -freflection -g } } }
+
+using info = decltype (^^::);
+info a {};
+extern info foo (info);
+
+int
+main ()
+{
+  if (a != info{} || foo (a) != a)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/lto/pr126017_1.C 
b/gcc/testsuite/g++.dg/lto/pr126017_1.C
new file mode 100644
index 000000000000..4a63fa2cbf45
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr126017_1.C
@@ -0,0 +1,22 @@
+// PR c++/126017
+
+#include <meta>
+
+extern std::meta::info a;
+
+consteval std::meta::info
+bar ()
+{
+  struct S;
+  consteval { define_aggregate (^^S, { data_member_spec (^^int, { .name = 
"abc" }) }); }
+  return ^^S;
+}
+
+struct T : [: bar () :] {};
+
+std::meta::info
+foo (std::meta::info x)
+{
+  T a;
+  return x;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/diag6.C 
b/gcc/testsuite/g++.dg/reflect/diag6.C
index 2eed4d0b6336..14cd5f4709f2 100644
--- a/gcc/testsuite/g++.dg/reflect/diag6.C
+++ b/gcc/testsuite/g++.dg/reflect/diag6.C
@@ -5,6 +5,6 @@
 void
 g ()
 {
-  constexpr decltype(^^::) dm = ^^int; // { dg-message ".constexpr 
std::meta::info const dm. previously declared here" }
-  constexpr decltype(^^::) dm = ^^int; // { dg-error "redeclaration of 
.constexpr std::meta::info const dm." }
+  constexpr decltype(^^::) dm = ^^int; // { dg-message ".constexpr const 
std::meta::info dm. previously declared here" }
+  constexpr decltype(^^::) dm = ^^int; // { dg-error "redeclaration of 
.constexpr const std::meta::info dm." }
 }
diff --git a/gcc/testsuite/g++.dg/reflect/init2.C 
b/gcc/testsuite/g++.dg/reflect/init2.C
index c4f2292f21d5..c95570068bcd 100644
--- a/gcc/testsuite/g++.dg/reflect/init2.C
+++ b/gcc/testsuite/g++.dg/reflect/init2.C
@@ -8,7 +8,7 @@ f ()
   constexpr static auto srefl = ^^int;
   constexpr auto *p = &srefl;
   constexpr auto **q = &p;  // { dg-error "unable to deduce" }
-  // { dg-message "types .auto\\*. and .std::meta::info const\\* const." "" { 
target *-*-* } .-1 }
+  // { dg-message "types .auto\\*. and .const std::meta::info\\* const." "" { 
target *-*-* } .-1 }
 }
 
 void
diff --git a/gcc/testsuite/g++.dg/reflect/pr127856.C 
b/gcc/testsuite/g++.dg/reflect/pr127856.C
new file mode 100644
index 000000000000..0faebce184f3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/pr127856.C
@@ -0,0 +1,11 @@
+// PR c++/127856
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-O2 -freflection" }
+
+struct A { decltype (^^int) a; bool b = true; };
+
+void
+foo ()
+{
+  A a;
+}
diff --git a/gcc/testsuite/g++.target/powerpc/reflection1.C 
b/gcc/testsuite/g++.target/powerpc/reflection1.C
new file mode 100644
index 000000000000..815c030e61bd
--- /dev/null
+++ b/gcc/testsuite/g++.target/powerpc/reflection1.C
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target power10_ok }
+// { dg-additional-options "-freflection -mcpu=power10" }
+
+using info = decltype (^^::);
+
+template <typename T> struct W {};
+
+void f (W<info>) {}
+void f (W<__vector_quad>) {}
+void f (W<__vector_pair>) {}
+
+static_assert (^^info != ^^__vector_quad);
+static_assert (__is_scalar (info));
+static_assert (!__is_same (info, __vector_quad));
+
+// { dg-final { scan-assembler "_Z1f1WIDmE" } }
+// { dg-final { scan-assembler "_Z1f1WIu13__vector_quadE" } }
+// { dg-final { scan-assembler "_Z1f1WIu13__vector_pairE" } }
diff --git a/gcc/tree.cc b/gcc/tree.cc
index e43a2b78c61c..7e5a53234bae 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -1862,7 +1862,9 @@ wide_int_to_tree_1 (tree type, const wide_int_ref &pcst)
       switch (code)
        {
        /* This could represent the C++ std::meta::info type.  */
-       case LANG_TYPE:
+       case OPAQUE_TYPE:
+         gcc_assert (SCALAR_INT_MODE_P (TYPE_MODE (type)));
+         /* Fallthru.  */
        case NULLPTR_TYPE:
          gcc_assert (hwi == 0);
          /* Fallthru.  */
@@ -2039,7 +2041,9 @@ cache_integer_cst (tree t, bool might_duplicate 
ATTRIBUTE_UNUSED)
   switch (TREE_CODE (type))
     {
     /* This could represent the C++ std::meta::info type.  */
-    case LANG_TYPE:
+    case OPAQUE_TYPE:
+      gcc_assert (SCALAR_INT_MODE_P (TYPE_MODE (type)));
+      /* Fallthru.  */
     case NULLPTR_TYPE:
       gcc_checking_assert (integer_zerop (t));
       /* Fallthru.  */
@@ -14540,7 +14544,10 @@ verify_opaque_type (const_tree t, tree tv, tree tc)
        debug_tree (t2);
        return;
       }
-    if (!OPAQUE_MODE_P (TYPE_MODE (t2)))
+    /* For C++ Reflection, we use the opaque type with a scalar integer
+       mode.  */
+    if (!OPAQUE_MODE_P (TYPE_MODE (t2))
+       && !SCALAR_INT_MODE_P (TYPE_MODE (t2)))
       {
        error ("type %s is not with opaque mode", kind_msg);
        debug_tree (t2);
diff --git a/gcc/tree.def b/gcc/tree.def
index 2e767dbe0453..c11ad1abf24b 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -265,7 +265,8 @@ DEFTREECODE (LANG_TYPE, "lang_type", tcc_type, 0)
 /* This is for types that will use MODE_OPAQUE in the back end.  They are meant
    to be able to go in a register of some sort but are explicitly not to be
    converted or operated on like INTEGER_TYPE.  They will have size and
-   alignment information only.  */
+   alignment information only.  The C++ FE uses this to represent the
+   std::meta::info type; in that case, it has a scalar integer mode.  */
 DEFTREECODE (OPAQUE_TYPE, "opaque_type", tcc_type, 0)
 
 /* Expressions */

Reply via email to