aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathaniel Shead <nathanieloshead@gmail.com>2025-01-19 15:26:03 +1100
committerNathaniel Shead <nathanieloshead@gmail.com>2025-01-21 09:35:15 +1100
commit2fcb0c079530b019586e5693f057d2eb72855e70 (patch)
treee4ead205e00e072cdb01e15e808af219166104bb
parent5c0e1879ea639dc527d3928af877d3df985e3f13 (diff)
downloadgcc-2fcb0c079530b019586e5693f057d2eb72855e70.zip
gcc-2fcb0c079530b019586e5693f057d2eb72855e70.tar.gz
gcc-2fcb0c079530b019586e5693f057d2eb72855e70.tar.bz2
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 <nathanieloshead@gmail.com>
-rw-r--r--gcc/cp/parser.cc1
-rw-r--r--gcc/cp/tree.cc2
-rw-r--r--gcc/testsuite/g++.dg/modules/export-6.C6
-rw-r--r--gcc/testsuite/g++.dg/modules/hdr-2.H9
4 files changed, 18 insertions, 0 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index ff58a8e..a8ac8af 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 ed01ca4..3658186 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 c59944a..460cdf0 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 097546d..834c682 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;
}