diff options
author | Nathaniel Shead <nathanieloshead@gmail.com> | 2023-11-10 14:28:40 +1100 |
---|---|---|
committer | Nathaniel Shead <nathanieloshead@gmail.com> | 2023-11-25 12:44:17 +1100 |
commit | 1f70291b93a07178bb645273cdd80c404d77ba2f (patch) | |
tree | 1feca8b9e05e19e61e43a6bf0e3849648afee788 /gcc | |
parent | 9dd8be6fc2debc4fbd0950386d4e98878af27a45 (diff) | |
download | gcc-1f70291b93a07178bb645273cdd80c404d77ba2f.zip gcc-1f70291b93a07178bb645273cdd80c404d77ba2f.tar.gz gcc-1f70291b93a07178bb645273cdd80c404d77ba2f.tar.bz2 |
c++: more checks for exporting names with using-declarations
Currently only functions are directly checked for validity when
exporting via a using-declaration. This patch also checks exporting
non-external names of variables, types, and enumerators. This also
prevents ICEs with `export using enum` for internal-linkage enums.
While we're at it this patch also improves the error messages for these
cases to provide more context about what went wrong.
gcc/cp/ChangeLog:
* name-lookup.cc (check_can_export_using_decl): New.
(do_nonmember_using_decl): Use above to check if names can be
exported.
gcc/testsuite/ChangeLog:
* g++.dg/modules/using-10.C: New test.
* g++.dg/modules/using-enum-2.C: New test.
Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/name-lookup.cc | 75 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/using-10.C | 71 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/modules/using-enum-2.C | 23 |
3 files changed, 148 insertions, 21 deletions
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 50aeb77..d19ea5d 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -4802,6 +4802,49 @@ pushdecl_outermost_localscope (tree x) return b ? do_pushdecl_with_scope (x, b) : error_mark_node; } +/* Checks if BINDING is a binding that we can export. */ + +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)); + + /* 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))) + { + bool internal_p = !TREE_PUBLIC (decl); + + /* 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); + + 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); + else + inform (DECL_SOURCE_LOCATION (binding), + "%q#D declared here with module linkage", binding); + return false; + } + + return true; +} + /* Process a local-scope or namespace-scope using declaration. LOOKUP is the result of qualified lookup (both value & type are significant). FN_SCOPE_P indicates if we're at function-scope (as @@ -4845,23 +4888,7 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, tree new_fn = *usings; bool exporting = revealing_p && module_exporting_p (); if (exporting) - { - /* Module flags for templates are on the template_result. */ - tree decl = STRIP_TEMPLATE (new_fn); - - /* 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))) - { - auto_diagnostic_group d; - error ("%q#D does not have external linkage", new_fn); - inform (DECL_SOURCE_LOCATION (new_fn), - "%q#D declared here", new_fn); - exporting = false; - } - } + exporting = check_can_export_using_decl (new_fn); /* [namespace.udecl] @@ -4939,20 +4966,26 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, failed = true; } else if (insert_p) - // FIXME:what if we're newly exporting lookup.value - value = lookup.value; + { + value = lookup.value; + if (revealing_p && module_exporting_p ()) + check_can_export_using_decl (value); + } /* Now the type binding. */ if (lookup.type && lookup.type != type) { - // FIXME: What if we're exporting lookup.type? if (type && !decls_match (lookup.type, type)) { diagnose_name_conflict (lookup.type, type); failed = true; } else if (insert_p) - type = lookup.type; + { + type = lookup.type; + if (revealing_p && module_exporting_p ()) + check_can_export_using_decl (type); + } } if (insert_p) diff --git a/gcc/testsuite/g++.dg/modules/using-10.C b/gcc/testsuite/g++.dg/modules/using-10.C new file mode 100644 index 0000000..5735353 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-10.C @@ -0,0 +1,71 @@ +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi !bad } + +export module bad; + +// internal linkage +namespace s { + namespace { + struct a1 {}; // { dg-message "declared here with internal linkage" } + + template <typename T> + struct b1; // { dg-message "declared here with internal linkage" } + + int x1; // { dg-message "declared here with internal linkage" } + + template <typename T> + T y1; // { dg-message "declared here with internal linkage" } + + void f1(); // { dg-message "declared here with internal linkage" } + + template <typename T> + void g1(); // { dg-message "declared here with internal linkage" } + } +} + +// module linkage +namespace m { + struct a2 {}; // { dg-message "declared here with module linkage" } + + template <typename T> + struct b2; // { dg-message "declared here with module linkage" } + + int x2; // { dg-message "declared here with module linkage" } + + template <typename T> + T y2; // { dg-message "declared here with module linkage" } + + void f2(); // { dg-message "declared here with module linkage" } + + template <typename T> + 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" } +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" } + + template <typename T> + using b = int; // { dg-message "declared here with no linkage" } + + typedef int c; // { dg-message "declared here with no 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::c; // { dg-error "does not have external linkage" } + +// { dg-prune-output "not writing module" } diff --git a/gcc/testsuite/g++.dg/modules/using-enum-2.C b/gcc/testsuite/g++.dg/modules/using-enum-2.C new file mode 100644 index 0000000..813e2f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-enum-2.C @@ -0,0 +1,23 @@ +// { dg-additional-options "-fmodules-ts -std=c++2a" } +// { dg-module-cmi !bad } + +export module bad; + +namespace s { + namespace { + enum e1 { x1 }; // { dg-message "declared here with internal linkage" } + enum class e2 { x2 }; // { dg-message "declared here with internal linkage" } + } +} + +namespace m { + enum e3 { x3 }; // { dg-message "declared here with module linkage" } + enum class e4 { x4 }; // { dg-message "declared here with module linkage" } +} + +export using enum s::e1; // { dg-error "does not have external linkage" } +export using enum s::e2; // { dg-error "does not have external linkage" } +export using enum m::e3; // { dg-error "does not have external linkage" } +export using enum m::e4; // { dg-error "does not have external linkage" } + +// { dg-prune-output "not writing module" } |