]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Copy over further 2 flags for !TREE_PUBLIC in copy_linkage [PR118513]
authorJakub Jelinek <jakub@redhat.com>
Sat, 18 Jan 2025 20:50:23 +0000 (21:50 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Sat, 18 Jan 2025 20:50:23 +0000 (21:50 +0100)
The following testcase ICEs in import_export_decl.
When cp_finish_decomp handles std::tuple* using structural binding,
it calls copy_linkage to copy various VAR_DECL flags from the structured
binding base to the individual sb variables.
In this case the base variable is in anonymous union, so we call
constrain_visibility (..., VISIBILITY_ANON, ...) on it which e.g.
clears TREE_PUBLIC etc. (flags which copy_linkage copies) but doesn't
copy over DECL_INTERFACE_KNOWN/DECL_NOT_REALLY_EXTERN.
When cp_finish_decl calls determine_visibility on the individual sb
variables, those have !TREE_PUBLIC since copy_linkage and so nothing tries
to determine visibility and nothing sets DECL_INTERFACE_KNOWN and
DECL_NOT_REALLY_EXTERN.
Now, this isn't a big deal without modules, the individual variables are
var_finalized_p and so nothing really cares about missing
DECL_INTERFACE_KNOWN.  But in the module case the variables are streamed
out and in and care about those bits.

The following patch is an attempt to copy over also those flags (but I've
limited it to the !TREE_PUBLIC case just in case).  Other option would be
to call it unconditionally, or call constrain_visibility with
VISIBILITY_ANON for !TREE_PUBLIC (but are all !TREE_PUBLIC constrained
visibility) or do it only in the cp_finish_decomp case
after the copy_linkage call there.

2025-01-18  Jakub Jelinek  <jakub@redhat.com>

PR c++/118513
* decl2.cc (copy_linkage): If not TREE_PUBLIC, also set
DECL_INTERFACE_KNOWN, assert it was set on decl and copy
DECL_NOT_REALLY_EXTERN flags.

* g++.dg/modules/decomp-3_a.H: New test.
* g++.dg/modules/decomp-3_b.C: New test.

gcc/cp/decl2.cc
gcc/testsuite/g++.dg/modules/decomp-3_a.H [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/decomp-3_b.C [new file with mode: 0644]

index f64aa848b94aa5e1b3a49baef5f02c71cd7d1d70..55f056ef9dc65d1f70bc89402e22cde2acad64c8 100644 (file)
@@ -3651,6 +3651,13 @@ copy_linkage (tree guard, tree decl)
        comdat_linkage (guard);
       DECL_VISIBILITY (guard) = DECL_VISIBILITY (decl);
       DECL_VISIBILITY_SPECIFIED (guard) = DECL_VISIBILITY_SPECIFIED (decl);
+      if (!TREE_PUBLIC (decl))
+       {
+         gcc_checking_assert (DECL_INTERFACE_KNOWN (decl));
+         DECL_INTERFACE_KNOWN (guard) = 1;
+         if (DECL_LANG_SPECIFIC (decl) && DECL_LANG_SPECIFIC (guard))
+           DECL_NOT_REALLY_EXTERN (guard) = DECL_NOT_REALLY_EXTERN (decl);
+       }
     }
 }
 
diff --git a/gcc/testsuite/g++.dg/modules/decomp-3_a.H b/gcc/testsuite/g++.dg/modules/decomp-3_a.H
new file mode 100644 (file)
index 0000000..74223cc
--- /dev/null
@@ -0,0 +1,20 @@
+// PR c++/118513
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+namespace std {
+  template<typename T> struct tuple_size;
+  template<int, typename> struct tuple_element;
+}
+
+struct A {
+  int a, b;
+  template <int I> int &get () { if (I == 0) return a; else return b; }
+};
+
+template <> struct std::tuple_size <A> { static const int value = 2; };
+template <int I> struct std::tuple_element <I, A> { using type = int; };
+
+namespace {
+auto [x, y] = A { 42, 43 };
+}
diff --git a/gcc/testsuite/g++.dg/modules/decomp-3_b.C b/gcc/testsuite/g++.dg/modules/decomp-3_b.C
new file mode 100644 (file)
index 0000000..00566ab
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/118513
+// { dg-do run }
+// { dg-additional-options "-fmodules-ts" }
+
+import "decomp-3_a.H";
+
+int
+main ()
+{
+  if (x != 42 || y != 43)
+    __builtin_abort ();
+}