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); + /* Declarations in header units are always OK. */ + if (header_module_p ()) + return true; - /* Linkage is determined by the owner of an enumerator. */ - if (TREE_CODE (decl) == CONST_DECL) - decl = TYPE_NAME (DECL_CONTEXT (decl)); - - /* 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" } -namespace t { - using a = int; // { dg-message "declared here with no linkage" } +// no linkage +namespace n { + using a3 = struct { int x; }; // { dg-message "declared here with no linkage" } - template - using b = int; // { dg-message "declared here with no linkage" } + struct {} tmp_s; // { dg-message "declared here with no linkage" } + using b3 = decltype(tmp_s); - typedef int c; // { dg-message "declared here with no linkage" } + 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 t::a; // { dg-error "does not have external linkage" } -export using t::b; // { dg-error "does not have external linkage" } +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 { + // aliases have the linkage of the entity they ultimately refer to + using a = int; + typedef a b; + + // a template is not an alias + template + 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" } + + // non-empty enum gets linkage of enumerator name + enum { X } e; // { dg-message "declared here with module 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" } } -namespace t { - using a = int; // { dg-message "declared here with no linkage" } +// no linkage +namespace n { + using a3 = struct { int x; }; // { dg-message "declared here with no linkage" } - template - using b = int; // { dg-message "declared here with no linkage" } + struct {} tmp_s; // { dg-message "declared here with no linkage" } + using b3 = decltype(tmp_s); - typedef int c; // { dg-message "declared here with no linkage" } + enum {} tmp_e; // { dg-message "declared here with no linkage" } + using c3 = decltype(tmp_e); - 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::c; // { dg-error "does not have external linkage" } + 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 { + // aliases have the linkage of the entity they ultimately refer to + using a = int; + typedef a b; + + // a template is not an alias + template + 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" } + + // non-empty enum gets linkage of enumerator name + enum { X } e; // { dg-message "declared here with module 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 +}