]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Constructor streaming [PR105322]
authorNathan Sidwell <nathan@acm.org>
Fri, 20 Oct 2023 16:20:37 +0000 (12:20 -0400)
committerNathan Sidwell <nathan@acm.org>
Fri, 20 Oct 2023 20:24:49 +0000 (16:24 -0400)
An expresion node's type is streamed after the expression's operands,
because the type can come from some aspect of an operand (for instance
decltype and noexcept). There's a comment in the code explaining that.

But that doesn't work for constructors, which can directly reference
components of their type (eg FIELD_DECLS). If this is a
type-introducing CONSTRUCTOR, we need to ensure the type has been
streamed first. So move CONSTRUCTOR stream to after the type streaming.

The reason things like COMPONENT_REF work is that they stream their
first operand first, and that introduces the type that their second
operand looks up a field in.

gcc/cp/
PR c++/105322
* module.cc (trees_out::core_vals): Stream CONSTRUCTOR operands
after the type.
(trees_in::core_vals): Likewise.
gcc/testsuite/
* g++.dg/modules/decltype-1_a.C: New.
* g++.dg/modules/decltype-1_b.C: New.
* g++.dg/modules/lambda-5_a.C: New.
* g++.dg/modules/lambda-5_b.C: New.

gcc/cp/module.cc
gcc/testsuite/g++.dg/modules/decltype-1_a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/decltype-1_b.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/lambda-5_a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/lambda-5_b.C [new file with mode: 0644]

index bbb1e20b55b483fd76ce4e9bb33d825ec4f15d89..539518d792344cdb508e2d623f144a784627607b 100644 (file)
@@ -6212,19 +6212,9 @@ trees_out::core_vals (tree t)
       break;
 
     case CONSTRUCTOR:
-      {
-       unsigned len = vec_safe_length (t->constructor.elts);
-       if (streaming_p ())
-         WU (len);
-       if (len)
-         for (unsigned ix = 0; ix != len; ix++)
-           {
-             const constructor_elt &elt = (*t->constructor.elts)[ix];
-
-             WT (elt.index);
-             WT (elt.value);
-           }
-      }
+      // This must be streamed /after/ we've streamed the type,
+      // because it can directly refer to elements of the type. Eg,
+      // FIELD_DECLs of a RECORD_TYPE.
       break;
 
     case OMP_CLAUSE:
@@ -6458,6 +6448,21 @@ trees_out::core_vals (tree t)
        WU (prec);
     }
 
+  if (TREE_CODE (t) == CONSTRUCTOR)
+    {
+      unsigned len = vec_safe_length (t->constructor.elts);
+      if (streaming_p ())
+       WU (len);
+      if (len)
+       for (unsigned ix = 0; ix != len; ix++)
+         {
+           const constructor_elt &elt = (*t->constructor.elts)[ix];
+
+           WT (elt.index);
+           WT (elt.value);
+         }
+    }
+
 #undef WT
 #undef WU
 }
@@ -6717,18 +6722,7 @@ trees_in::core_vals (tree t)
       break;
 
     case CONSTRUCTOR:
-      if (unsigned len = u ())
-       {
-         vec_alloc (t->constructor.elts, len);
-         for (unsigned ix = 0; ix != len; ix++)
-           {
-             constructor_elt elt;
-
-             RT (elt.index);
-             RTU (elt.value);
-             t->constructor.elts->quick_push (elt);
-           }
-       }
+      // Streamed after the node's type.
       break;
 
     case OMP_CLAUSE:
@@ -6901,6 +6895,20 @@ trees_in::core_vals (tree t)
        t->typed.type = type;
     }
 
+  if (TREE_CODE (t) == CONSTRUCTOR)
+    if (unsigned len = u ())
+      {
+       vec_alloc (t->constructor.elts, len);
+       for (unsigned ix = 0; ix != len; ix++)
+         {
+           constructor_elt elt;
+
+           RT (elt.index);
+           RTU (elt.value);
+           t->constructor.elts->quick_push (elt);
+         }
+      }
+
 #undef RT
 #undef RM
 #undef RU
diff --git a/gcc/testsuite/g++.dg/modules/decltype-1_a.C b/gcc/testsuite/g++.dg/modules/decltype-1_a.C
new file mode 100644 (file)
index 0000000..ca66e8b
--- /dev/null
@@ -0,0 +1,28 @@
+// PR c++/105322
+// { dg-module-do link
+// { dg-additional-options -fmodules-ts }
+// { dg-module-cmi pr105322.Decltype }
+
+export module pr105322.Decltype;
+
+auto f() {
+  struct A { int m;
+    int get () { return m; }
+  };
+  return A{};
+}
+
+export
+inline void g1() {
+  auto r = decltype(f()){0};
+}
+
+export
+inline void g2() {
+  auto r = f().m;
+}
+
+export
+inline void g3() {
+  auto r = f().get();
+}
diff --git a/gcc/testsuite/g++.dg/modules/decltype-1_b.C b/gcc/testsuite/g++.dg/modules/decltype-1_b.C
new file mode 100644 (file)
index 0000000..6bebe13
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/105322
+// { dg-additional-options -fmodules-ts }
+
+import pr105322.Decltype;
+
+int main() {
+  g1();
+  g2();
+  g3();
+}
diff --git a/gcc/testsuite/g++.dg/modules/lambda-5_a.C b/gcc/testsuite/g++.dg/modules/lambda-5_a.C
new file mode 100644 (file)
index 0000000..6b589d4
--- /dev/null
@@ -0,0 +1,24 @@
+// PR c++/105322
+// { dg-module-do link
+// { dg-additional-options -fmodules-ts }
+// { dg-module-cmi pr105322.Lambda }
+
+export module pr105322.Lambda;
+
+struct A { };
+
+export
+inline void f1() {
+  A a;
+  auto g1 = [a] { }; // used to ICE here during stream out
+}
+
+export
+template<class...>
+void f2() {
+  A a;
+  auto g2 = [a] { };
+}
+
+export
+inline auto g3 = [a=A{}] { };
diff --git a/gcc/testsuite/g++.dg/modules/lambda-5_b.C b/gcc/testsuite/g++.dg/modules/lambda-5_b.C
new file mode 100644 (file)
index 0000000..a7ce709
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/105322
+// { dg-additional-options -fmodules-ts }
+
+import pr105322.Lambda;
+
+int main() {
+  f1();
+  f2();
+  g3();
+}