Hi!

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.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2025-01-17  Jakub Jelinek  <ja...@redhat.com>

        PR c++/118513
        * decl2.cc (copy_linkage): If not TREE_PUBLIC, also copy
        DECL_INTERFACE_KNOWN and 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.jj  2025-01-16 13:34:29.719360710 +0100
+++ gcc/cp/decl2.cc     2025-01-16 16:25:37.006911025 +0100
@@ -3656,6 +3656,12 @@ 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))
+       {
+         DECL_INTERFACE_KNOWN (guard) = DECL_INTERFACE_KNOWN (decl);
+         if (DECL_LANG_SPECIFIC (decl) && DECL_LANG_SPECIFIC (guard))
+           DECL_NOT_REALLY_EXTERN (guard) = DECL_NOT_REALLY_EXTERN (decl);
+       }
     }
 }
 
--- gcc/testsuite/g++.dg/modules/decomp-3_a.H.jj        2025-01-16 
13:43:36.492879734 +0100
+++ gcc/testsuite/g++.dg/modules/decomp-3_a.H   2025-01-16 13:43:11.314224231 
+0100
@@ -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 };
+}
--- gcc/testsuite/g++.dg/modules/decomp-3_b.C.jj        2025-01-16 
13:43:41.782807354 +0100
+++ gcc/testsuite/g++.dg/modules/decomp-3_b.C   2025-01-16 13:41:49.256346946 
+0100
@@ -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 ();
+}

        Jakub

Reply via email to