diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index a17d8433e34..0d9e50bba7f 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -13478,16 +13478,35 @@ bool depset::hash::is_tu_local_entity (tree decl, bool explain/*=false*/) { gcc_checking_assert (DECL_P (decl)); + location_t loc = DECL_SOURCE_LOCATION (decl); + tree type = TREE_TYPE (decl); - /* An explicit type alias is not an entity, and so is never TU-local. - Neither are the built-in declarations of 'int' and such. */ + /* Only types, functions, variables, and template (specialisations) + can be TU-local. */ + if (TREE_CODE (decl) != TYPE_DECL + && TREE_CODE (decl) != FUNCTION_DECL + && TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != TEMPLATE_DECL) + return false; + + /* An explicit type alias is not an entity; we don't want to stream + such aliases if they refer to TU-local entities, so propagate this + from the original type. The built-in declarations of 'int' and such + are never TU-local. */ if (TREE_CODE (decl) == TYPE_DECL && !DECL_SELF_REFERENCE_P (decl) && !DECL_IMPLICIT_TYPEDEF_P (decl)) - return false; - - location_t loc = DECL_SOURCE_LOCATION (decl); - tree type = TREE_TYPE (decl); + { + tree orig = DECL_ORIGINAL_TYPE (decl); + if (orig && TYPE_NAME (orig)) + { + if (explain) + inform (loc, "%qD is an alias of TU-local type %qT", decl, orig); + return is_tu_local_entity (TYPE_NAME (orig), explain); + } + else + return false; + } /* Check specializations first for slightly better explanations. */ int use_tpl = -1; @@ -16623,8 +16642,9 @@ module_state::write_namespaces (elf_out *to, vec spaces, depset *b = spaces[ix]; tree ns = b->get_entity (); + /* This could be an anonymous namespace even for a named module, + since we can still emit no-linkage decls. */ gcc_checking_assert (TREE_CODE (ns) == NAMESPACE_DECL); - gcc_checking_assert (TREE_PUBLIC (ns) || header_module_p ()); unsigned flags = 0; if (TREE_PUBLIC (ns)) @@ -20579,13 +20599,25 @@ check_module_decl_linkage (tree decl) /* An internal-linkage declaration cannot be generally be exported. But it's OK to export any declaration from a header unit, including internal linkage declarations. */ - if (!header_module_p () - && DECL_MODULE_EXPORT_P (decl) - && decl_linkage (decl) == lk_internal) + if (!header_module_p () && DECL_MODULE_EXPORT_P (decl)) { - error_at (DECL_SOURCE_LOCATION (decl), - "exporting declaration %qD with internal linkage", decl); - DECL_MODULE_EXPORT_P (decl) = false; + /* Let's additionally treat any exported declaration within an + internal namespace as exporting a declaration with internal + linkage, as this would also implicitly export the internal + linkage namespace. */ + if (decl_internal_context_p (decl)) + { + error_at (DECL_SOURCE_LOCATION (decl), + "exporting declaration %qD declared in unnamed namespace", + decl); + DECL_MODULE_EXPORT_P (decl) = false; + } + else if (decl_linkage (decl) == lk_internal) + { + error_at (DECL_SOURCE_LOCATION (decl), + "exporting declaration %qD with internal linkage", decl); + DECL_MODULE_EXPORT_P (decl) = false; + } } } diff --git a/gcc/testsuite/g++.dg/modules/export-6.C b/gcc/testsuite/g++.dg/modules/export-6.C index 460cdf08ea9..af54e5fbe87 100644 --- a/gcc/testsuite/g++.dg/modules/export-6.C +++ b/gcc/testsuite/g++.dg/modules/export-6.C @@ -16,27 +16,32 @@ export static auto [d] = S{}; // { dg-error "internal linkage" "" { target c++2 #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 void v(); // { dg-error "internal linkage" } - export template void w() {} // { dg-error "internal linkage" } - export auto [e] = S{}; // { dg-error "internal linkage" } + export int y = 456; // { dg-error "exporting" } + export void h(); // { dg-error "exporting" } + export void i() {} // { dg-error "exporting" } + export template void v(); // { dg-error "exporting" } + export template void w() {} // { dg-error "exporting" } + export auto [e] = S{}; // { dg-error "exporting" } - export namespace ns {} // { dg-error "internal linkage" } - export namespace alias = global; // { dg-error "internal linkage" } + export namespace ns {} // { dg-error "exporting" } + export namespace alias = global; // { dg-error "exporting" } - export struct A {}; // { dg-error "internal linkage" } - export template struct B {}; // { dg-error "internal linkage" } + export struct A {}; // { dg-error "exporting" } + export template struct B {}; // { dg-error "exporting" } - export enum E {}; // { dg-error "internal linkage" } - export enum class F {}; // { dg-error "internal linkage" } + export enum E {}; // { dg-error "exporting" } + export enum class F {}; // { dg-error "exporting" } - export template using U = int; // { dg-error "internal linkage" } + export template using U = int; // { dg-error "exporting" } #if __cplusplus >= 202002L - export template concept C = true; // { dg-error "internal linkage" "" { target c++20 } } + export template concept C = true; // { dg-error "exporting" "" { target c++20 } } #endif + + // Also complain about exporting no-linkage decls in an unnamed namespace + export typedef int T; // { dg-error "exporting" } + export typedef struct {} *PC; // { dg-error "exporting" } + export using V = int; // { dg-error "exporting" } } export namespace {} // { dg-error "exporting unnamed namespace" } diff --git a/gcc/testsuite/g++.dg/modules/internal-4_b.C b/gcc/testsuite/g++.dg/modules/internal-4_b.C index 81fc65a69bd..a6ccb43b446 100644 --- a/gcc/testsuite/g++.dg/modules/internal-4_b.C +++ b/gcc/testsuite/g++.dg/modules/internal-4_b.C @@ -32,8 +32,8 @@ inline void expose_header_decl() { // { dg-error "exposes TU-local entity" } header_f(); } -// We additionally consider a namespace with internal linkage as TU-local -namespace expose_ns = internal_ns; // { dg-error "exposes TU-local entity" } +// A namespace with internal linkage is not inherently an exposure. +namespace expose_ns = internal_ns; // { dg-bogus "exposes TU-local entity" } // But we don't consider a weakref as being TU-local, despite being // marked static; this is to support uses of weakrefs in header files @@ -56,9 +56,12 @@ static auto get_local_type() { static auto get_local_lambda() { return []{}; } -using T = decltype(get_local_ok()); // OK -using U = decltype(get_local_type()); // { dg-error "exposes TU-local entity" } -using V = decltype(get_local_lambda()); // { dg-error "exposes TU-local entity" } +using T = decltype(get_local_ok()); +T* expose_t; // OK +using U = decltype(get_local_type()); +U* expose_u; // { dg-error "exposes TU-local entity" } +using V = decltype(get_local_lambda()); +V* expose_v; // { dg-error "exposes TU-local entity" } static auto internal_lambda = []{ internal_f(); }; // OK auto expose_lambda = internal_lambda; // { dg-error "exposes TU-local entity" } @@ -73,7 +76,8 @@ int not_in_tu_local struct {} no_name; // { dg-error "exposes TU-local entity" } enum {} e; // { dg-error "exposes TU-local entity" } -using not_an_initializer = class {}; // { dg-error "exposes TU-local entity" } +using not_an_initializer = class {}; +not_an_initializer expose_nai; // { dg-error "exposes TU-local entity" } class in_class_specifier { struct {} x; }; // OK void in_function_body() { struct {} x; } // OK @@ -81,7 +85,8 @@ auto in_initializer = []{}; // OK #if __cplusplus >= 202002L decltype([]{}) d_lambda; // { dg-error "exposes TU-local entity" "" { target c++20 } } -using alias_lambda = decltype([]{}); // { dg-error "exposes TU-local entity" "" { target c++20 } } +using alias_lambda = decltype([]{}); +alias_lambda expose_lam; // { dg-error "exposes TU-local entity" "" { target c++20 } } template concept in_constraint_expression = requires { diff --git a/gcc/testsuite/g++.dg/modules/using-30_a.C b/gcc/testsuite/g++.dg/modules/using-30_a.C new file mode 100644 index 00000000000..def719ce3e5 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-30_a.C @@ -0,0 +1,13 @@ +// { dg-additional-options "-fmodules" } +// { dg-module-cmi M } + +export module M; + +namespace { + using A = int; + typedef int B; + + struct Internal {}; + using C = Internal; + typedef Internal D; +} diff --git a/gcc/testsuite/g++.dg/modules/using-30_b.C b/gcc/testsuite/g++.dg/modules/using-30_b.C new file mode 100644 index 00000000000..aeee19f4887 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-30_b.C @@ -0,0 +1,10 @@ +// { dg-additional-options "-fmodules" } + +module M; + +A x; +B y; + +// Aliases that refer to TU-local entities should not be visible. +C c; // { dg-error "does not name a type" } +D d; // { dg-error "does not name a type" } diff --git a/gcc/testsuite/g++.dg/modules/using-30_c.C b/gcc/testsuite/g++.dg/modules/using-30_c.C new file mode 100644 index 00000000000..5ba59817da4 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-30_c.C @@ -0,0 +1,17 @@ +// { dg-additional-options "-fmodules" } +// The different declarations in the anonymous namespace shouldn't clash with +// those in M. + +namespace { + using A = double; + typedef double B; + using C = double; + typedef double D; +} +import M; +int main() { + A a = 1.0; + B b = 2.0; + C c = 3.0; + D d = 4.0; +}