-- >8 --
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>
---
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(-)
create mode 100644 gcc/testsuite/g++.dg/modules/using-27.C
create mode 100644 gcc/testsuite/g++.dg/modules/using-28_a.C
create mode 100644 gcc/testsuite/g++.dg/modules/using-28_b.C
create mode 100644 gcc/testsuite/g++.dg/modules/using-29.H
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index c0f89f98d87..eb365b259d9 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 d468a36f5d8..6f82b5dd147 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 52ef3c6285d..4fd71696f62 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 00000000000..857d7d4a035
--- /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 00000000000..96bbef57f64
--- /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 00000000000..72876b517ca
--- /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 00000000000..ea44e0a78cc
--- /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
+}