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

commit r15-3912-gd0762e93ce1ed046e1dd9477ebe0ad941c298677
Author: Nathaniel Shead <nathanielosh...@gmail.com>
Date:   Wed Sep 4 01:18:19 2024 +1000

    c++/modules: Fix linkage checks for exported using-decls
    
    This fixes some inconsistencies with what kinds of linkage various
    entities are assumed to have.  This also fixes handling of exported
    using-decls binding to GM entities and type aliases to better align with
    the standard's requirements.
    
    gcc/cp/ChangeLog:
    
            * name-lookup.cc (check_can_export_using_decl): Handle internal
            linkage GM entities (but ignore in header units); use linkage
            of entity ultimately referred to by aliases.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/modules/using-10.C: Add tests for no-linkage, fix
            expected linkage of aliases.
            * g++.dg/modules/using-12.C: Likewise.
            * g++.dg/modules/using-27.C: New test.
            * g++.dg/modules/using-28_a.C: New test.
            * g++.dg/modules/using-28_b.C: New test.
            * g++.dg/modules/using-29.H: New test.
    
    Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 gcc/cp/name-lookup.cc                     | 57 ++++++++++++++++++-------------
 gcc/testsuite/g++.dg/modules/using-10.C   | 56 +++++++++++++++++++++++-------
 gcc/testsuite/g++.dg/modules/using-12.C   | 42 ++++++++++++++++++++---
 gcc/testsuite/g++.dg/modules/using-27.C   | 14 ++++++++
 gcc/testsuite/g++.dg/modules/using-28_a.C | 12 +++++++
 gcc/testsuite/g++.dg/modules/using-28_b.C |  8 +++++
 gcc/testsuite/g++.dg/modules/using-29.H   |  6 ++++
 7 files changed, 154 insertions(+), 41 deletions(-)

diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index c0f89f98d87e..eb365b259d92 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -5206,38 +5206,47 @@ pushdecl_outermost_localscope (tree x)
 static bool
 check_can_export_using_decl (tree binding)
 {
-  tree decl = STRIP_TEMPLATE (binding);
-
-  /* Linkage is determined by the owner of an enumerator.  */
-  if (TREE_CODE (decl) == CONST_DECL)
-    decl = TYPE_NAME (DECL_CONTEXT (decl));
+  /* Declarations in header units are always OK.  */
+  if (header_module_p ())
+    return true;
 
-  /* If the using decl is exported, the things it refers
-     to must also be exported (or not have module attachment).  */
-  if (!DECL_MODULE_EXPORT_P (decl)
-      && (DECL_LANG_SPECIFIC (decl)
-         && DECL_MODULE_ATTACH_P (decl)))
+  /* We want the linkage of the underlying entity, so strip typedefs.
+     If the underlying entity is a builtin type then we're OK.  */
+  tree entity = binding;
+  if (TREE_CODE (entity) == TYPE_DECL)
     {
-      bool internal_p = !TREE_PUBLIC (decl);
+      entity = TYPE_MAIN_DECL (TREE_TYPE (entity));
+      if (!entity)
+       return true;
+    }
 
-      /* A template in an anonymous namespace doesn't constrain TREE_PUBLIC
-        until it's instantiated, so double-check its context.  */
-      if (!internal_p && TREE_CODE (binding) == TEMPLATE_DECL)
-       internal_p = decl_internal_context_p (decl);
+  linkage_kind linkage = decl_linkage (entity);
+  tree not_tmpl = STRIP_TEMPLATE (entity);
 
+  /* Attachment is determined by the owner of an enumerator.  */
+  if (TREE_CODE (not_tmpl) == CONST_DECL)
+    not_tmpl = TYPE_NAME (DECL_CONTEXT (not_tmpl));
+
+  /* If the using decl is exported, the things it refers to must
+     have external linkage.  decl_linkage returns lk_external for
+     module linkage so also check for attachment.  */
+  if (linkage != lk_external
+      || (DECL_LANG_SPECIFIC (not_tmpl)
+         && DECL_MODULE_ATTACH_P (not_tmpl)
+         && !DECL_MODULE_EXPORT_P (not_tmpl)))
+    {
       auto_diagnostic_group d;
       error ("exporting %q#D that does not have external linkage",
             binding);
-      if (TREE_CODE (decl) == TYPE_DECL && !DECL_IMPLICIT_TYPEDEF_P (decl))
-       /* An un-exported explicit type alias has no linkage.  */
-       inform (DECL_SOURCE_LOCATION (binding),
-               "%q#D declared here with no linkage", binding);
-      else if (internal_p)
-       inform (DECL_SOURCE_LOCATION (binding),
-               "%q#D declared here with internal linkage", binding);
+      if (linkage == lk_none)
+       inform (DECL_SOURCE_LOCATION (entity),
+               "%q#D declared here with no linkage", entity);
+      else if (linkage == lk_internal)
+       inform (DECL_SOURCE_LOCATION (entity),
+               "%q#D declared here with internal linkage", entity);
       else
-       inform (DECL_SOURCE_LOCATION (binding),
-               "%q#D declared here with module linkage", binding);
+       inform (DECL_SOURCE_LOCATION (entity),
+               "%q#D declared here with module linkage", entity);
       return false;
     }
 
diff --git a/gcc/testsuite/g++.dg/modules/using-10.C 
b/gcc/testsuite/g++.dg/modules/using-10.C
index d468a36f5d87..6f82b5dd147a 100644
--- a/gcc/testsuite/g++.dg/modules/using-10.C
+++ b/gcc/testsuite/g++.dg/modules/using-10.C
@@ -23,6 +23,13 @@ namespace s {
   }
 }
 
