https://gcc.gnu.org/g:2fcb0c079530b019586e5693f057d2eb72855e70

commit r15-7085-g2fcb0c079530b019586e5693f057d2eb72855e70
Author: Nathaniel Shead <nathanielosh...@gmail.com>
Date:   Sun Jan 19 15:26:03 2025 +1100

    c++/modules: Check linkage of structured binding decls
    
    When looking at PR c++/118513 I noticed that we don't currently check
    the linkage of structured binding declarations in modules.  This patch
    adds those checks, and corrects decl_linkage to properly recognise
    structured binding declarations as potentially having linkage.
    
    gcc/cp/ChangeLog:
    
            * parser.cc (cp_parser_decomposition_declaration): Check linkage
            of structured bindings in modules.
            * tree.cc (decl_linkage): Structured bindings don't necessarily
            have no linkage.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/modules/export-6.C: Add structured binding tests.
            * g++.dg/modules/hdr-2.H: Likewise.
    
    Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>

Diff:
---
 gcc/cp/parser.cc                        | 1 +
 gcc/cp/tree.cc                          | 2 ++
 gcc/testsuite/g++.dg/modules/export-6.C | 6 ++++++
 gcc/testsuite/g++.dg/modules/hdr-2.H    | 9 +++++++++
 4 files changed, 18 insertions(+)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index ff58a8ec98e4..a8ac8af09550 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -16728,6 +16728,7 @@ cp_parser_decomposition_declaration (cp_parser *parser,
          cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE,
                          (is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT),
                          &decomp);
+         check_module_decl_linkage (decl);
        }
     }
   else if (decl != error_mark_node)
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index ed01ca42eafe..36581865a177 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -6003,6 +6003,8 @@ decl_linkage (tree decl)
     {
       if (TREE_CODE (decl) == TYPE_DECL && !TYPE_ANON_P (TREE_TYPE (decl)))
        /* This entity has a typedef name for linkage purposes.  */;
+      else if (DECL_DECOMPOSITION_P (decl) && DECL_DECOMP_IS_BASE (decl))
+       /* Namespace-scope structured bindings can have linkage.  */;
       else if (TREE_CODE (decl) == NAMESPACE_DECL && cxx_dialect >= cxx11)
        /* An anonymous namespace has internal linkage since C++11.  */
        return lk_internal;
diff --git a/gcc/testsuite/g++.dg/modules/export-6.C 
b/gcc/testsuite/g++.dg/modules/export-6.C
index c59944aa6888..460cdf08ea99 100644
--- a/gcc/testsuite/g++.dg/modules/export-6.C
+++ b/gcc/testsuite/g++.dg/modules/export-6.C
@@ -3,6 +3,7 @@
 
 export module bad;
 namespace global {}
+struct S { int x; };
 
 export static int x = 123;  // { dg-error "internal linkage" }
 export static void f();  // { dg-error "internal linkage" }
@@ -10,12 +11,17 @@ export static void g() {}  // { dg-error "internal linkage" 
}
 export template <typename T> static void t();  // { dg-error "internal 
linkage" }
 export template <typename T> static void u() {}  // { dg-error "internal 
linkage" }
 
+#if __cplusplus >= 202002L
+export static auto [d] = S{};  // { dg-error "internal linkage" "" { target 
c++20 } }
+#endif
+
 namespace {
   export int y = 456;  // { dg-error "internal linkage" }
   export void h();  // { dg-error "internal linkage" }
   export void i() {}  // { dg-error "internal linkage" }
   export template <typename T> void v(); // { dg-error "internal linkage" }
   export template <typename T> void w() {} // { dg-error "internal linkage" }
+  export auto [e] = S{};  // { dg-error "internal linkage" }
 
   export namespace ns {}  // { dg-error "internal linkage" }
   export namespace alias = global;  // { dg-error "internal linkage" }
diff --git a/gcc/testsuite/g++.dg/modules/hdr-2.H 
b/gcc/testsuite/g++.dg/modules/hdr-2.H
index 097546d56674..834c68241b85 100644
--- a/gcc/testsuite/g++.dg/modules/hdr-2.H
+++ b/gcc/testsuite/g++.dg/modules/hdr-2.H
@@ -3,8 +3,11 @@
 // external linkage variables or functions in header units must
 // not have non-inline definitions
 
+struct S { int x; };
+
 int x_err;  // { dg-error "external linkage definition" }
 int y_err = 123;  // { dg-error "external linkage definition" }
+auto [d_err] = S{};  // { dg-error "external linkage definition" }
 void f_err() {}  // { dg-error "external linkage definition" }
 
 struct Err {
@@ -59,6 +62,7 @@ struct Inl {
 // Internal linkage decls are OK
 static int x_internal;
 static int y_internal = 123;
+namespace { auto [d_internal] = S{}; }
 static void f_internal() {}
 
 namespace {
@@ -81,6 +85,11 @@ inline void f_static() {
   thread_local int x_thread_local;
   thread_local int y_thread_local = 123;
 
+#if __cplusplus >= 202002L
+  static auto [d_static] = S{};
+  thread_local auto [d_thread_local] = S{};
+#endif
+
   x_static = y_static;
   x_thread_local = y_thread_local;
 }

Reply via email to