aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2023-10-20 12:20:37 -0400
committerNathan Sidwell <nathan@acm.org>2023-10-20 16:24:49 -0400
commit084addf8a700fab9222d4127ab8524920d0ca481 (patch)
tree1ce1f519ced10494d25476a8a194e7e2ed2d124a /gcc
parent7069ea909f5292a17d22e5e68218373186820d29 (diff)
downloadgcc-084addf8a700fab9222d4127ab8524920d0ca481.zip
gcc-084addf8a700fab9222d4127ab8524920d0ca481.tar.gz
gcc-084addf8a700fab9222d4127ab8524920d0ca481.tar.bz2
c++: Constructor streaming [PR105322]
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/module.cc58
-rw-r--r--gcc/testsuite/g++.dg/modules/decltype-1_a.C28
-rw-r--r--gcc/testsuite/g++.dg/modules/decltype-1_b.C10
-rw-r--r--gcc/testsuite/g++.dg/modules/lambda-5_a.C24
-rw-r--r--gcc/testsuite/g++.dg/modules/lambda-5_b.C10
5 files changed, 105 insertions, 25 deletions
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index bbb1e20..539518d 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -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
index 0000000..ca66e8b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/decltype-1_a.C
@@ -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
index 0000000..6bebe13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/decltype-1_b.C
@@ -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
index 0000000..6b589d4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-5_a.C
@@ -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
index 0000000..a7ce709
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/lambda-5_b.C
@@ -0,0 +1,10 @@
+// PR c++/105322
+// { dg-additional-options -fmodules-ts }
+
+import pr105322.Lambda;
+
+int main() {
+ f1();
+ f2();
+ g3();
+}