+export using s::a1;  // { dg-error "does not have external linkage" }
+export using s::b1;  // { dg-error "does not have external linkage" }
+export using s::x1;  // { dg-error "does not have external linkage" }
+export using s::y1;  // { dg-error "does not have external linkage" }
+export using s::f1;  // { dg-error "does not have external linkage" }
+export using s::g1;  // { dg-error "does not have external linkage" }
+
 // module linkage
 namespace m {
   struct a2 {};  // { dg-message "declared here with module linkage" }
@@ -41,13 +48,6 @@ namespace m {
   void g2();  // { dg-message "declared here with module linkage" }
 }
 
-export using s::a1;  // { dg-error "does not have external linkage" }
-export using s::b1;  // { dg-error "does not have external linkage" }
-export using s::x1;  // { dg-error "does not have external linkage" }
-export using s::y1;  // { dg-error "does not have external linkage" }
-export using s::f1;  // { dg-error "does not have external linkage" }
-export using s::g1;  // { dg-error "does not have external linkage" }
-
 export using m::a2;  // { dg-error "does not have external linkage" }
 export using m::b2;  // { dg-error "does not have external linkage" }
 export using m::x2;  // { dg-error "does not have external linkage" }
@@ -55,15 +55,47 @@ export using m::y2;  // { dg-error "does not have external 
linkage" }
 export using m::f2;  // { dg-error "does not have external linkage" }
 export using m::g2;  // { dg-error "does not have external linkage" }
 
+// no linkage
+namespace n {
+  using a3 = struct { int x; };  // { dg-message "declared here with no 
linkage" }
+
+  struct {} tmp_s;  // { dg-message "declared here with no linkage" }
+  using b3 = decltype(tmp_s);
+
+  enum {} tmp_e;  // { dg-message "declared here with no linkage" }
+  using c3 = decltype(tmp_e);
+
+  auto foo() {
+    struct s {};  // { dg-message "declared here with no linkage" }
+    return s{};
+  }
+  using d3 = decltype(foo());
+}
+
+export using n::a3;  // { dg-error "does not have external linkage" }
+export using n::b3;  // { dg-error "does not have external linkage" }
+export using n::c3;  // { dg-error "does not have external linkage" }
+export using n::d3;  // { dg-error "does not have external linkage" }
+
+// typedefs
 namespace t {
-  using a = int;  // { dg-message "declared here with no linkage" }
+  // aliases have the linkage of the entity they ultimately refer to
+  using a = int;
+  typedef a b;
 
+  // a template is not an alias
   template <typename T>
-  using b = int;  // { dg-message "declared here with no linkage" }
+  using c = int;  // { dg-message "declared here with module linkage" }
+
+  // anonymous type with typedef name for linkage purposes
+  typedef struct {} d;  // { dg-message "declared here with module linkage" }
 
-  typedef int c;  // { dg-message "declared here with no linkage" }
+  // non-empty enum gets linkage of enumerator name
+  enum { X } e;  // { dg-message "declared here with module linkage"} 
 }
 
-export using t::a;  // { dg-error "does not have external linkage" }
-export using t::b;  // { dg-error "does not have external linkage" }
+export using t::a;
+export using t::b;
 export using t::c;  // { dg-error "does not have external linkage" }
+export using t::d;  // { dg-error "does not have external linkage" }
+export using t::e;  // { dg-error "does not have external linkage" }
diff --git a/gcc/testsuite/g++.dg/modules/using-12.C 
b/gcc/testsuite/g++.dg/modules/using-12.C
index 52ef3c6285d8..4fd71696f62b 100644
--- a/gcc/testsuite/g++.dg/modules/using-12.C
+++ b/gcc/testsuite/g++.dg/modules/using-12.C
@@ -57,15 +57,47 @@ namespace m {
   export using m::g2;  // { dg-error "does not have external linkage" }
 }
 
+// no linkage
+namespace n {
+  using a3 = struct { int x; };  // { dg-message "declared here with no 
linkage" }
+
+  struct {} tmp_s;  // { dg-message "declared here with no linkage" }
+  using b3 = decltype(tmp_s);
+
+  enum {} tmp_e;  // { dg-message "declared here with no linkage" }
+  using c3 = decltype(tmp_e);
+
+  auto foo() {
+    struct s {};  // { dg-message "declared here with no linkage" }
+    return s{};
+  }
+  using d3 = decltype(foo());
+
+  export using n::a3;  // { dg-error "does not have external linkage" }
+  export using n::b3;  // { dg-error "does not have external linkage" }
+  export using n::c3;  // { dg-error "does not have external linkage" }
+  export using n::d3;  // { dg-error "does not have external linkage" }
+}
+
+// typedefs
 namespace t {
-  using a = int;  // { dg-message "declared here with no linkage" }
+  // aliases have the linkage of the entity they ultimately refer to
+  using a = int;
+  typedef a b;
 
+  // a template is not an alias
   template <typename T>
-  using b = int;  // { dg-message "declared here with no linkage" }
+  using c = int;  // { dg-message "declared here with module linkage" }
+
+  // anonymous type with typedef name for linkage purposes
+  typedef struct {} d;  // { dg-message "declared here with module linkage" }
 
-  typedef int c;  // { dg-message "declared here with no linkage" }
+  // non-empty enum gets linkage of enumerator name
+  enum { X } e;  // { dg-message "declared here with module linkage" }
 
-  export using t::a;  // { dg-error "does not have external linkage" }
-  export using t::b;  // { dg-error "does not have external linkage" }
+  export using t::a;
+  export using t::b;
   export using t::c;  // { dg-error "does not have external linkage" }
+  export using t::d;  // { dg-error "does not have external linkage" }
+  export using t::e;  // { dg-error "does not have external linkage" }
 }
diff --git a/gcc/testsuite/g++.dg/modules/using-27.C 
b/gcc/testsuite/g++.dg/modules/using-27.C
new file mode 100644
index 000000000000..857d7d4a035f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-27.C
@@ -0,0 +1,14 @@
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi !bad }
+
+module;
+
+static int x = 123;   // { dg-message "declared here with internal linkage" }
+static void f() {}    // { dg-message "declared here with internal linkage" }
+using T = struct {};  // { dg-message "declared here with no linkage" }
+
+export module bad;
+
+export using ::x;  // { dg-error "does not have external linkage" }
+export using ::f;  // { dg-error "does not have external linkage" }
+export using ::T;  // { dg-error "does not have external linkage" }
diff --git a/gcc/testsuite/g++.dg/modules/using-28_a.C 
b/gcc/testsuite/g++.dg/modules/using-28_a.C
new file mode 100644
index 000000000000..96bbef57f646
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-28_a.C
@@ -0,0 +1,12 @@
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi M }
+// Test that typedef names correctly provide external linkage
+
+module;
+typedef struct { int x; } A;
+export module M;
+
+export typedef struct {} B;
+
+export using ::A;
+export using ::B;
diff --git a/gcc/testsuite/g++.dg/modules/using-28_b.C 
b/gcc/testsuite/g++.dg/modules/using-28_b.C
new file mode 100644
index 000000000000..72876b517cad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-28_b.C
@@ -0,0 +1,8 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import M;
+
+int main() {
+  A a { 10 };
+  B b;
+}
diff --git a/gcc/testsuite/g++.dg/modules/using-29.H 
b/gcc/testsuite/g++.dg/modules/using-29.H
new file mode 100644
index 000000000000..ea44e0a78ccd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-29.H
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fmodule-header" }
+
+static int foo = 123;
+namespace ns {
+  using ::foo;  // OK, we're in a header unit
+}

Reply via email to