Message ID | 66f1fd74.a70a0220.265533.05f6@mx.google.com |
---|---|
State | New |
Headers | show |
Series | c++/modules: Implement P1815 "Translation-unit-local entities" | expand |
On Tue, Sep 24, 2024 at 09:44:48AM +1000, Nathaniel Shead wrote: > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? > > -- >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. > Linaro picked up a regression on ARM from this patch where the standard library headers are exporting using-decls of internal linkage entities, which is supposed to be valid (and I'd missed in this version of the patch). Here's an updated version of the patch which handles this case and adds a dedicated testcase for it. Bootstrapped and regtested on x86_64-pc-linux-gnu and aarch64-unknown-linux-gnu. -- >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 <nathanieloshead@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 +}
On 9/24/24 2:53 AM, Nathaniel Shead wrote: > On Tue, Sep 24, 2024 at 09:44:48AM +1000, Nathaniel Shead wrote: >> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? >> >> -- >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. >> > > Linaro picked up a regression on ARM from this patch where the standard > library headers are exporting using-decls of internal linkage entities, > which is supposed to be valid (and I'd missed in this version of the > patch). > > Here's an updated version of the patch which handles this case and adds > a dedicated testcase for it. > > Bootstrapped and regtested on x86_64-pc-linux-gnu and > aarch64-unknown-linux-gnu. OK. > -- >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 <nathanieloshead@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 > +}
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index c0f89f98d87..cbb2827808f 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -5206,38 +5206,43 @@ 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)); - - /* 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; + } + + linkage_kind linkage = decl_linkage (entity); + tree not_tmpl = STRIP_TEMPLATE (entity); - /* 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); + /* 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; +}
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? -- >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, and 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. Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com> --- gcc/cp/name-lookup.cc | 55 ++++++++++++---------- 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 ++++ 6 files changed, 145 insertions(+), 42 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