[gcc r15-4061] c++: Allow references to internal-linkage vars in C++11 [PR113266]
https://gcc.gnu.org/g:247643c7e21b087e6c93b8b8d49b4268bf84b03b commit r15-4061-g247643c7e21b087e6c93b8b8d49b4268bf84b03b Author: Nathaniel Shead Date: Fri Oct 4 12:01:38 2024 +1000 c++: Allow references to internal-linkage vars in C++11 [PR113266] [temp.arg.nontype] changed in C++11 to allow naming internal-linkage variables and functions. We currently already handle internal-linkage functions, but variables were missed; this patch updates this. PR c++/113266 PR c++/116911 gcc/cp/ChangeLog: * parser.cc (cp_parser_template_argument): Allow internal-linkage variables since C++11. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/nontype6.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/parser.cc | 17 - gcc/testsuite/g++.dg/cpp0x/nontype6.C | 19 +++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 08f9c89f1f04..9d31a975dcf9 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -19864,9 +19864,11 @@ cp_parser_template_argument (cp_parser* parser) -- the name of a non-type template-parameter; or - -- the name of an object or function with external linkage... + -- the name of an object or function with external (or internal, + since C++11) linkage... - -- the address of an object or function with external linkage... + -- the address of an object or function with external (or internal, + since C++11) linkage... -- a pointer to member... */ /* Look for a non-type template parameter. */ @@ -19929,11 +19931,16 @@ cp_parser_template_argument (cp_parser* parser) probe = TREE_OPERAND (probe, 1); if (VAR_P (probe)) { - /* A variable without external linkage might still be a + /* A variable without valid linkage might still be a valid constant-expression, so no error is issued here if the external-linkage check fails. */ - if (!address_p && !DECL_EXTERNAL_LINKAGE_P (probe)) - cp_parser_simulate_error (parser); + if (!address_p) + { + linkage_kind linkage = decl_linkage (probe); + if (linkage != lk_external + && (cxx_dialect < cxx11 || linkage != lk_internal)) + cp_parser_simulate_error (parser); + } } else if (is_overloaded_fn (argument)) /* All overloaded functions are allowed; if the external diff --git a/gcc/testsuite/g++.dg/cpp0x/nontype6.C b/gcc/testsuite/g++.dg/cpp0x/nontype6.C new file mode 100644 index ..5543d1e8b6d2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nontype6.C @@ -0,0 +1,19 @@ +// PR c++/113266, PR c++/116911 +// { dg-do compile } + +template struct a {}; +static int guard1; +a b; // { dg-error "constant-expression|invalid" "" { target c++98_only } } + +namespace { + int guard2; +} +a c; // OK in C++98 because guard2 has external linkage + // OK since C++11 because we can refer to an internal linkage decl + +void nolinkage() { + static int guard3; + a d; // { dg-error "constant-expression|invalid" "" { target c++98_only } } + // { dg-error "constant expression|no linkage" "" { target { c++11 && c++14_down } } .-1 } + // OK since C++17 since we can now refer to no-linkage decls +}
[gcc r15-4060] c++: Return the underlying decl rather than the USING_DECL from update_binding [PR116913]
https://gcc.gnu.org/g:6a1e109158940ce3a2d1ceed3e1b614ea6c9a2de commit r15-4060-g6a1e109158940ce3a2d1ceed3e1b614ea6c9a2de Author: Nathaniel Shead Date: Fri Oct 4 10:46:57 2024 +1000 c++: Return the underlying decl rather than the USING_DECL from update_binding [PR116913] Users of pushdecl assume that the returned decl will be a possibly updated decl matching the one that was passed in. My r15-3910 change broke this since in some cases we would now return USING_DECLs; this patch fixes the situation. PR c++/116913 gcc/cp/ChangeLog: * name-lookup.cc (update_binding): Return the strip_using'd old decl rather than the binding. gcc/testsuite/ChangeLog: * g++.dg/lookup/using70.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/name-lookup.cc | 4 ++-- gcc/testsuite/g++.dg/lookup/using70.C | 13 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 4754ef5a5229..609bd6e8c9b5 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -3101,7 +3101,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, { if (same_type_p (TREE_TYPE (old), TREE_TYPE (decl))) /* Two type decls to the same type. Do nothing. */ - return old_bval; + return old; else goto conflict; } @@ -3114,7 +3114,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, /* The new one must be an alias at this point. */ gcc_assert (DECL_NAMESPACE_ALIAS (decl)); - return old_bval; + return old; } else if (TREE_CODE (old) == VAR_DECL) { diff --git a/gcc/testsuite/g++.dg/lookup/using70.C b/gcc/testsuite/g++.dg/lookup/using70.C new file mode 100644 index ..14838eea7ec3 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/using70.C @@ -0,0 +1,13 @@ +// PR c++/116913 +// { dg-do compile { target c++11 } } + +namespace ns { + struct c {}; + using d = int; +} + +using ns::c; +using ns::d; + +using c = ns::c; +using d = ns::d;
[gcc r15-3939] c++: Implement resolution for DR 36 [PR116160]
https://gcc.gnu.org/g:2196a20b82bdde2aeb099bcfd164fa29a698e837 commit r15-3939-g2196a20b82bdde2aeb099bcfd164fa29a698e837 Author: Nathaniel Shead Date: Fri Sep 20 00:47:12 2024 +1000 c++: Implement resolution for DR 36 [PR116160] This implements part of P1787 to no longer complain about redeclaring an entity via using-decl other than in a class scope. PR c++/116160 gcc/cp/ChangeLog: * name-lookup.cc (supplement_binding): Allow redeclaration via USING_DECL if not in class scope. (do_nonmember_using_decl): Remove function-scope exemption. (push_using_decl_bindings): Remove outdated comment. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/using-enum-3.C: No longer expect an error. * g++.dg/lookup/using53.C: Remove XFAIL. * g++.dg/cpp2a/using-enum-11.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/name-lookup.cc | 12 +++- gcc/testsuite/g++.dg/cpp0x/using-enum-3.C | 2 +- gcc/testsuite/g++.dg/cpp2a/using-enum-11.C | 9 + gcc/testsuite/g++.dg/lookup/using53.C | 2 +- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index a2f94e0f363e..4754ef5a5229 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -2874,6 +2874,12 @@ supplement_binding (cxx_binding *binding, tree decl) "%<-std=c++2c%> or %<-std=gnu++2c%>"); binding->value = name_lookup::ambiguous (decl, binding->value); } + else if (binding->scope->kind != sk_class + && TREE_CODE (decl) == USING_DECL + && decls_match (target_bval, target_decl)) +/* Since P1787 (DR 36) it is OK to redeclare entities via using-decl, + except in class scopes. */ +ok = false; else { if (!error_operand_p (bval)) @@ -5377,8 +5383,7 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, else if (value /* Ignore anticipated builtins. */ && !anticipated_builtin_p (value) - && (fn_scope_p - || !decls_match (lookup.value, strip_using_decl (value + && !decls_match (lookup.value, strip_using_decl (value))) { diagnose_name_conflict (lookup.value, value); failed = true; @@ -6651,9 +6656,6 @@ push_using_decl_bindings (name_lookup *lookup, tree name, tree value) type = binding->type; } - /* DR 36 questions why using-decls at function scope may not be - duplicates. Disallow it, as C++11 claimed and PR 20420 - implemented. */ if (lookup) do_nonmember_using_decl (*lookup, true, true, &value, &type); diff --git a/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C b/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C index 34f8bf4fa0bb..4638181c63ce 100644 --- a/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C +++ b/gcc/testsuite/g++.dg/cpp0x/using-enum-3.C @@ -9,7 +9,7 @@ void f () { enum e { a }; - using e::a; // { dg-error "redeclaration" } + using e::a; // { dg-bogus "redeclaration" "P1787" } // { dg-error "enum" "" { target { ! c++2a } } .-1 } } diff --git a/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C b/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C new file mode 100644 index ..ff99ed422d5f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/using-enum-11.C @@ -0,0 +1,9 @@ +// PR c++/116160 +// { dg-do compile { target c++20 } } + +enum class Blah { b }; +void foo() { + using Blah::b; + using Blah::b; + using enum Blah; +} diff --git a/gcc/testsuite/g++.dg/lookup/using53.C b/gcc/testsuite/g++.dg/lookup/using53.C index e91829e939a9..8279c73bfc4f 100644 --- a/gcc/testsuite/g++.dg/lookup/using53.C +++ b/gcc/testsuite/g++.dg/lookup/using53.C @@ -52,5 +52,5 @@ void f () { using N::i; - using N::i; // { dg-bogus "conflicts" "See P1787 (CWG36)" { xfail *-*-* } } + using N::i; // { dg-bogus "conflicts" "See P1787 (CWG36)" } }
[gcc r15-3938] c++: Don't strip USING_DECLs when updating local bindings [PR116748]
https://gcc.gnu.org/g:b9ac51a843f9dc807b00ab7f49f64968807a4ee8 commit r15-3938-gb9ac51a843f9dc807b00ab7f49f64968807a4ee8 Author: Nathaniel Shead Date: Fri Sep 20 00:05:04 2024 +1000 c++: Don't strip USING_DECLs when updating local bindings [PR116748] Currently update_binding strips USING_DECLs too eagerly, leading to ICEs in pop_local_decl as it can't find the decl it's popping in the binding list. Let's rather try to keep the original USING_DECL around. This also means that using59.C can point to the location of the using-decl rather than the underlying object directly; this is in the direction required to fix PR c++/106851 (though more work is needed to emit properly helpful diagnostics here). PR c++/116748 gcc/cp/ChangeLog: * name-lookup.cc (update_binding): Maintain USING_DECLs in the binding slots. gcc/testsuite/ChangeLog: * g++.dg/lookup/using59.C: Update location. * g++.dg/lookup/using69.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/name-lookup.cc | 12 +++- gcc/testsuite/g++.dg/lookup/using59.C | 4 ++-- gcc/testsuite/g++.dg/lookup/using69.C | 10 ++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index eb365b259d92..a2f94e0f363e 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -3005,6 +3005,8 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, if (old == error_mark_node) old = NULL_TREE; + + tree old_bval = old; old = strip_using_decl (old); if (DECL_IMPLICIT_TYPEDEF_P (decl)) @@ -3021,7 +3023,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, gcc_checking_assert (!to_type); hide_type = hiding; to_type = decl; - to_val = old; + to_val = old_bval; } else hide_value = hiding; @@ -3034,7 +3036,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, /* OLD is an implicit typedef. Move it to to_type. */ gcc_checking_assert (!to_type); - to_type = old; + to_type = old_bval; hide_type = hide_value; old = NULL_TREE; hide_value = false; @@ -3093,7 +3095,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, { if (same_type_p (TREE_TYPE (old), TREE_TYPE (decl))) /* Two type decls to the same type. Do nothing. */ - return old; + return old_bval; else goto conflict; } @@ -3106,7 +3108,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, /* The new one must be an alias at this point. */ gcc_assert (DECL_NAMESPACE_ALIAS (decl)); - return old; + return old_bval; } else if (TREE_CODE (old) == VAR_DECL) { @@ -3121,7 +3123,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot, else { conflict: - diagnose_name_conflict (decl, old); + diagnose_name_conflict (decl, old_bval); to_val = NULL_TREE; } } diff --git a/gcc/testsuite/g++.dg/lookup/using59.C b/gcc/testsuite/g++.dg/lookup/using59.C index 3c3a73c28d59..b7ec325d2348 100644 --- a/gcc/testsuite/g++.dg/lookup/using59.C +++ b/gcc/testsuite/g++.dg/lookup/using59.C @@ -1,10 +1,10 @@ namespace Y { - extern int I; // { dg-message "previous declaration" } + extern int I; } -using Y::I; +using Y::I; // { dg-message "previous declaration" } extern int I; // { dg-error "conflicts with a previous" } extern int J; diff --git a/gcc/testsuite/g++.dg/lookup/using69.C b/gcc/testsuite/g++.dg/lookup/using69.C new file mode 100644 index ..7d52b73b9ce0 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/using69.C @@ -0,0 +1,10 @@ +// PR c++/116748 + +namespace ns { + struct empty; +} + +void foo() { + using ns::empty; + int empty; +}
[gcc r15-3937] c++/modules: Propagate purview/import for templates in duplicate_decls [PR116803]
https://gcc.gnu.org/g:cf9efe5ec14fea3ad5746fbefb22544bb9424d9d commit r15-3937-gcf9efe5ec14fea3ad5746fbefb22544bb9424d9d Author: Nathaniel Shead Date: Fri Sep 27 18:58:27 2024 +1000 c++/modules: Propagate purview/import for templates in duplicate_decls [PR116803] We need to ensure that for a declaration in the module purview, that the resulting declaration has PURVIEW_P set and IMPORT_P cleared so that we understand it might be something requiring exporting. This is normally handled for a declaration by set_instantiating_module, but when this declaration is a redeclaration duplicate_decls needs to propagate this to olddecl. This patch only changes the logic for template declarations, because in the non-template case the whole contents of olddecl's DECL_LANG_SPECIFIC is replaced with newdecl's (which includes these flags), so there's nothing to do. PR c++/116803 gcc/cp/ChangeLog: * decl.cc (duplicate_decls): Propagate DECL_MODULE_PURVIEW_P and DECL_MODULE_IMPORT_P for template redeclarations. gcc/testsuite/ChangeLog: * g++.dg/modules/merge-18_a.H: New test. * g++.dg/modules/merge-18_b.H: New test. * g++.dg/modules/merge-18_c.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/decl.cc| 10 ++ gcc/testsuite/g++.dg/modules/merge-18_a.H | 8 gcc/testsuite/g++.dg/modules/merge-18_b.H | 13 + gcc/testsuite/g++.dg/modules/merge-18_c.C | 10 ++ 4 files changed, 41 insertions(+) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 6a7ba416cf8a..07fb9855cd20 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -2528,6 +2528,16 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) } } + /* Propagate purviewness and importingness as with +set_instantiating_module. */ + if (modules_p ()) + { + if (DECL_MODULE_PURVIEW_P (new_result)) + DECL_MODULE_PURVIEW_P (old_result) = true; + if (!DECL_MODULE_IMPORT_P (new_result)) + DECL_MODULE_IMPORT_P (old_result) = false; + } + /* If the new declaration is a definition, update the file and line information on the declaration, and also make the old declaration the same definition. */ diff --git a/gcc/testsuite/g++.dg/modules/merge-18_a.H b/gcc/testsuite/g++.dg/modules/merge-18_a.H new file mode 100644 index ..8d86ad980ba5 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/merge-18_a.H @@ -0,0 +1,8 @@ +// PR c++/116803 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +namespace ns { + template void foo(); + template extern const int bar; +} diff --git a/gcc/testsuite/g++.dg/modules/merge-18_b.H b/gcc/testsuite/g++.dg/modules/merge-18_b.H new file mode 100644 index ..2a762e2ac498 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/merge-18_b.H @@ -0,0 +1,13 @@ +// PR c++/116803 +// { dg-additional-options "-fmodule-header -fdump-lang-module" } +// { dg-module-cmi {} } + +import "merge-18_a.H"; + +namespace ns { + template void foo() {} + template const int bar = 123; +} + +// { dg-final { scan-lang-dump {Writing definition '::ns::template foo'} module } } +// { dg-final { scan-lang-dump {Writing definition '::ns::template bar'} module } } diff --git a/gcc/testsuite/g++.dg/modules/merge-18_c.C b/gcc/testsuite/g++.dg/modules/merge-18_c.C new file mode 100644 index ..b90d85f75024 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/merge-18_c.C @@ -0,0 +1,10 @@ +// PR c++/116803 +// { dg-module-do link } +// { dg-additional-options "-fmodules-ts" } + +import "merge-18_b.H"; + +int main() { + ns::foo(); + static_assert(ns::bar == 123); +}
[gcc r15-3913] c++/modules: Allow imported references in constant expressions
https://gcc.gnu.org/g:1a0b33ebc57ebcc9595b19050f5c36c1f9d39e3e commit r15-3913-g1a0b33ebc57ebcc9595b19050f5c36c1f9d39e3e Author: Nathaniel Shead Date: Thu Sep 12 20:06:39 2024 +1000 c++/modules: Allow imported references in constant expressions Currently the streaming code uses TREE_CONSTANT to determine whether an entity will have a definition that is interesting to stream out. This is not sufficient, however; we also need to write the definition of references, since although not TREE_CONSTANT they can still be usable in constant expressions. As such this patch uses the existing decl_maybe_constant_var function which correctly handles this case. gcc/cp/ChangeLog: * module.cc (has_definition): Use decl_maybe_constant_var instead of TREE_CONSTANT. gcc/testsuite/ChangeLog: * g++.dg/modules/cexpr-5_a.C: New test. * g++.dg/modules/cexpr-5_b.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/module.cc | 2 +- gcc/testsuite/g++.dg/modules/cexpr-5_a.C | 13 + gcc/testsuite/g++.dg/modules/cexpr-5_b.C | 9 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index f5df9e875d3a..65b37b4b5544 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -11829,7 +11829,7 @@ has_definition (tree decl) since there's no TU to emit them in otherwise. */ return true; - if (!TREE_CONSTANT (decl)) + if (!decl_maybe_constant_var_p (decl)) return false; return true; diff --git a/gcc/testsuite/g++.dg/modules/cexpr-5_a.C b/gcc/testsuite/g++.dg/modules/cexpr-5_a.C new file mode 100644 index ..3a9f00523f65 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cexpr-5_a.C @@ -0,0 +1,13 @@ +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi M } + +export module M; + +int x = 123; +void f() {} + +int& xr = x; +auto& fr = f; + +constexpr int& cxr = xr; +constexpr auto& cfr = fr; diff --git a/gcc/testsuite/g++.dg/modules/cexpr-5_b.C b/gcc/testsuite/g++.dg/modules/cexpr-5_b.C new file mode 100644 index ..4b1b901104bc --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cexpr-5_b.C @@ -0,0 +1,9 @@ +// { dg-additional-options "-fmodules-ts" } + +module M; + +constexpr auto& use_xr = xr; +constexpr auto& use_fr = fr; + +static_assert(&cxr == &use_xr); +static_assert(&cfr == &use_fr);
[gcc r15-3912] c++/modules: Fix linkage checks for exported using-decls
https://gcc.gnu.org/g:d0762e93ce1ed046e1dd9477ebe0ad941c298677 commit r15-3912-gd0762e93ce1ed046e1dd9477ebe0ad941c298677 Author: Nathaniel Shead Date: Wed Sep 4 01:18:19 2024 +1000 c++/modules: Fix linkage checks for exported using-decls 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 Reviewed-by: Jason Merrill Diff: --- 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(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index c0f89f98d87e..eb365b259d92 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 d468a36f5d
[gcc r15-3911] c++/modules: Use decl_linkage in maybe_record_mergeable_decl
https://gcc.gnu.org/g:ad08ef098a8c8bb9c148d0a32e91456fdf58ffc1 commit r15-3911-gad08ef098a8c8bb9c148d0a32e91456fdf58ffc1 Author: Nathaniel Shead Date: Wed Sep 4 02:42:58 2024 +1000 c++/modules: Use decl_linkage in maybe_record_mergeable_decl This avoids any possible inconsistencies (current or future) about whether a declaration is internal or not. gcc/cp/ChangeLog: * name-lookup.cc (maybe_record_mergeable_decl): Use decl_linkage instead of ad-hoc checks. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/name-lookup.cc | 9 + 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 50e169eca43e..c0f89f98d87e 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -3725,17 +3725,10 @@ maybe_record_mergeable_decl (tree *slot, tree name, tree decl) if (TREE_CODE (*slot) != BINDING_VECTOR) return; - if (!TREE_PUBLIC (CP_DECL_CONTEXT (decl))) -/* Member of internal namespace. */ + if (decl_linkage (decl) == lk_internal) return; tree not_tmpl = STRIP_TEMPLATE (decl); - if ((TREE_CODE (not_tmpl) == FUNCTION_DECL - || VAR_P (not_tmpl)) - && DECL_THIS_STATIC (not_tmpl)) -/* Internal linkage. */ -return; - bool is_attached = (DECL_LANG_SPECIFIC (not_tmpl) && DECL_MODULE_ATTACH_P (not_tmpl)); tree *gslot = get_fixed_binding_slot
[gcc r15-3910] c++: Update decl_linkage for C++11
https://gcc.gnu.org/g:af4471cb422a867f1877c7c08bb63fa75afe commit r15-3910-gaf4471cb422a867f1877c7c08bb63fa75afe Author: Nathaniel Shead Date: Mon Aug 19 16:38:41 2024 +1000 c++: Update decl_linkage for C++11 Currently modules code uses a variety of ad-hoc methods to attempt to determine whether an entity has internal linkage, which leads to inconsistencies and some correctness issues as different edge cases are neglected. While investigating this I discovered 'decl_linkage', but it doesn't seem to have been updated to account for the C++11 clarification that all entities declared in an anonymous namespace are internal. I'm not convinced that even in C++98 it was intended that e.g. types in anonymous namespaces should be external, but some tests in the testsuite rely on this, so for compatibility I restricted those modifications to C++11 and later. This should have relatively minimal impact as not much seems to actually rely on decl_linkage, but does change the mangling of symbols in anonymous namespaces slightly. Previously, we had namespace { int x; // mangled as '_ZN12_GLOBAL__N_11xE' static int y; // mangled as '_ZN12_GLOBAL__N_1L1yE' } but with this patch the x is now mangled like y (with the extra 'L'). For contrast, Clang currently mangles neither x nor y with the 'L'. Since this only affects internal-linkage entities I don't believe this should break ABI in any observable fashion. gcc/cp/ChangeLog: * name-lookup.cc (do_namespace_alias): Propagate TREE_PUBLIC for namespace aliases. * tree.cc (decl_linkage): Update rules for C++11. gcc/testsuite/ChangeLog: * g++.dg/modules/mod-sym-4.C: Update test to account for non-static internal-linkage variables new mangling. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/name-lookup.cc| 1 + gcc/cp/tree.cc | 92 gcc/testsuite/g++.dg/modules/mod-sym-4.C | 4 +- 3 files changed, 60 insertions(+), 37 deletions(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index c7a693e02d59..50e169eca43e 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -6610,6 +6610,7 @@ do_namespace_alias (tree alias, tree name_space) DECL_NAMESPACE_ALIAS (alias) = name_space; DECL_EXTERNAL (alias) = 1; DECL_CONTEXT (alias) = FROB_CONTEXT (current_scope ()); + TREE_PUBLIC (alias) = TREE_PUBLIC (DECL_CONTEXT (alias)); set_originating_module (alias); pushdecl (alias); diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index e8d8b2ab6f70..0a7a56cc6e2e 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -5841,7 +5841,7 @@ char_type_p (tree type) || same_type_p (type, wchar_type_node)); } -/* Returns the kind of linkage associated with the indicated DECL. Th +/* Returns the kind of linkage associated with the indicated DECL. The value returned is as specified by the language standard; it is independent of implementation details regarding template instantiation, etc. For example, it is possible that a declaration @@ -5858,53 +5858,75 @@ decl_linkage (tree decl) linkage first, and then transform that into a concrete implementation. */ - /* Things that don't have names have no linkage. */ - if (!DECL_NAME (decl)) -return lk_none; + /* An explicit type alias has no linkage. */ + if (TREE_CODE (decl) == TYPE_DECL + && !DECL_IMPLICIT_TYPEDEF_P (decl) + && !DECL_SELF_REFERENCE_P (decl)) +{ + /* But this could be a typedef name for linkage purposes, in which +case we're interested in the linkage of the main decl. */ + if (decl == TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (decl + decl = TYPE_MAIN_DECL (TREE_TYPE (decl)); + else + return lk_none; +} - /* Fields have no linkage. */ - if (TREE_CODE (decl) == FIELD_DECL) + /* Namespace-scope entities with no name usually have no linkage. */ + if (NAMESPACE_SCOPE_P (decl) + && (!DECL_NAME (decl) || IDENTIFIER_ANON_P (DECL_NAME (decl +{ + if (TREE_CODE (decl) == TYPE_DECL && !TYPE_ANON_P (TREE_TYPE (decl))) + /* This entity has a typedef name for linkage purposes. */; + else if (TREE_CODE (decl) == NAMESPACE_DECL && cxx_dialect >= cxx11) + /* An anonymous namespace has internal linkage since C++11. */ + return lk_internal; + else + return lk_none; +} + + /* Fields and parameters have no linkage. */ + if (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == PARM_DECL) return lk_none; - /* Things in local scope do not have linkage. */ + /* Things in block scope do not have linkage. */ if (decl_function_context (decl)) return lk_none; + /* Things in class scope have the linkage
[gcc r15-3906] libgcc, libstdc++: Make declarations no longer TU-local [PR115126]
https://gcc.gnu.org/g:6a4d1c374eed177eceb12a50f3b25bd20f8b347a commit r15-3906-g6a4d1c374eed177eceb12a50f3b25bd20f8b347a Author: Nathaniel Shead Date: Tue Sep 24 23:53:59 2024 +1000 libgcc, libstdc++: Make declarations no longer TU-local [PR115126] In C++20, modules streaming check for exposures of TU-local entities. In general exposing internal linkage functions in a header is liable to cause ODR violations in C++, and this is now detected in a module context. This patch goes through and removes 'static' from many declarations exposed through libstdc++ to prevent code like the following from failing: export module M; extern "C++" { #include } Since gthreads is used from C as well, we need to choose whether to use 'inline' or 'static inline' depending on whether we're compiling for C or C++ (since the semantics of 'inline' are different between the languages). Additionally we need to remove static global variables, so we migrate these to function-local statics to avoid the ODR issues. There doesn't seem to be a good workaround for weakrefs, so I've left them as-is and will work around it in the modules streaming code to consider them as not TU-local. The same issue occurs in the objective-C specific parts of gthreads, but I'm not familiar with the surrounding context and we don't currently test modules with Objective C++ anyway so I've left it as-is. PR libstdc++/115126 libgcc/ChangeLog: * gthr-posix.h (__GTHREAD_ALWAYS_INLINE): New macro. (__GTHREAD_INLINE): New macro. (__gthread_active): Convert from variable to (hidden) function. (__gthread_active_p): Mark as __GTHREAD_INLINE instead of static; make visibility("hidden") when it has a static local variable. (__gthread_trigger): Mark as __GTHREAD_INLINE instead of static. (__gthread_create): Likewise. (__gthread_join): Likewise. (__gthread_detach): Likewise. (__gthread_equal): Likewise. (__gthread_self): Likewise. (__gthread_yield): Likewise. (__gthread_once): Likewise. (__gthread_key_create): Likewise. (__gthread_key_delete): Likewise. (__gthread_getspecific): Likewise. (__gthread_setspecific): Likewise. (__gthread_mutex_init_function): Likewise. (__gthread_mutex_destroy): Likewise. (__gthread_mutex_lock): Likewise. (__gthread_mutex_trylock): Likewise. (__gthread_mutex_timedlock): Likewise. (__gthread_mutex_unlock): Likewise. (__gthread_recursive_mutex_init_function): Likewise. (__gthread_recursive_mutex_lock): Likewise. (__gthread_recursive_mutex_trylock): Likewise. (__gthread_recursive_mutex_timedlock): Likewise. (__gthread_recursive_mutex_unlock): Likewise. (__gthread_recursive_mutex_destroy): Likewise. (__gthread_cond_init_function): Likewise. (__gthread_cond_broadcast): Likewise. (__gthread_cond_signal): Likewise. (__gthread_cond_wait): Likewise. (__gthread_cond_timedwait): Likewise. (__gthread_cond_wait_recursive): Likewise. (__gthread_cond_destroy): Likewise. (__gthread_rwlock_rdlock): Likewise. (__gthread_rwlock_tryrdlock): Likewise. (__gthread_rwlock_wrlock): Likewise. (__gthread_rwlock_trywrlock): Likewise. (__gthread_rwlock_unlock): Likewise. * gthr-single.h: (__GTHREAD_ALWAYS_INLINE): New macro. (__GTHREAD_INLINE): New macro. (__gthread_active_p): Mark as __GTHREAD_INLINE instead of static. (__gthread_once): Likewise. (__gthread_key_create): Likewise. (__gthread_key_delete): Likewise. (__gthread_getspecific): Likewise. (__gthread_setspecific): Likewise. (__gthread_mutex_destroy): Likewise. (__gthread_mutex_lock): Likewise. (__gthread_mutex_trylock): Likewise. (__gthread_mutex_unlock): Likewise. (__gthread_recursive_mutex_lock): Likewise. (__gthread_recursive_mutex_trylock): Likewise. (__gthread_recursive_mutex_unlock): Likewise. (__gthread_recursive_mutex_destroy): Likewise. libstdc++-v3/ChangeLog: * include/bits/shared_ptr.h (std::__is_shared_ptr): Remove unnecessary 'static'. * include/bits/unique_ptr.h (std::__is_unique_ptr): Likewise. * include/std/future (std::__create_task_state): Likewise. * include/std/shared_mutex (_GLIBCXX_GTRHW): Likewise. (__glibcxx_rwlock_init): Likewise. (__glibcxx_r
[gcc r15-3884] testsuite: Fix testcase g++.dg/modules/indirect-1_b.C [PR116846]
https://gcc.gnu.org/g:064d5c67d7ad2be446c19e84f0cd993ecab784c3 commit r15-3884-g064d5c67d7ad2be446c19e84f0cd993ecab784c3 Author: Nathaniel Shead Date: Thu Sep 26 11:12:02 2024 +1000 testsuite: Fix testcase g++.dg/modules/indirect-1_b.C [PR116846] r15-3878 exposed a mistake in the testcase, probably from an older version of the dumping logic. Apart from the slightly different syntax for the dump line, also check for importing the type_decl rather than the const_decl (we need the type anyway and importing the type also brings along the enumerators so it would be unnecessary to seed an import for them as well). PR c++/116846 gcc/testsuite/ChangeLog: * g++.dg/modules/indirect-1_b.C: Fix testcase. Signed-off-by: Nathaniel Shead Diff: --- gcc/testsuite/g++.dg/modules/indirect-1_b.C | 7 ++- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gcc/testsuite/g++.dg/modules/indirect-1_b.C b/gcc/testsuite/g++.dg/modules/indirect-1_b.C index dee8a00ef15e..e5abf66c7b3d 100644 --- a/gcc/testsuite/g++.dg/modules/indirect-1_b.C +++ b/gcc/testsuite/g++.dg/modules/indirect-1_b.C @@ -48,8 +48,5 @@ namespace bar // { dg-final { scan-lang-dump {Lazily binding '::foo::Scoped'@'foo' section:} module } } // { dg-final { scan-lang-dump-not {Lazily binding '::foo::Scoped@foo:.::[ABCD]'@'foo' section:} module } } -// XFAIL is for PR116846 -// { dg-final { scan-lang-dump {Wrote named import:-[0-9]* const_decl:'::foo::Plain@\(foo\)::C'@foo} module { xfail *-*-* } } } -// { dg-final { scan-lang-dump {Wrote named import:-[0-9]* const_decl:'::foo::Plain@\(foo\)::B'@foo} module { xfail *-*-* } } } -// { dg-final { scan-lang-dump {Wrote named import:-[0-9]* const_decl:'::foo::Scoped@\(foo\)::C'@foo} module { xfail *-*-* } } } -// { dg-final { scan-lang-dump {Wrote named import:-[0-9]* const_decl:'::foo::Scoped@\(foo\)::B'@foo} module { xfail *-*-* } } } +// { dg-final { scan-lang-dump-times {Wrote import:-[0-9]* type_decl:'::foo::Plain@foo:.'@foo} 2 module } } +// { dg-final { scan-lang-dump-times {Wrote import:-[0-9]* type_decl:'::foo::Scoped@foo:.'@foo} 2 module } }
[gcc r15-3592] c++/modules: Really always track partial specialisations [PR116496]
https://gcc.gnu.org/g:ba393bf8879e5cf1f917bd88246d6b80ac081052 commit r15-3592-gba393bf8879e5cf1f917bd88246d6b80ac081052 Author: Nathaniel Shead Date: Wed Sep 11 22:41:21 2024 +1000 c++/modules: Really always track partial specialisations [PR116496] My last fix for this issue (PR c++/114947, r15-810) didn't go far enough; I had assumed that the issue where we lost track of partial specialisations we would need to walk again later was limited to partitions (where we always re-walk all specialisations), but the linked PR is the same cause but for header units, and it is possible to construct test cases exposing the same bug just for normal modules. As such this patch just unconditionally ensures that whenever we modify DECL_TEMPLATE_SPECIALIZATIONS we also track any partial specialisations that might have added. Also clean up a couple of comments and assertions to make expected state more obvious when processing these specs. PR c++/116496 gcc/cp/ChangeLog: * module.cc (trees_in::decl_value): Don't call set_defining_module_for_partial_spec here. (depset::hash::add_partial_entities): Clarity assertions. * pt.cc (add_mergeable_specialization): Always call set_defining_module_for_partial_spec when adding a partial spec. gcc/testsuite/ChangeLog: * g++.dg/modules/partial-5_a.C: New test. * g++.dg/modules/partial-5_b.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 25 - gcc/cp/pt.cc | 1 + gcc/testsuite/g++.dg/modules/partial-5_a.C | 9 + gcc/testsuite/g++.dg/modules/partial-5_b.C | 9 + 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index dc0e9e5520f9..f5df9e875d3a 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -8434,11 +8434,6 @@ trees_in::decl_value () add_mergeable_specialization (!is_type, &spec, decl, spec_flags); } - /* When making a CMI from a partition we're going to need to walk partial -specializations again, so make sure they're tracked. */ - if (state->is_partition () && (spec_flags & 2)) - set_defining_module_for_partial_spec (inner); - if (NAMESPACE_SCOPE_P (decl) && (mk == MK_named || mk == MK_unique || mk == MK_enum || mk == MK_friend_spec) @@ -13356,16 +13351,20 @@ depset::hash::add_partial_entities (vec *partial_classes) specialization. */ gcc_checking_assert (dep->get_entity_kind () == depset::EK_PARTIAL); + + /* Only emit GM entities if reached. */ + if (!DECL_LANG_SPECIFIC (inner) + || !DECL_MODULE_PURVIEW_P (inner)) + dep->set_flag_bit (); } else - /* It was an explicit specialization, not a partial one. */ - gcc_checking_assert (dep->get_entity_kind () -== depset::EK_SPECIALIZATION); - - /* Only emit GM entities if reached. */ - if (!DECL_LANG_SPECIFIC (inner) - || !DECL_MODULE_PURVIEW_P (inner)) - dep->set_flag_bit (); + { + /* It was an explicit specialization, not a partial one. +We should have already added this. */ + gcc_checking_assert (dep->get_entity_kind () + == depset::EK_SPECIALIZATION); + gcc_checking_assert (dep->is_special ()); + } } } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 310e5dfff033..cb3164d49147 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -31684,6 +31684,7 @@ add_mergeable_specialization (bool decl_p, spec_entry *elt, tree decl, DECL_TEMPLATE_SPECIALIZATIONS (elt->tmpl)); TREE_TYPE (cons) = decl_p ? TREE_TYPE (elt->spec) : elt->spec; DECL_TEMPLATE_SPECIALIZATIONS (elt->tmpl) = cons; + set_defining_module_for_partial_spec (STRIP_TEMPLATE (decl)); } } diff --git a/gcc/testsuite/g++.dg/modules/partial-5_a.C b/gcc/testsuite/g++.dg/modules/partial-5_a.C new file mode 100644 index ..768e6995f0ff --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-5_a.C @@ -0,0 +1,9 @@ +// PR c++/116496 +// { dg-additional-options "-fmodules-ts -std=c++20 -Wno-global-module" } +// { dg-module-cmi A } + +module; +template struct S {}; +export module A; +template struct S {}; +template requires false struct S {}; diff --git a/gcc/testsuite/g++.dg/modules/partial-5_b.C b/gcc/testsuite/g++.dg/modules/partial-5_b.C new file mode 100644 index ..95401fe8b562 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/partial-5_b.C @@ -0,0 +1,9 @@ +// PR c++/116496 +// { dg-additional-options "-fmodules-ts -std=c++20 -Wno-global-module" } +// { dg-module-cmi B } + +module; +template struct S {
[gcc r15-3482] c++: Add missing auto_diagnostic_groups
https://gcc.gnu.org/g:cb76fcf5ebf0817e6f1b7c019071362f7a5f3ae0 commit r15-3482-gcb76fcf5ebf0817e6f1b7c019071362f7a5f3ae0 Author: Nathaniel Shead Date: Wed Aug 7 19:20:19 2024 +1000 c++: Add missing auto_diagnostic_groups This patch goes through all .cc files in gcc/cp and adds in any auto_diagnostic_groups that seem to be missing by looking for any 'inform' calls that aren't grouped with their respective error/warning. Now with SARIF output support this seems to be a bit more important. The patch isn't complete; I've tried to also track helper functions used for diagnostics to group them, but some may have been missed. Additionally there are a few functions that are definitely missing groupings but I wasn't able to see an obvious way to add them without potentially grouping together unrelated messages. This list includes: - lazy_load_{binding,pendings} "during load of {binding,pendings} for" - cp_finish_decomp "in initialization of structured binding variable" - require_deduced_type "using __builtin_source_location" - convert_nontype_argument "in template argument for type %qT" - coerce_template_params "so any instantiation with a non-empty parameter pack" - tsubst_default_argument "when instantiating default argument" - invalid_nontype_parm_type_p "invalid template non-type parameter" gcc/cp/ChangeLog: * class.cc (add_method): Add missing auto_diagnostic_group. (handle_using_decl): Likewise. (maybe_warn_about_overly_private_class): Likewise. (check_field_decl): Likewise. (check_field_decls): Likewise. (resolve_address_of_overloaded_function): Likewise. (note_name_declared_in_class): Likewise. * constraint.cc (associate_classtype_constraints): Likewise. (diagnose_trait_expr): Clean up whitespace. * coroutines.cc (find_coro_traits_template_decl): Add missing auto_diagnostic_group. (coro_promise_type_found_p): Likewise. (coro_diagnose_throwing_fn): Likewise. * cvt.cc (build_expr_type_conversion): Likewise. * decl.cc (validate_constexpr_redeclaration): Likewise. (duplicate_function_template_decls): Likewise. (duplicate_decls): Likewise. (lookup_label_1): Likewise. (check_previous_goto_1): Likewise. (check_goto_1): Likewise. (make_typename_type): Likewise. (make_unbound_class_template): Likewise. (check_tag_decl): Likewise. (start_decl): Likewise. (maybe_commonize_var): Likewise. (check_for_uninitialized_const_var): Likewise. (reshape_init_class): Likewise. (check_initializer): Likewise. (cp_finish_decl): Likewise. (find_decomp_class_base): Likewise. (cp_finish_decomp): Likewise. (expand_static_init): Likewise. (grokfndecl): Likewise. (grokdeclarator): Likewise. (check_elaborated_type_specifier): Likewise. (lookup_and_check_tag): Likewise. (xref_tag): Likewise. (cxx_simulate_enum_decl): Likewise. (finish_function): Likewise. * decl2.cc (check_classfn): Likewise. (record_mangling): Likewise. (mark_used): Likewise. * error.cc (qualified_name_lookup_error): Likewise. * except.cc (build_throw): Likewise. * init.cc (get_nsdmi): Likewise. (diagnose_uninitialized_cst_or_ref_member_1): Likewise. (warn_placement_new_too_small): Likewise. (build_new_1): Likewise. (build_vec_delete_1): Likewise. (build_delete): Likewise. * lambda.cc (add_capture): Likewise. (add_default_capture): Likewise. * lex.cc (unqualified_fn_lookup_error): Likewise. * method.cc (synthesize_method): Likewise. (defaulted_late_check): Likewise. * module.cc (trees_in::is_matching_decl): Likewise. (trees_in::read_enum_def): Likewise. (module_state::check_not_purview): Likewise. (module_state::deferred_macro): Likewise. (module_state::read_config): Likewise. (module_state::check_read): Likewise. (declare_module): Likewise. (init_modules): Likewise. * name-lookup.cc (diagnose_name_conflict): Likewise. (lookup_using_decl): Likewise. (set_decl_namespace): Likewise. (finish_using_directive): Likewise. (push_namespace): Likewise. (add_imported_namespace): Likewise. * parser.cc (cp_parser_check_for_definition_in_return_type): Likewise. (cp_parser_userdef_numeric_literal): Likewise. (cp_parser_nested_na
[gcc r15-3207] c++/modules: Fix include translation for already-seen headers [PR99243]
https://gcc.gnu.org/g:215ff991a8681f968823b913e1c79a32d339c097 commit r15-3207-g215ff991a8681f968823b913e1c79a32d339c097 Author: Nathaniel Shead Date: Thu Aug 22 20:41:54 2024 +1000 c++/modules: Fix include translation for already-seen headers [PR99243] After importing a header unit we learn about and setup any header modules that we transitively depend on. However, this causes 'set_filename' to fail an assertion if we then come across this header as an #include and attempt to translate it into a module. We still need to do this translation so that libcpp learns that this is a header unit, but we shouldn't error just because we've already seen it as an import. Instead this patch merely checks and errors to handle the case of a broken mapper implementation which supplies a different CMI path from the one we already got. As a drive-by fix, also make failing to find the CMI for a module be a fatal error: any further errors in the TU are unlikely to be helpful. PR c++/99243 gcc/cp/ChangeLog: * module.cc (module_state::set_filename): Handle repeated calls to 'set_filename' as long as the CMI path matches. (maybe_translate_include): Adjust comment. gcc/testsuite/ChangeLog: * g++.dg/modules/map-2.C: Prune additional fatal error message. * g++.dg/modules/inc-xlate-4_a.H: New test. * g++.dg/modules/inc-xlate-4_b.H: New test. * g++.dg/modules/inc-xlate-4_c.H: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 18 +- gcc/testsuite/g++.dg/modules/inc-xlate-4_a.H | 5 + gcc/testsuite/g++.dg/modules/inc-xlate-4_b.H | 5 + gcc/testsuite/g++.dg/modules/inc-xlate-4_c.H | 6 ++ gcc/testsuite/g++.dg/modules/map-2.C | 3 ++- 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 4cd7e1c284b8..95c2405fcd47 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -20086,14 +20086,21 @@ canonicalize_header_name (cpp_reader *reader, location_t loc, bool unquoted, void module_state::set_filename (const Cody::Packet &packet) { - gcc_checking_assert (!filename); if (packet.GetCode () == Cody::Client::PC_PATHNAME) -filename = xstrdup (packet.GetString ().c_str ()); +{ + /* If we've seen this import before we better have the same CMI. */ + const std::string &path = packet.GetString (); + if (!filename) + filename = xstrdup (packet.GetString ().c_str ()); + else if (filename != path) + error_at (loc, "mismatching compiled module interface: " + "had %qs, got %qs", filename, path.c_str ()); +} else { gcc_checking_assert (packet.GetCode () == Cody::Client::PC_ERROR); - error_at (loc, "unknown Compiled Module Interface: %s", - packet.GetString ().c_str ()); + fatal_error (loc, "unknown compiled module interface: %s", + packet.GetString ().c_str ()); } } @@ -20127,7 +20134,8 @@ maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc, translate = packet.GetInteger () ? xlate_kind::text : xlate_kind::unknown; else if (packet.GetCode () == Cody::Client::PC_PATHNAME) { - /* Record the CMI name for when we do the import. */ + /* Record the CMI name for when we do the import. +We may already know about this import, but libcpp doesn't yet. */ module_state *import = get_module (build_string (len, path)); import->set_filename (packet); translate = xlate_kind::import; diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-4_a.H b/gcc/testsuite/g++.dg/modules/inc-xlate-4_a.H new file mode 100644 index ..8afb49d01a5a --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/inc-xlate-4_a.H @@ -0,0 +1,5 @@ +// PR c++/99243 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +void foo(); diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-4_b.H b/gcc/testsuite/g++.dg/modules/inc-xlate-4_b.H new file mode 100644 index ..0e67566f5716 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/inc-xlate-4_b.H @@ -0,0 +1,5 @@ +// PR c++/99243 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +#include "inc-xlate-4_a.H" diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-4_c.H b/gcc/testsuite/g++.dg/modules/inc-xlate-4_c.H new file mode 100644 index ..c2fa647bce84 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/inc-xlate-4_c.H @@ -0,0 +1,6 @@ +// PR c++/99243 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +#include "inc-xlate-4_b.H" +#include "inc-xlate-4_a.H" diff --git a/gcc/testsuite/g++.dg/modules/map-2.C b/gcc/testsuite/g++.dg/modules/map-2.C index 94d3f7a1a41d..3f95aea36705 100644 --- a/gcc/testsuite/g++.dg/modul
[gcc r15-3206] c++/modules: Clean up include translation [PR110980]
https://gcc.gnu.org/g:98608342932e8951a4c8db3e9df79f9187424d53 commit r15-3206-g98608342932e8951a4c8db3e9df79f9187424d53 Author: Nathaniel Shead Date: Thu Aug 22 21:04:11 2024 +1000 c++/modules: Clean up include translation [PR110980] Currently the handling of include translation is confusing to read, using a tri-state integer without much clarity on what different states mean. This patch cleans this up to use explicit enumerators indicating the different possible states instead, and fixes a bug where the option '-flang-info-include-translate' ended being accidentally unusable. PR c++/110980 gcc/cp/ChangeLog: * module.cc (maybe_translate_include): Clean up. gcc/testsuite/ChangeLog: * g++.dg/modules/inc-xlate-2_a.H: New test. * g++.dg/modules/inc-xlate-2_b.H: New test. * g++.dg/modules/inc-xlate-3.h: New test. * g++.dg/modules/inc-xlate-3_a.H: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 23 ++- gcc/testsuite/g++.dg/modules/inc-xlate-2_a.H | 3 +++ gcc/testsuite/g++.dg/modules/inc-xlate-2_b.H | 5 + gcc/testsuite/g++.dg/modules/inc-xlate-3.h | 2 ++ gcc/testsuite/g++.dg/modules/inc-xlate-3_a.H | 5 + 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 07477d33955c..4cd7e1c284b8 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -20118,15 +20118,19 @@ maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc, size_t len = strlen (path); path = canonicalize_header_name (NULL, loc, true, path, len); auto packet = mapper->IncludeTranslate (path, Cody::Flags::None, len); - int xlate = false; + + enum class xlate_kind { +unknown, text, import, + } translate = xlate_kind::unknown; + if (packet.GetCode () == Cody::Client::PC_BOOL) -xlate = -int (packet.GetInteger ()); +translate = packet.GetInteger () ? xlate_kind::text : xlate_kind::unknown; else if (packet.GetCode () == Cody::Client::PC_PATHNAME) { /* Record the CMI name for when we do the import. */ module_state *import = get_module (build_string (len, path)); import->set_filename (packet); - xlate = +1; + translate = xlate_kind::import; } else { @@ -20136,9 +20140,9 @@ maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc, } bool note = false; - if (note_include_translate_yes && xlate > 1) + if (note_include_translate_yes && translate == xlate_kind::import) note = true; - else if (note_include_translate_no && xlate == 0) + else if (note_include_translate_no && translate == xlate_kind::unknown) note = true; else if (note_includes) /* We do not expect the note_includes vector to be large, so O(N) @@ -20148,15 +20152,16 @@ maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc, note = true; if (note) -inform (loc, xlate +inform (loc, translate == xlate_kind::import ? G_("include %qs translated to import") - : G_("include %qs processed textually") , path); + : G_("include %qs processed textually"), path); - dump () && dump (xlate ? "Translating include to import" + dump () && dump (translate == xlate_kind::import + ? "Translating include to import" : "Keeping include as include"); dump.pop (0); - if (!(xlate > 0)) + if (translate != xlate_kind::import) return nullptr; /* Create the translation text. */ diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-2_a.H b/gcc/testsuite/g++.dg/modules/inc-xlate-2_a.H new file mode 100644 index ..d6a4866a6766 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/inc-xlate-2_a.H @@ -0,0 +1,3 @@ +// PR c++/110980 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-2_b.H b/gcc/testsuite/g++.dg/modules/inc-xlate-2_b.H new file mode 100644 index ..f04dd430feca --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/inc-xlate-2_b.H @@ -0,0 +1,5 @@ +// PR c++/110980 +// { dg-additional-options "-fmodule-header -flang-info-include-translate" } +// { dg-module-cmi {} } + +#include "inc-xlate-2_a.H" // { dg-message "translated to import" } diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-3.h b/gcc/testsuite/g++.dg/modules/inc-xlate-3.h new file mode 100644 index ..c0584bada0c2 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/inc-xlate-3.h @@ -0,0 +1,2 @@ +// PR c++/110980 +// Just an empty file to be an include target. diff --git a/gcc/testsuite/g++.dg/modules/inc-xlate-3_a.H b/gcc/testsuite/g++.dg/modules/inc-xlate-3_a.H new file mode 100644 index ..47772089149a --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/inc-xlate-3_a.H @@ -0,0 +1,5 @
[gcc r15-3053] c++/modules: Remove unnecessary errors when not writing compiled module
https://gcc.gnu.org/g:e668771ff0dcc3c72937768e5c37b6f287b97799 commit r15-3053-ge668771ff0dcc3c72937768e5c37b6f287b97799 Author: Nathaniel Shead Date: Sun Aug 18 21:35:23 2024 +1000 c++/modules: Remove unnecessary errors when not writing compiled module It was pointed out to me that the current error referencing an internal linkage entity reads almost like an ICE message, with the message finishing with the unhelpful: m.cpp:1:8: error: failed to write compiled module: Bad file data 1 | export module M; |^~ Similarly, whenever we decide not to emit a module CMI due to other errors we currently emit the following message: m.cpp:1:8: warning: not writing module ‘M’ due to errors 1 | export module M; |^~ Neither of these messages really add anything useful; users already understand that when an error is reported then the normal outputs will not be created, so these messages are just noise. There is one case we still need this latter message, however; when an error in a template has been silenced with '-Wno-template-body' we still don't want to write a module CMI, so emit an error now instead. This patch also removes a number of dg-prune-output directives in the testsuite that are no longer needed with this change. gcc/cp/ChangeLog: * module.cc (module_state::write_begin): Return a boolean to indicate errors rather than just doing set_error(). (finish_module_processing): Prevent emission of unnecessary errors; only indicate module writing occurred if write_begin succeeds. gcc/testsuite/ChangeLog: * g++.dg/modules/export-1.C: Remove message. * g++.dg/modules/internal-1.C: Remove message. * g++.dg/modules/ambig-2_b.C: Remove unnecessary pruning. * g++.dg/modules/atom-decl-2.C: Likewise. * g++.dg/modules/atom-pragma-3.C: Likewise. * g++.dg/modules/atom-preamble-2_f.C: Likewise. * g++.dg/modules/block-decl-2.C: Likewise. * g++.dg/modules/dir-only-4.C: Likewise. * g++.dg/modules/enum-12.C: Likewise. * g++.dg/modules/exp-xlate-1_b.C: Likewise. * g++.dg/modules/export-3.C: Likewise. * g++.dg/modules/friend-3.C: Likewise. * g++.dg/modules/friend-5_b.C: Likewise. * g++.dg/modules/inc-xlate-1_e.C: Likewise. * g++.dg/modules/linkage-2.C: Likewise. * g++.dg/modules/local-extern-1.C: Likewise. * g++.dg/modules/main-1.C: Likewise. * g++.dg/modules/map-2.C: Likewise. * g++.dg/modules/mod-decl-1.C: Likewise. * g++.dg/modules/mod-decl-3.C: Likewise. * g++.dg/modules/pr99174.H: Likewise. * g++.dg/modules/pr99468.H: Likewise. * g++.dg/modules/token-1.C: Likewise. * g++.dg/modules/token-3.C: Likewise. * g++.dg/modules/token-4.C: Likewise. * g++.dg/modules/token-5.C: Likewise. * g++.dg/modules/using-10.C: Likewise. * g++.dg/modules/using-12.C: Likewise. * g++.dg/modules/using-3.C: Likewise. * g++.dg/modules/using-9.C: Likewise. * g++.dg/modules/using-enum-2.C: Likewise. * g++.dg/modules/permissive-error-1.C: New test. * g++.dg/modules/permissive-error-2.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/module.cc | 42 ++- gcc/testsuite/g++.dg/modules/ambig-2_b.C | 2 -- gcc/testsuite/g++.dg/modules/atom-decl-2.C| 2 -- gcc/testsuite/g++.dg/modules/atom-pragma-3.C | 2 -- gcc/testsuite/g++.dg/modules/atom-preamble-2_f.C | 1 - gcc/testsuite/g++.dg/modules/block-decl-2.C | 2 -- gcc/testsuite/g++.dg/modules/dir-only-4.C | 1 - gcc/testsuite/g++.dg/modules/enum-12.C| 2 -- gcc/testsuite/g++.dg/modules/exp-xlate-1_b.C | 1 - gcc/testsuite/g++.dg/modules/export-1.C | 2 -- gcc/testsuite/g++.dg/modules/export-3.C | 2 -- gcc/testsuite/g++.dg/modules/friend-3.C | 1 - gcc/testsuite/g++.dg/modules/friend-5_b.C | 1 - gcc/testsuite/g++.dg/modules/inc-xlate-1_e.C | 2 -- gcc/testsuite/g++.dg/modules/internal-1.C | 2 +- gcc/testsuite/g++.dg/modules/linkage-2.C | 2 -- gcc/testsuite/g++.dg/modules/local-extern-1.C | 3 -- gcc/testsuite/g++.dg/modules/main-1.C | 1 - gcc/testsuite/g++.dg/modules/map-2.C | 2 -- gcc/testsuite/g++.dg/modules/mod-decl-1.C | 2 -- gcc/testsuite/g++.dg/modules/mod-decl-3.C | 2 -- gcc/testsuite/g++.dg/modules/permissive-error-1.C | 10 ++ gcc/testsuite/g++.dg/modules/permissive-error-2.C | 11 +
[gcc r15-3033] c++/modules: Disable streaming definitions of non-vague-linkage GMF decls [PR115020]
https://gcc.gnu.org/g:c1a53d9dcf9ebf0a6b4528a8c3eae48a583f272c commit r15-3033-gc1a53d9dcf9ebf0a6b4528a8c3eae48a583f272c Author: Nathaniel Shead Date: Sat Aug 17 22:37:30 2024 +1000 c++/modules: Disable streaming definitions of non-vague-linkage GMF decls [PR115020] The error in the linked PR is caused because 'DECL_THIS_STATIC' is true for the static member function, causing the streaming code to assume that this is an internal linkage GM entity that needs to be explicitly streamed, which then on read-in gets marked as a vague linkage function (despite being non-inline) causing import_export_decl to complain. However, I don't see any reason why we should care about this: definitions in the GMF should just be emitted as per usual regardless of whether they're internal-linkage or not. Actually the only thing we care about here are header modules, since they have no TU to write definitions into. As such this patch removes these conditions from 'has_definition' and updates some comments to clarify. PR c++/115020 gcc/cp/ChangeLog: * module.cc (has_definition): Only force writing definitions for header_module_p. gcc/testsuite/ChangeLog: * g++.dg/modules/pr115020_a.C: New test. * g++.dg/modules/pr115020_b.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/module.cc | 14 +++--- gcc/testsuite/g++.dg/modules/pr115020_a.C | 10 ++ gcc/testsuite/g++.dg/modules/pr115020_b.C | 10 ++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index ce0ba69641b..7c42aea05ee 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -11790,10 +11790,9 @@ has_definition (tree decl) if (DECL_DECLARED_INLINE_P (decl)) return true; - if (DECL_THIS_STATIC (decl) - && (header_module_p () - || (!DECL_LANG_SPECIFIC (decl) || !DECL_MODULE_PURVIEW_P (decl - /* GM static function. */ + if (header_module_p ()) + /* We always need to write definitions in header modules, + since there's no TU to emit them in otherwise. */ return true; if (DECL_TEMPLATE_INFO (decl)) @@ -11826,11 +11825,12 @@ has_definition (tree decl) else { if (!DECL_INITIALIZED_P (decl)) + /* Not defined. */ return false; - if (header_module_p () - || (!DECL_LANG_SPECIFIC (decl) || !DECL_MODULE_PURVIEW_P (decl))) - /* GM static variable. */ + if (header_module_p ()) + /* We always need to write definitions in header modules, + since there's no TU to emit them in otherwise. */ return true; if (!TREE_CONSTANT (decl)) diff --git a/gcc/testsuite/g++.dg/modules/pr115020_a.C b/gcc/testsuite/g++.dg/modules/pr115020_a.C new file mode 100644 index 000..8c190f13b1e --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr115020_a.C @@ -0,0 +1,10 @@ +// PR c++/115020 +// { dg-additional-options "-fmodules-ts -Wno-global-module" } +// { dg-module-cmi M:a } + +module; +struct Check { static void assertion(); }; +void Check::assertion() {} + +module M:a; +Check c; diff --git a/gcc/testsuite/g++.dg/modules/pr115020_b.C b/gcc/testsuite/g++.dg/modules/pr115020_b.C new file mode 100644 index 000..e299454ed54 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr115020_b.C @@ -0,0 +1,10 @@ +// PR c++/115020 +// { dg-additional-options "-fmodules-ts -Wno-global-module" } +// { dg-module-cmi M } + +module; +struct Check { static void assertion(); }; + +export module M; +import :a; +void foo() { Check::assertion(); }
[gcc r15-3032] c++/modules: Handle transitive reachability for deduction guides [PR116403]
https://gcc.gnu.org/g:6f115a8eeea41d383dfb1bbb1af6ac9a97aee180 commit r15-3032-g6f115a8eeea41d383dfb1bbb1af6ac9a97aee180 Author: Nathaniel Shead Date: Sun Aug 18 11:36:40 2024 +1000 c++/modules: Handle transitive reachability for deduction guides [PR116403] Currently we implement [temp.deduct.guide] p1 by forcing all deduction guides to be considered as exported. However this is not sufficient: for transitive non-exported imports we will still hide the deduction guide from name lookup, causing errors. This patch instead adjusts name lookup to have a new ANY_REACHABLE flag to allow for this case. Currently this is only used by deduction guides but there are some other circumstances where this may be useful in the future (e.g. finding existing temploid friends). PR c++/116403 gcc/cp/ChangeLog: * pt.cc (deduction_guides_for): Use ANY_REACHABLE for lookup of deduction guides. * module.cc (depset::hash::add_deduction_guides): Likewise. (module_state::write_cluster): No longer override deduction guides as exported. * name-lookup.cc (name_lookup::search_namespace_only): Ignore visibility when LOOK_want::ANY_REACHABLE is specified. (check_module_override): Ignore visibility when checking for ambiguating deduction guides. * name-lookup.h (LOOK_want): New flag 'ANY_REACHABLE'. gcc/testsuite/ChangeLog: * g++.dg/modules/dguide-4_a.C: New test. * g++.dg/modules/dguide-4_b.C: New test. * g++.dg/modules/dguide-4_c.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/module.cc | 7 +- gcc/cp/name-lookup.cc | 38 --- gcc/cp/name-lookup.h | 5 +++- gcc/cp/pt.cc | 3 ++- gcc/testsuite/g++.dg/modules/dguide-4_a.C | 18 +++ gcc/testsuite/g++.dg/modules/dguide-4_b.C | 9 gcc/testsuite/g++.dg/modules/dguide-4_c.C | 15 7 files changed, 79 insertions(+), 16 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 0a4ceffa3d6..ce0ba69641b 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -13645,7 +13645,7 @@ depset::hash::add_deduction_guides (tree decl) if (find_binding (ns, name)) return; - tree guides = lookup_qualified_name (ns, name, LOOK_want::NORMAL, + tree guides = lookup_qualified_name (ns, name, LOOK_want::ANY_REACHABLE, /*complain=*/false); if (guides == error_mark_node) return; @@ -15228,11 +15228,6 @@ module_state::write_cluster (elf_out *to, depset *scc[], unsigned size, flags |= cbf_hidden; else if (DECL_MODULE_EXPORT_P (STRIP_TEMPLATE (bound))) flags |= cbf_export; - else if (deduction_guide_p (bound)) - /* Deduction guides are always exported so that they are -visible to name lookup whenever their class template -is reachable. */ - flags |= cbf_export; } gcc_checking_assert (DECL_P (bound)); diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 872f1af0b2e..70ad4cbf3b5 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -916,7 +916,8 @@ name_lookup::search_namespace_only (tree scope) if (unsigned base = cluster->indices[jx].base) if (unsigned span = cluster->indices[jx].span) do - if (bitmap_bit_p (imports, base)) + if (bool (want & LOOK_want::ANY_REACHABLE) + || bitmap_bit_p (imports, base)) goto found; while (++base, --span); continue; @@ -960,9 +961,17 @@ name_lookup::search_namespace_only (tree scope) dup_detect |= dup; } - if (STAT_TYPE_VISIBLE_P (bind)) - type = STAT_TYPE (bind); - bind = STAT_VISIBLE (bind); + if (bool (want & LOOK_want::ANY_REACHABLE)) + { + type = STAT_TYPE (bind); + bind = STAT_DECL (bind); + } + else + { + if (STAT_TYPE_VISIBLE_P (bind)) + type = STAT_TYPE (bind); + bind = STAT_VISIBLE (bind); + } } /* And process it. */ @@ -3761,6 +3770,10 @@ check_module_override (tree decl, tree mvec, bool hiding, tree nontmpl = STRIP_TEMPLATE (decl); bool attached = DECL_LANG_SPECIFIC (nontm
[gcc r15-3031] c++/modules: Avoid rechecking initializers when streaming NTTPs [PR116382]
https://gcc.gnu.org/g:0b7904e274fbd6a736d63c0fed28ea32f9cb5997 commit r15-3031-g0b7904e274fbd6a736d63c0fed28ea32f9cb5997 Author: Nathaniel Shead Date: Fri Aug 16 15:06:33 2024 +1000 c++/modules: Avoid rechecking initializers when streaming NTTPs [PR116382] When reading an NTTP we call get_template_parm_object which delegates setting of DECL_INITIAL to the general cp_finish_decl procedure, which calls check_initializer to validate and record it. Apart from being unnecessary (it must have already been validated by the writing module), this also causes errors in cases like the linked PR, as validating may end up needing to call lazy_load_pendings to determine any specialisations that may exist which violates assumptions of the modules streaming code. This patch works around the issue by adding a flag to get_template_parm_object to disable these checks when not needed. PR c++/116382 gcc/cp/ChangeLog: * cp-tree.h (get_template_parm_object): Add check_init param. * module.cc (trees_in::tree_node): Pass check_init=false when building NTTPs. * pt.cc (get_template_parm_object): Prevent cp_finish_decl from validating the initializer when check_init=false. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-nttp-1_a.C: New test. * g++.dg/modules/tpl-nttp-1_b.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/cp-tree.h| 3 ++- gcc/cp/module.cc| 6 +- gcc/cp/pt.cc| 18 ++ gcc/testsuite/g++.dg/modules/tpl-nttp-1_a.C | 8 gcc/testsuite/g++.dg/modules/tpl-nttp-1_b.C | 6 ++ 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 039c70710a2..a9ce44bb214 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7626,7 +7626,8 @@ enum { nt_opaque = false, nt_transparent = true }; extern tree alias_template_specialization_p (const_tree, bool); extern tree dependent_alias_template_spec_p (const_tree, bool); extern bool dependent_opaque_alias_p(const_tree); -extern tree get_template_parm_object (tree expr, tree mangle); +extern tree get_template_parm_object (tree expr, tree mangle, +bool check_init = true); extern tree tparm_object_argument (tree); extern bool explicit_class_specialization_p (tree); extern bool push_tinst_level(tree); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index c3218bd5caf..0a4ceffa3d6 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -9938,7 +9938,11 @@ trees_in::tree_node (bool is_use) tree name = tree_node (); if (!get_overrun ()) { - res = get_template_parm_object (init, name); + /* We don't want to check the initializer as that may require + name lookup, which could recursively start lazy loading. + Instead we know that INIT is already valid so we can just + apply that directly. */ + res = get_template_parm_object (init, name, /*check_init=*/false); int tag = insert (res); dump (dumper::TREE) && dump ("Created nttp object:%d %N", tag, name); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 32d164f0fd5..76edc7aad50 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -7361,10 +7361,11 @@ create_template_parm_object (tree expr, tsubst_flags_t complain) static GTY(()) hash_map *tparm_obj_values; /* Find or build an nttp object for (already-validated) EXPR with name - NAME. */ + NAME. When CHECK_INIT is false we don't need to process the initialiser, + it's already been done. */ tree -get_template_parm_object (tree expr, tree name) +get_template_parm_object (tree expr, tree name, bool check_init/*=true*/) { tree decl = get_global_binding (name); if (decl) @@ -7385,11 +7386,20 @@ get_template_parm_object (tree expr, tree name) { /* If EXPR contains any PTRMEM_CST, they will get clobbered by lower_var_init before we're done mangling. So store the original -value elsewhere. */ - tree copy = unshare_constructor (expr); +value elsewhere. We only need to unshare EXPR if it's not yet +been processed. */ + tree copy = check_init ? unshare_constructor (expr) : expr; hash_map_safe_put (tparm_obj_values, decl, copy); } + if (!check_init) +{ + /* The EXPR is the already processed initializer, set it on the NTTP +object now so that cp_finish_decl doesn't do it again later. */ + DECL_INITIAL (decl) = expr; + DECL_INITIALIZED_P (decl) = 1; +} + pushdecl_top_level_and_finish (decl, expr); return decl; diff --git
[gcc r15-3030] c++/modules: Fix type lookup in DECL_TEMPLATE_INSTANTIATIONS [PR116364]
https://gcc.gnu.org/g:c310d29cac1c3a770f48ab8bb2d295ef9cc08c53 commit r15-3030-gc310d29cac1c3a770f48ab8bb2d295ef9cc08c53 Author: Nathaniel Shead Date: Thu Aug 15 21:46:09 2024 +1000 c++/modules: Fix type lookup in DECL_TEMPLATE_INSTANTIATIONS [PR116364] We need to use the DECL_TEMPLATE_INSTANTIATIONS property to find reachable specialisations from a template to ensure that any GM specialisations are properly marked as reachable. Currently the modules code uses the decl when rebuilding this property, but this is not always correct; it appears that for type specialisations we need to use the TREE_TYPE of the decl instead so that the specialisation is correctly found. This patch makes the required adjustments. PR c++/116364 gcc/cp/ChangeLog: * cp-tree.h (get_mergeable_specialization_flags): Adjust signature. * module.cc (trees_out::decl_value): Indicate whether this is a type or decl specialisation. * pt.cc (get_mergeable_specialization_flags): Match against the type of a non-decl specialisation. (add_mergeable_specialization): Use the already calculated spec instead of always adding decl to DECL_TEMPLATE_INSTANTIATIONS. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-spec-9_a.C: New test. * g++.dg/modules/tpl-spec-9_b.C: New test. * g++.dg/modules/tpl-spec-9_c.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/cp-tree.h| 3 ++- gcc/cp/module.cc| 3 ++- gcc/cp/pt.cc| 8 +--- gcc/testsuite/g++.dg/modules/tpl-spec-9_a.C | 12 gcc/testsuite/g++.dg/modules/tpl-spec-9_b.C | 5 + gcc/testsuite/g++.dg/modules/tpl-spec-9_c.C | 5 + 6 files changed, 31 insertions(+), 5 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a53fbcb43ec..039c70710a2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7672,7 +7672,8 @@ extern void walk_specializations (bool, void *), void *); extern tree match_mergeable_specialization (bool is_decl, spec_entry *); -extern unsigned get_mergeable_specialization_flags (tree tmpl, tree spec); +extern unsigned get_mergeable_specialization_flags (bool is_decl, tree tmpl, + tree spec); extern void add_mergeable_specialization(bool is_decl, spec_entry *, tree outer, unsigned); extern tree add_to_template_args (tree, tree); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index f4d137b13a1..c3218bd5caf 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -7981,7 +7981,8 @@ trees_out::decl_value (tree decl, depset *dep) auto *entry = reinterpret_cast (dep->deps[0]); if (streaming_p ()) - u (get_mergeable_specialization_flags (entry->tmpl, decl)); + u (get_mergeable_specialization_flags (mk & MK_tmpl_decl_mask, + entry->tmpl, decl)); tree_node (entry->tmpl); tree_node (entry->args); } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 684ee0c8a60..32d164f0fd5 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -31561,13 +31561,14 @@ match_mergeable_specialization (bool decl_p, spec_entry *elt) specialization lists of TMPL. */ unsigned -get_mergeable_specialization_flags (tree tmpl, tree decl) +get_mergeable_specialization_flags (bool decl_p, tree tmpl, tree decl) { unsigned flags = 0; + tree spec = decl_p ? decl : TREE_TYPE (decl); for (tree inst = DECL_TEMPLATE_INSTANTIATIONS (tmpl); inst; inst = TREE_CHAIN (inst)) -if (TREE_VALUE (inst) == decl) +if (TREE_VALUE (inst) == spec) { flags |= 1; break; @@ -31625,7 +31626,8 @@ add_mergeable_specialization (bool decl_p, spec_entry *elt, tree decl, if (flags & 1) DECL_TEMPLATE_INSTANTIATIONS (elt->tmpl) - = tree_cons (elt->args, decl, DECL_TEMPLATE_INSTANTIATIONS (elt->tmpl)); + = tree_cons (elt->args, elt->spec, + DECL_TEMPLATE_INSTANTIATIONS (elt->tmpl)); if (flags & 2) { diff --git a/gcc/testsuite/g++.dg/modules/tpl-spec-9_a.C b/gcc/testsuite/g++.dg/modules/tpl-spec-9_a.C new file mode 100644 index 000..d7c02bb279d --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-spec-9_a.C @@ -0,0 +1,12 @@ +// PR c++/116364 +// { dg-additional-options "-fmodules-ts -Wno-global-module" } +// { dg-module-cmi foo:part } + +module; +template struct S {}; +template <> struct S + { static constexpr bool value = true; }; +export module foo:part; + +export templa
[gcc r15-2819] c++: Propagate TREE_ADDRESSABLE in fixup_type_variants [PR115062]
https://gcc.gnu.org/g:71aebb36174c194231da5f9c7c23f81dbb082ca4 commit r15-2819-g71aebb36174c194231da5f9c7c23f81dbb082ca4 Author: Nathaniel Shead Date: Thu Aug 8 17:52:03 2024 +1000 c++: Propagate TREE_ADDRESSABLE in fixup_type_variants [PR115062] This has caused issues with modules when an import fills in the definition of a type already created with a typedef. PR c++/115062 gcc/cp/ChangeLog: * class.cc (fixup_type_variants): Propagate TREE_ADDRESSABLE. (finish_struct_bits): Cleanup now that TREE_ADDRESSABLE is propagated by fixup_type_variants. gcc/testsuite/ChangeLog: * g++.dg/modules/pr115062_a.H: New test. * g++.dg/modules/pr115062_b.H: New test. * g++.dg/modules/pr115062_c.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/class.cc | 31 ++- gcc/testsuite/g++.dg/modules/pr115062_a.H | 6 ++ gcc/testsuite/g++.dg/modules/pr115062_b.H | 14 ++ gcc/testsuite/g++.dg/modules/pr115062_c.C | 9 + 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index 718601756ddc..fb6c33709500 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -2312,6 +2312,7 @@ fixup_type_variants (tree type) TYPE_PRECISION (variant) = TYPE_PRECISION (type); TYPE_MODE_RAW (variant) = TYPE_MODE_RAW (type); TYPE_EMPTY_P (variant) = TYPE_EMPTY_P (type); + TREE_ADDRESSABLE (variant) = TREE_ADDRESSABLE (type); } } @@ -2378,8 +2379,17 @@ fixup_attribute_variants (tree t) static void finish_struct_bits (tree t) { - /* Fix up variants (if any). */ - fixup_type_variants (t); + /* If this type has a copy constructor or a destructor, force its + mode to be BLKmode, and force its TREE_ADDRESSABLE bit to be + nonzero. This will cause it to be passed by invisible reference + and prevent it from being returned in a register. */ + if (type_has_nontrivial_copy_init (t) + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)) +{ + SET_DECL_MODE (TYPE_MAIN_DECL (t), BLKmode); + SET_TYPE_MODE (t, BLKmode); + TREE_ADDRESSABLE (t) = 1; +} if (BINFO_N_BASE_BINFOS (TYPE_BINFO (t)) && TYPE_POLYMORPHIC_P (t)) /* For a class w/o baseclasses, 'finish_struct' has set @@ -2392,21 +2402,8 @@ finish_struct_bits (tree t) looking in the vtables). */ get_pure_virtuals (t); - /* If this type has a copy constructor or a destructor, force its - mode to be BLKmode, and force its TREE_ADDRESSABLE bit to be - nonzero. This will cause it to be passed by invisible reference - and prevent it from being returned in a register. */ - if (type_has_nontrivial_copy_init (t) - || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)) -{ - tree variants; - SET_DECL_MODE (TYPE_MAIN_DECL (t), BLKmode); - for (variants = t; variants; variants = TYPE_NEXT_VARIANT (variants)) - { - SET_TYPE_MODE (variants, BLKmode); - TREE_ADDRESSABLE (variants) = 1; - } -} + /* Fix up variants (if any). */ + fixup_type_variants (t); } /* Issue warnings about T having private constructors, but no friends, diff --git a/gcc/testsuite/g++.dg/modules/pr115062_a.H b/gcc/testsuite/g++.dg/modules/pr115062_a.H new file mode 100644 index ..3c9daac317e6 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr115062_a.H @@ -0,0 +1,6 @@ +// PR c++/115062 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +template class S; +typedef S X; diff --git a/gcc/testsuite/g++.dg/modules/pr115062_b.H b/gcc/testsuite/g++.dg/modules/pr115062_b.H new file mode 100644 index ..d8da59591ec5 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr115062_b.H @@ -0,0 +1,14 @@ +// PR c++/115062 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +template +struct S { + int a; + long b; + union {}; + ~S(); + void foo(); +}; +extern template void S::foo(); +S operator+(S, const char *); diff --git a/gcc/testsuite/g++.dg/modules/pr115062_c.C b/gcc/testsuite/g++.dg/modules/pr115062_c.C new file mode 100644 index ..5255b9ffca7a --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr115062_c.C @@ -0,0 +1,9 @@ +// PR c++/115062 +// { dg-additional-options "-fmodules-ts" } + +import "pr115062_a.H"; +import "pr115062_b.H"; + +int main() { + X x = X() + ""; +}
[gcc r15-2818] c++/modules: Assume header bindings are global module
https://gcc.gnu.org/g:0de1481a9d91e936135da4f882314499eea38a36 commit r15-2818-g0de1481a9d91e936135da4f882314499eea38a36 Author: Nathaniel Shead Date: Thu Aug 8 22:00:07 2024 +1000 c++/modules: Assume header bindings are global module While stepping through some code I noticed that we do some extra work (finding the originating module decl, stripping the template, and inspecting the attached-ness) for every declaration taken from a header unit. This doesn't seem necessary though since no declaration in a header unit can be attached to anything but the global module, so we can just assume that global_p will be true. This was the original behaviour before I removed this assumption while refactoring for r15-2807-gc592310d5275e0. gcc/cp/ChangeLog: * module.cc (module_state::read_cluster): Assume header module declarations will require GM merging. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 58ad8cbdb614..f4d137b13a17 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -15361,7 +15361,7 @@ module_state::read_cluster (unsigned snum) tree visible = NULL_TREE; tree type = NULL_TREE; bool dedup = false; - bool global_p = false; + bool global_p = is_header (); /* We rely on the bindings being in the reverse order of the resulting overload set. */
[gcc r15-2808] c++/modules: Handle instantiating already tsubsted template friend classes [PR115801]
https://gcc.gnu.org/g:79209273663672ff05663554741fd2558b4aac99 commit r15-2808-g79209273663672ff05663554741fd2558b4aac99 Author: Nathaniel Shead Date: Tue Aug 6 15:41:38 2024 +1000 c++/modules: Handle instantiating already tsubsted template friend classes [PR115801] With modules it may be the case that a template friend class provided with a qualified name is not found by name lookup at instantiation time, due to the class not being exported from its module. This causes issues in tsubst_friend_class which did not handle this case. This is caused by the named friend class not actually requiring tsubsting. This was already worked around for the "found by name lookup" case (g++.dg/template/friend5.C), but it looks like there's no need to do name lookup at all for this particular case to work. We do need to be careful to continue to do name lookup to handle templates from an outer current instantiation though; this patch adds a new testcase for this as well. This should not impact modules (because exportingness will only affect namespace lookup). PR c++/115801 gcc/cp/ChangeLog: * pt.cc (tsubst_friend_class): Return the type immediately when no tsubsting or name lookup is required. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-friend-16_a.C: New test. * g++.dg/modules/tpl-friend-16_b.C: New test. * g++.dg/template/friend82.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Patrick Palka Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 8 ++ gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C | 40 ++ gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C | 17 +++ gcc/testsuite/g++.dg/template/friend82.C | 23 +++ 4 files changed, 88 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 3e55d5c0fea5..1dde7d167fd6 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11732,6 +11732,14 @@ tsubst_friend_class (tree friend_tmpl, tree args) return TREE_TYPE (tmpl); } + if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (friend_tmpl)) == 1) +/* The template has already been fully substituted, e.g. for + +template friend class ::C; + + so we can just return it directly. */ +return TREE_TYPE (friend_tmpl); + tree context = CP_DECL_CONTEXT (friend_tmpl); if (TREE_CODE (context) == NAMESPACE_DECL) push_nested_namespace (context); diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C b/gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C new file mode 100644 index ..e1cdcd98e1e0 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-friend-16_a.C @@ -0,0 +1,40 @@ +// PR c++/115801 +// { dg-additional-options "-fmodules-ts -Wno-global-module" } +// { dg-module-cmi test } + +module; + +template struct GMF; +template struct GMF_Hidden { + int go() { GMF gmf; return gmf.x; } +}; + +template struct GMF { +private: + template friend struct ::GMF_Hidden; + int x = 1; +}; + +template int test_gmf() { + GMF_Hidden h; return h.go(); +} + +export module test; + +export using ::GMF; +export using ::test_gmf; + +export template struct Attached; +template struct Attached_Hidden { + int go() { Attached attached; return attached.x; } +}; + +template struct Attached { +private: + template friend struct ::Attached_Hidden; + int x = 2; +}; + +export template int test_attached() { + Attached_Hidden h; return h.go(); +} diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C b/gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C new file mode 100644 index ..d3484ab19b11 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-friend-16_b.C @@ -0,0 +1,17 @@ +// PR c++/115801 +// { dg-additional-options "-fmodules-ts" } + +import test; + +int main() { + GMF gmf; + Attached attached; + + int a = test_gmf(); + int b = test_attached(); + + GMF_Hidden gmf_hidden; // { dg-error "not declared" } + Attached_Hidden attached_hidden; // { dg-error "not declared" } +} + +// { dg-prune-output "expected primary-expression" } diff --git a/gcc/testsuite/g++.dg/template/friend82.C b/gcc/testsuite/g++.dg/template/friend82.C new file mode 100644 index ..28a057dd23e5 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend82.C @@ -0,0 +1,23 @@ +// { dg-do compile } + +template +struct A { + template struct B; + + template + struct C { +template friend struct A::B; + private: +int x; + }; +}; + +template +template +struct A::B { + int foo(A::C c) { return c.x; } // { dg-error "private" } +}; + +template struct A::C; +template struct A::B; // { dg-bogus "" } +template struct A::B; // { dg-message "required from here" }
[gcc r15-2807] c++/modules: Fix merging of GM entities in partitions [PR114950]
https://gcc.gnu.org/g:c592310d5275e09977504c136419686bd2277af0 commit r15-2807-gc592310d5275e09977504c136419686bd2277af0 Author: Nathaniel Shead Date: Mon Aug 5 22:37:57 2024 +1000 c++/modules: Fix merging of GM entities in partitions [PR114950] Currently name lookup generally seems to assume that all entities declared within a named module (partition) are attached to said module, which is not true for GM entities (e.g. via extern "C++"), and causes issues with deduplication. This patch fixes the issue by ensuring that module attachment of a declaration is consistently used to handling merging. Handling this exposes some issues with deduplicating temploid friends; to resolve this we always create the BINDING_SLOT_PARTITION slot so that we have somewhere to place attached names (from any module). This doesn't yet completely handle issues with allowing otherwise conflicting temploid friends from different modules to co-exist in the same module if neither are reachable from the other via name lookup. PR c++/114950 gcc/cp/ChangeLog: * module.cc (trees_out::decl_value): Stream bit indicating imported temploid friends early. (trees_in::decl_value): Use this bit with key_mergeable. (trees_in::key_mergeable): Allow merging attached declarations if they're imported temploid friends (which must be namespace scope). (module_state::read_cluster): Check for GM entities that may require merging even when importing from partitions. * name-lookup.cc (enum binding_slots): Adjust comment. (get_fixed_binding_slot): Always create partition slot. (name_lookup::search_namespace_only): Support binding vectors with both partition and GM entities to dedup. (walk_module_binding): Likewise. (name_lookup::adl_namespace_fns): Likewise. (set_module_binding): Likewise. (check_module_override): Use attachment of the decl when checking overrides rather than named_module_p. (lookup_imported_hidden_friend): Use partition slot for finding mergeable template bindings. * name-lookup.h (set_module_binding): Split mod_glob_flag parameter into separate global_p and partition_p params. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-friend-13_e.C: Adjust error message. * g++.dg/modules/ambig-2_a.C: New test. * g++.dg/modules/ambig-2_b.C: New test. * g++.dg/modules/part-9_a.C: New test. * g++.dg/modules/part-9_b.C: New test. * g++.dg/modules/part-9_c.C: New test. * g++.dg/modules/tpl-friend-15.h: New test. * g++.dg/modules/tpl-friend-15_a.C: New test. * g++.dg/modules/tpl-friend-15_b.C: New test. * g++.dg/modules/tpl-friend-15_c.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/module.cc | 52 + gcc/cp/name-lookup.cc | 65 +- gcc/cp/name-lookup.h | 2 +- gcc/testsuite/g++.dg/modules/ambig-2_a.C | 7 +++ gcc/testsuite/g++.dg/modules/ambig-2_b.C | 10 gcc/testsuite/g++.dg/modules/part-9_a.C| 10 gcc/testsuite/g++.dg/modules/part-9_b.C| 10 gcc/testsuite/g++.dg/modules/part-9_c.C| 8 gcc/testsuite/g++.dg/modules/tpl-friend-13_e.C | 4 +- gcc/testsuite/g++.dg/modules/tpl-friend-15.h | 11 + gcc/testsuite/g++.dg/modules/tpl-friend-15_a.C | 8 gcc/testsuite/g++.dg/modules/tpl-friend-15_b.C | 8 gcc/testsuite/g++.dg/modules/tpl-friend-15_c.C | 7 +++ 13 files changed, 148 insertions(+), 54 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 0f3e1d97c53b..58ad8cbdb614 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -2958,7 +2958,8 @@ private: public: tree decl_container (); tree key_mergeable (int tag, merge_kind, tree decl, tree inner, tree type, - tree container, bool is_attached); + tree container, bool is_attached, + bool is_imported_temploid_friend); unsigned binfo_mergeable (tree *); private: @@ -7806,6 +7807,7 @@ trees_out::decl_value (tree decl, depset *dep) || !TYPE_PTRMEMFUNC_P (TREE_TYPE (decl))); merge_kind mk = get_merge_kind (decl, dep); + bool is_imported_temploid_friend = imported_temploid_friends->get (decl); if (CHECKING_P) { @@ -7841,13 +7843,11 @@ trees_out::decl_value (tree decl, depset *dep) && DECL_MODULE_ATTACH_P (not_tmpl)) is_attached = true; - /* But don't consider imported temploid friends as attached, -
[gcc r15-2806] c++/modules: Clarify error message in read_enum_def
https://gcc.gnu.org/g:c0ad382caa38873bb6078edf5314930504bc01f1 commit r15-2806-gc0ad382caa38873bb6078edf5314930504bc01f1 Author: Nathaniel Shead Date: Wed Aug 7 19:17:52 2024 +1000 c++/modules: Clarify error message in read_enum_def This error message reads to me the wrong way around, particularly in the context of other errors. Updated so that the ellipsis connect. gcc/cp/ChangeLog: * module.cc (trees_in::read_enum_def): Clarify error. gcc/testsuite/ChangeLog: * g++.dg/modules/enum-bad-1_b.C: Update error message. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc| 4 ++-- gcc/testsuite/g++.dg/modules/enum-bad-1_b.C | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 723f0890d96e..0f3e1d97c53b 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -12687,9 +12687,9 @@ trees_in::read_enum_def (tree defn, tree maybe_template) if (known_decl && new_decl) { inform (DECL_SOURCE_LOCATION (new_decl), - "... this enumerator %qD", new_decl); + "enumerator %qD does not match ...", new_decl); inform (DECL_SOURCE_LOCATION (known_decl), - "enumerator %qD does not match ...", known_decl); + "... this enumerator %qD", known_decl); } else if (known_decl || new_decl) { diff --git a/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C b/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C index b01cd66a14d0..23e17b088a2c 100644 --- a/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C +++ b/gcc/testsuite/g++.dg/modules/enum-bad-1_b.C @@ -13,13 +13,13 @@ import "enum-bad-1_a.H"; ONE one; -// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:5:6: error: definition of 'enum ONE' does not match\n[^\n]*enum-bad-1_b.C:3:6: note: existing definition 'enum ONE'\nIn module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:5:11: note: ... this enumerator 'A'\n[^\n]*enum-bad-1_b.C:3:11: note: enumerator 'Q' does not match ...\n[^\n]*enum-bad-1_b.C:15:1: note: during load of binding '::ONE'\n} } +// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:5:6: error: definition of 'enum ONE' does not match\n[^\n]*enum-bad-1_b.C:3:6: note: existing definition 'enum ONE'\nIn module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:5:11: note: enumerator 'A' does not match ...\n[^\n]*enum-bad-1_b.C:3:11: note: ... this enumerator 'Q'\n[^\n]*enum-bad-1_b.C:15:1: note: during load of binding '::ONE'\n} } int i = TWO; -// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:6:6: error: definition of 'enum' does not match\n[^\n]*enum-bad-1_b.C:4:6: note: existing definition 'enum'\nIn module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:6:12: note: ... this enumerator 'THREE'\n[^\n]*enum-bad-1_b.C:4:12: note: enumerator 'DREI' does not match ...\n[^\n]*enum-bad-1_b.C:18:9: note: during load of binding '::TWO'\n} } +// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:6:6: error: definition of 'enum' does not match\n[^\n]*enum-bad-1_b.C:4:6: note: existing definition 'enum'\nIn module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:6:12: note: enumerator 'THREE' does not match ...\n[^\n]*enum-bad-1_b.C:4:12: note: ... this enumerator 'DREI'\n[^\n]*enum-bad-1_b.C:18:9: note: during load of binding '::TWO'\n} } FOUR four; -// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:7:6: error: definition of 'enum FOUR' does not match\n[^\n]*enum-bad-1_b.C:5:6: note: existing definition 'enum FOUR'\nIn module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:7:12: note: ... this enumerator 'B'\n[^\n]*enum-bad-1_b.C:5:12: note: enumerator 'B' does not match ...\n[^\n]*enum-bad-1_b.C:21:1: note: during load of binding '::FOUR'\n} } +// { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:7:6: error: definition of 'enum FOUR' does not match\n[^\n]*enum-bad-1_b.C:5:6: note: existing definition 'enum FOUR'\nIn module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:7:12: note: enumerator 'B' does not match ...\n[^\n]*enum-bad-1_b.C:5:12: note: ... this enumerator 'B'\n[^\n]*enum-bad-1_b.C:21:1: note: during load of binding '::FOUR'\n} } FIVE five; // { dg-regexp {In module [^\n]*enum-bad-1_a.H, imported at [^\n]*enum-bad-1_b.C:8:\n[^\n]*enum-bad-1_a.H:8:6: error: definition of 'enum FIVE' does not matc
[gcc r15-2779] c++/modules: Ensure deduction guides are always reachable [PR115231]
https://gcc.gnu.org/g:ca287145f23ec3ea987fc2eacde3994096cc528e commit r15-2779-gca287145f23ec3ea987fc2eacde3994096cc528e Author: Nathaniel Shead Date: Sat Jun 15 22:50:14 2024 +1000 c++/modules: Ensure deduction guides are always reachable [PR115231] Deduction guides are represented as 'normal' functions currently, and have no special handling in modules. However, this causes some issues; by [temp.deduct.guide] a deduction guide is not found by normal name lookup and instead all reachable deduction guides for a class template should be considered, but this does not happen currently. To solve this, this patch ensures that all deduction guides are considered exported to ensure that they are always visible to importers if they are reachable. Another alternative here would be to add a new kind of "all reachable" flag to name lookup, but that is complicated by some difficulties in handling GM entities; this may be a better way to go if more kinds of entities end up needing this handling, however. Another issue here is that because deduction guides are "unrelated" functions, they will usually get discarded from the GMF, so this patch ensures that when finding dependencies, GMF deduction guides will also have bindings created. We do this in find_dependencies so that we don't unnecessarily create bindings for GMF deduction guides that are never reached; for consistency we do this for *all* deduction guides, not just GM ones. We also make sure that the opposite (a deduction guide being the only purview reference to a GMF template) correctly marks it as reachable. Finally, when merging deduction guides from multiple modules, the name lookup code may now return two-dimensional overload sets, so update callers to match. As a small drive-by improvement this patch also updates the error pretty printing code to add a space before the '->' when printing a deduction guide, so we get 'S(int) -> S' instead of 'S(int)-> S'. PR c++/115231 gcc/cp/ChangeLog: * error.cc (dump_function_decl): Add a space before '->' when printing deduction guides. * module.cc (depset::hash::add_binding_entity): Don't create bindings for guides here, only mark dependencies. (depset::hash::add_deduction_guides): New. (depset::hash::find_dependencies): Add deduction guide dependencies for a class template. (module_state::write_cluster): Always consider deduction guides as exported. * pt.cc (deduction_guides_for): Use 'lkp_iterator' instead of 'ovl_iterator'. gcc/testsuite/ChangeLog: * g++.dg/modules/dguide-1_a.C: New test. * g++.dg/modules/dguide-1_b.C: New test. * g++.dg/modules/dguide-2_a.C: New test. * g++.dg/modules/dguide-2_b.C: New test. * g++.dg/modules/dguide-3_a.C: New test. * g++.dg/modules/dguide-3_b.C: New test. * g++.dg/modules/dguide-3_c.C: New test. * g++.dg/modules/dguide-3_d.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/error.cc | 1 + gcc/cp/module.cc | 65 +++ gcc/cp/pt.cc | 2 +- gcc/testsuite/g++.dg/modules/dguide-1_a.C | 44 + gcc/testsuite/g++.dg/modules/dguide-1_b.C | 20 ++ gcc/testsuite/g++.dg/modules/dguide-2_a.C | 24 gcc/testsuite/g++.dg/modules/dguide-2_b.C | 19 + gcc/testsuite/g++.dg/modules/dguide-3_a.C | 10 + gcc/testsuite/g++.dg/modules/dguide-3_b.C | 10 + gcc/testsuite/g++.dg/modules/dguide-3_c.C | 6 +++ gcc/testsuite/g++.dg/modules/dguide-3_d.C | 30 ++ 11 files changed, 230 insertions(+), 1 deletion(-) diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index ee3868efaed6..6c22ff55b463 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -1936,6 +1936,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) dump_type_suffix (pp, ret, flags); else if (deduction_guide_p (t)) { + pp->set_padding (pp_before); pp_cxx_ws_string (pp, "->"); dump_type (pp, TREE_TYPE (TREE_TYPE (t)), flags); } diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 7130faf26f52..723f0890d96e 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -2589,6 +2589,9 @@ public: void add_partial_entities (vec *); void add_class_entities (vec *); + private: +void add_deduction_guides (tree decl); + public: void find_dependencies (module_state *); bool finalize_dependencies (); @@ -13172,6 +13175,15 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) /* Ignore NTTP objects. */ return false;
[gcc r15-2778] c++: Improve fixits for incorrect explicit instantiations
https://gcc.gnu.org/g:b7f719612515a86d1d2a36e24b02ade3f0904e10 commit r15-2778-gb7f719612515a86d1d2a36e24b02ade3f0904e10 Author: Nathaniel Shead Date: Mon Mar 4 22:59:56 2024 +1100 c++: Improve fixits for incorrect explicit instantiations When forgetting the '<>' on an explicit specialisation, the suggested fixit hint suggests to add 'template <>', but naively applying will cause nonsense results like 'template template <> struct S {};'. Instead check if we're currently parsing an explicit instantiation, and if so inform about the issue (an instantiation cannot have a class body) and suggest a fixit of simply '<>' to create a specialisation instead. gcc/cp/ChangeLog: * parser.cc (cp_parser_class_head): Clarify error message for explicit instantiations. gcc/testsuite/ChangeLog: * g++.dg/template/explicit-instantiation9.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/parser.cc | 19 ++- .../g++.dg/template/explicit-instantiation9.C | 6 ++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index f625b0a310c8..82f3903838e2 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -27721,11 +27721,20 @@ cp_parser_class_head (cp_parser* parser, class_head_start_location, get_finish (type_start_token->location)); rich_location richloc (line_table, reported_loc); - richloc.add_fixit_insert_before (class_head_start_location, - "template <> "); - error_at (&richloc, - "an explicit specialization must be preceded by" - " %%>"); + if (processing_explicit_instantiation) + { + richloc.add_fixit_insert_before ("<> "); + error_at (&richloc, + "an explicit instantiation cannot have a definition;" + " use %%> to declare a specialization"); + } + else + { + richloc.add_fixit_insert_before ("template <> "); + error_at (&richloc, + "an explicit specialization must be preceded by" + " %%>"); + } invalid_explicit_specialization_p = true; /* Take the same action that would have been taken by cp_parser_explicit_specialization. */ diff --git a/gcc/testsuite/g++.dg/template/explicit-instantiation9.C b/gcc/testsuite/g++.dg/template/explicit-instantiation9.C new file mode 100644 index ..c4400226ef83 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/explicit-instantiation9.C @@ -0,0 +1,6 @@ +// Fixits for specialisations are not valid for instantiations + +template +struct S {}; + +template struct S {}; // { dg-error "explicit instantiation cannot have a definition" }
[gcc r15-2334] c++/modules: Stream warning suppressions [PR115757]
https://gcc.gnu.org/g:fd599d96d464caed8bf78e4a43120d9a121b7e7a commit r15-2334-gfd599d96d464caed8bf78e4a43120d9a121b7e7a Author: Nathaniel Shead Date: Sun Jul 7 13:56:25 2024 +1000 c++/modules: Stream warning suppressions [PR115757] Currently we don't stream the contents of 'nowarn_map'; this means that warning suppressions don't get applied in importers, which is particularly relevant for templates (as in the linked testcase). Rather than streaming the whole contents of 'nowarn_map', this patch instead just streams the exported suppressions for each tree node individually, to not build up additional locations and suppressions for tree nodes that do not need to be streamed. PR c++/115757 gcc/cp/ChangeLog: * module.cc (trees_out::core_vals): Write warning specs for DECLs and EXPRs. (trees_in::core_vals): Read warning specs. gcc/ChangeLog: * tree.h (put_warning_spec_at): Declare new function. (has_warning_spec): Likewise. (get_warning_spec): Likewise. (put_warning_spec): Likewise. * diagnostic-spec.h (nowarn_spec_t::from_bits): New function. * diagnostic-spec.cc (put_warning_spec_at): New function. * warning-control.cc (has_warning_spec): New function. (get_warning_spec): New function. (put_warning_spec): New function. gcc/testsuite/ChangeLog: * g++.dg/modules/warn-spec-1_a.C: New test. * g++.dg/modules/warn-spec-1_b.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 12 gcc/diagnostic-spec.cc | 21 + gcc/diagnostic-spec.h| 7 +++ gcc/testsuite/g++.dg/modules/warn-spec-1_a.C | 10 ++ gcc/testsuite/g++.dg/modules/warn-spec-1_b.C | 8 gcc/tree.h | 9 + gcc/warning-control.cc | 26 ++ 7 files changed, 93 insertions(+) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 69764fd772d3..d1607a067575 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -6000,6 +6000,10 @@ trees_out::core_vals (tree t) if (state) state->write_location (*this, t->decl_minimal.locus); + + if (streaming_p ()) + if (has_warning_spec (t)) + u (get_warning_spec (t)); } if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON)) @@ -6113,6 +6117,10 @@ trees_out::core_vals (tree t) if (state) state->write_location (*this, t->exp.locus); + if (streaming_p ()) + if (has_warning_spec (t)) + u (get_warning_spec (t)); + /* Walk in forward order, as (for instance) REQUIRES_EXPR has a bunch of unscoped parms on its first operand. It's safer to create those in order. */ @@ -6576,6 +6584,8 @@ trees_in::core_vals (tree t) /* Don't zap the locus just yet, we don't record it correctly and thus lose all location information. */ t->decl_minimal.locus = state->read_location (*this); + if (has_warning_spec (t)) + put_warning_spec (t, u ()); } if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON)) @@ -6654,6 +6664,8 @@ trees_in::core_vals (tree t) if (CODE_CONTAINS_STRUCT (code, TS_EXP)) { t->exp.locus = state->read_location (*this); + if (has_warning_spec (t)) + put_warning_spec (t, u ()); bool vl = TREE_CODE_CLASS (code) == tcc_vl_exp; for (unsigned limit = (vl ? VL_EXP_OPERAND_LENGTH (t) diff --git a/gcc/diagnostic-spec.cc b/gcc/diagnostic-spec.cc index 996ad6b273aa..addaf089f035 100644 --- a/gcc/diagnostic-spec.cc +++ b/gcc/diagnostic-spec.cc @@ -179,6 +179,27 @@ suppress_warning_at (location_t loc, opt_code opt /* = all_warnings */, return true; } +/* Change the warning disposition for LOC to match OPTSPEC. */ + +void +put_warning_spec_at (location_t loc, unsigned bits) +{ + gcc_checking_assert (!RESERVED_LOCATION_P (loc)); + + nowarn_spec_t optspec = nowarn_spec_t::from_bits (bits); + if (!optspec) +{ + if (nowarn_map) + nowarn_map->remove (loc); +} + else +{ + if (!nowarn_map) + nowarn_map = nowarn_map_t::create_ggc (32); + nowarn_map->put (loc, optspec); +} +} + /* Copy the no-warning disposition from one location to another. */ void diff --git a/gcc/diagnostic-spec.h b/gcc/diagnostic-spec.h index 22d4c0671584..0b155a5cde3f 100644 --- a/gcc/diagnostic-spec.h +++ b/gcc/diagnostic-spec.h @@ -56,6 +56,13 @@ public: nowarn_spec_t (opt_code); + static nowarn_spec_t from_bits (unsigned bits) + { +nowarn_spec_t spec; +spec.m_bits = bits; +return spec; + } + /* Return the raw bitset. */ operator unsigned() const { diff --git a/gcc/testsuite/g++.dg/modules/warn-spec-1
[gcc r14-10453] c++/modules: Conditionally start timer during lazy load [PR115165]
https://gcc.gnu.org/g:f0c3a1c16af234b55f48cf1cfe299417f93f163c commit r14-10453-gf0c3a1c16af234b55f48cf1cfe299417f93f163c Author: Nathaniel Shead Date: Sun Jul 7 23:19:52 2024 +1000 c++/modules: Conditionally start timer during lazy load [PR115165] While lazy loading, instantiation of pendings can sometimes recursively perform name lookup and begin further lazy loading. When using the '-ftime-report' functionality this causes ICEs as we could start an already-running timer for the importing. This patch fixes the issue by using the 'timevar_cond*' API instead to support such recursive calls. PR c++/115165 gcc/cp/ChangeLog: * module.cc (lazy_load_binding): Use 'timevar_cond*' APIs. (lazy_load_pendings): Likewise. gcc/testsuite/ChangeLog: * g++.dg/modules/timevar-1_a.H: New test. * g++.dg/modules/timevar-1_b.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 8 gcc/testsuite/g++.dg/modules/timevar-1_a.H | 14 ++ gcc/testsuite/g++.dg/modules/timevar-1_b.C | 10 ++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index b610b808240c..fb10537d3e34 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -19517,7 +19517,7 @@ lazy_load_binding (unsigned mod, tree ns, tree id, binding_slot *mslot) { int count = errorcount + warningcount; - timevar_start (TV_MODULE_IMPORT); + bool timer_running = timevar_cond_start (TV_MODULE_IMPORT); /* Make sure lazy loading from a template context behaves as if from a non-template context. */ @@ -19547,7 +19547,7 @@ lazy_load_binding (unsigned mod, tree ns, tree id, binding_slot *mslot) function_depth--; - timevar_stop (TV_MODULE_IMPORT); + timevar_cond_stop (TV_MODULE_IMPORT, timer_running); if (!ok) fatal_error (input_location, @@ -19586,7 +19586,7 @@ lazy_load_pendings (tree decl) int count = errorcount + warningcount; - timevar_start (TV_MODULE_IMPORT); + bool timer_running = timevar_cond_start (TV_MODULE_IMPORT); bool ok = !recursive_lazy (); if (ok) { @@ -19620,7 +19620,7 @@ lazy_load_pendings (tree decl) function_depth--; } - timevar_stop (TV_MODULE_IMPORT); + timevar_cond_stop (TV_MODULE_IMPORT, timer_running); if (!ok) fatal_error (input_location, "failed to load pendings for %<%E%s%E%>", diff --git a/gcc/testsuite/g++.dg/modules/timevar-1_a.H b/gcc/testsuite/g++.dg/modules/timevar-1_a.H new file mode 100644 index ..efd7f0ecced0 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/timevar-1_a.H @@ -0,0 +1,14 @@ +// PR c++/115165 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +template struct A { virtual ~A(); }; +struct B : A {}; +struct C : B { C() {} }; + +class D { C c; }; +void f(D); + +struct X { + friend void f(X); +}; diff --git a/gcc/testsuite/g++.dg/modules/timevar-1_b.C b/gcc/testsuite/g++.dg/modules/timevar-1_b.C new file mode 100644 index ..645f01697eb7 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/timevar-1_b.C @@ -0,0 +1,10 @@ +// PR c++/115165 +// { dg-additional-options "-fmodules-ts -ftime-report" } +// { dg-allow-blank-lines-in-output 1 } +// { dg-prune-output "Time variable" } +// { dg-prune-output "\[0-9\]+%" } +// { dg-prune-output "TOTAL" } +// { dg-prune-output "checks" } + +import "timevar-1_a.H"; +X x;
[gcc r15-2121] c++/modules: Conditionally start timer during lazy load [PR115165]
https://gcc.gnu.org/g:b7b2434cc7e712dc5055bde02c441393ae881f06 commit r15-2121-gb7b2434cc7e712dc5055bde02c441393ae881f06 Author: Nathaniel Shead Date: Sun Jul 7 23:19:52 2024 +1000 c++/modules: Conditionally start timer during lazy load [PR115165] While lazy loading, instantiation of pendings can sometimes recursively perform name lookup and begin further lazy loading. When using the '-ftime-report' functionality this causes ICEs as we could start an already-running timer for the importing. This patch fixes the issue by using the 'timevar_cond*' API instead to support such recursive calls. PR c++/115165 gcc/cp/ChangeLog: * module.cc (lazy_load_binding): Use 'timevar_cond*' APIs. (lazy_load_pendings): Likewise. gcc/testsuite/ChangeLog: * g++.dg/modules/timevar-1_a.H: New test. * g++.dg/modules/timevar-1_b.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 8 gcc/testsuite/g++.dg/modules/timevar-1_a.H | 14 ++ gcc/testsuite/g++.dg/modules/timevar-1_b.C | 10 ++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index d385b422168f..69764fd772d3 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -19604,7 +19604,7 @@ lazy_load_binding (unsigned mod, tree ns, tree id, binding_slot *mslot) { int count = errorcount + warningcount; - timevar_start (TV_MODULE_IMPORT); + bool timer_running = timevar_cond_start (TV_MODULE_IMPORT); /* Make sure lazy loading from a template context behaves as if from a non-template context. */ @@ -19634,7 +19634,7 @@ lazy_load_binding (unsigned mod, tree ns, tree id, binding_slot *mslot) function_depth--; - timevar_stop (TV_MODULE_IMPORT); + timevar_cond_stop (TV_MODULE_IMPORT, timer_running); if (!ok) fatal_error (input_location, @@ -19673,7 +19673,7 @@ lazy_load_pendings (tree decl) int count = errorcount + warningcount; - timevar_start (TV_MODULE_IMPORT); + bool timer_running = timevar_cond_start (TV_MODULE_IMPORT); bool ok = !recursive_lazy (); if (ok) { @@ -19707,7 +19707,7 @@ lazy_load_pendings (tree decl) function_depth--; } - timevar_stop (TV_MODULE_IMPORT); + timevar_cond_stop (TV_MODULE_IMPORT, timer_running); if (!ok) fatal_error (input_location, "failed to load pendings for %<%E%s%E%>", diff --git a/gcc/testsuite/g++.dg/modules/timevar-1_a.H b/gcc/testsuite/g++.dg/modules/timevar-1_a.H new file mode 100644 index ..efd7f0ecced0 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/timevar-1_a.H @@ -0,0 +1,14 @@ +// PR c++/115165 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +template struct A { virtual ~A(); }; +struct B : A {}; +struct C : B { C() {} }; + +class D { C c; }; +void f(D); + +struct X { + friend void f(X); +}; diff --git a/gcc/testsuite/g++.dg/modules/timevar-1_b.C b/gcc/testsuite/g++.dg/modules/timevar-1_b.C new file mode 100644 index ..645f01697eb7 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/timevar-1_b.C @@ -0,0 +1,10 @@ +// PR c++/115165 +// { dg-additional-options "-fmodules-ts -ftime-report" } +// { dg-allow-blank-lines-in-output 1 } +// { dg-prune-output "Time variable" } +// { dg-prune-output "\[0-9\]+%" } +// { dg-prune-output "TOTAL" } +// { dg-prune-output "checks" } + +import "timevar-1_a.H"; +X x;
[gcc r14-10442] c++/modules: Propagate BINDING_VECTOR_*_DUPS_P on realloc [PR99242]
https://gcc.gnu.org/g:5fad0b552c5851fb6ae6eb3616e50cc25af1391d commit r14-10442-g5fad0b552c5851fb6ae6eb3616e50cc25af1391d Author: Nathaniel Shead Date: Mon Jul 8 22:25:17 2024 +1000 c++/modules: Propagate BINDING_VECTOR_*_DUPS_P on realloc [PR99242] When importing modules, when a binding vector for a name runs out of slots it gets reallocated with a larger size, and existing bindings are copied across. However, the flags to indicate whether deduping needs to occur did not: this causes ICEs, as it allows a duplicate binding to be added which then violates assumptions later on. PR c++/99242 gcc/cp/ChangeLog: * name-lookup.cc (append_imported_binding_slot): Propagate dups flags. gcc/testsuite/ChangeLog: * g++.dg/modules/pr99242_a.H: New test. * g++.dg/modules/pr99242_b.H: New test. * g++.dg/modules/pr99242_c.H: New test. * g++.dg/modules/pr99242_d.C: New test. Signed-off-by: Nathaniel Shead (cherry picked from commit 1aa0f1627857c3e2d90982bdb07ca78ca10b26f3) Diff: --- gcc/cp/name-lookup.cc| 4 gcc/testsuite/g++.dg/modules/pr99242_a.H | 3 +++ gcc/testsuite/g++.dg/modules/pr99242_b.H | 3 +++ gcc/testsuite/g++.dg/modules/pr99242_c.H | 3 +++ gcc/testsuite/g++.dg/modules/pr99242_d.C | 7 +++ 5 files changed, 20 insertions(+) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 4dffc0e9acc8..b752598564a3 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -352,6 +352,10 @@ append_imported_binding_slot (tree *slot, tree name, unsigned ix) tree new_vec = make_binding_vec (name, want); BINDING_VECTOR_NUM_CLUSTERS (new_vec) = have + 1; + BINDING_VECTOR_GLOBAL_DUPS_P (new_vec) + = BINDING_VECTOR_GLOBAL_DUPS_P (*slot); + BINDING_VECTOR_PARTITION_DUPS_P (new_vec) + = BINDING_VECTOR_PARTITION_DUPS_P (*slot); memcpy (BINDING_VECTOR_CLUSTER_BASE (new_vec), BINDING_VECTOR_CLUSTER_BASE (*slot), have * sizeof (binding_cluster)); diff --git a/gcc/testsuite/g++.dg/modules/pr99242_a.H b/gcc/testsuite/g++.dg/modules/pr99242_a.H new file mode 100644 index ..2df0b4184ab3 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99242_a.H @@ -0,0 +1,3 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } +bool __is_constant_evaluated(); diff --git a/gcc/testsuite/g++.dg/modules/pr99242_b.H b/gcc/testsuite/g++.dg/modules/pr99242_b.H new file mode 100644 index ..2df0b4184ab3 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99242_b.H @@ -0,0 +1,3 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } +bool __is_constant_evaluated(); diff --git a/gcc/testsuite/g++.dg/modules/pr99242_c.H b/gcc/testsuite/g++.dg/modules/pr99242_c.H new file mode 100644 index ..2df0b4184ab3 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99242_c.H @@ -0,0 +1,3 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } +bool __is_constant_evaluated(); diff --git a/gcc/testsuite/g++.dg/modules/pr99242_d.C b/gcc/testsuite/g++.dg/modules/pr99242_d.C new file mode 100644 index ..1046d1af9846 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99242_d.C @@ -0,0 +1,7 @@ +// { dg-additional-options "-fmodules-ts" } +bool __is_constant_evaluated(); +import "pr99242_a.H"; +void f() { __is_constant_evaluated(); } +import "pr99242_b.H"; +import "pr99242_c.H"; +void g() { __is_constant_evaluated(); }
[gcc r15-2079] c++/modules: Propagate BINDING_VECTOR_*_DUPS_P on realloc [PR99242]
https://gcc.gnu.org/g:1aa0f1627857c3e2d90982bdb07ca78ca10b26f3 commit r15-2079-g1aa0f1627857c3e2d90982bdb07ca78ca10b26f3 Author: Nathaniel Shead Date: Mon Jul 8 22:25:17 2024 +1000 c++/modules: Propagate BINDING_VECTOR_*_DUPS_P on realloc [PR99242] When importing modules, when a binding vector for a name runs out of slots it gets reallocated with a larger size, and existing bindings are copied across. However, the flags to indicate whether deduping needs to occur did not: this causes ICEs, as it allows a duplicate binding to be added which then violates assumptions later on. PR c++/99242 gcc/cp/ChangeLog: * name-lookup.cc (append_imported_binding_slot): Propagate dups flags. gcc/testsuite/ChangeLog: * g++.dg/modules/pr99242_a.H: New test. * g++.dg/modules/pr99242_b.H: New test. * g++.dg/modules/pr99242_c.H: New test. * g++.dg/modules/pr99242_d.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/name-lookup.cc| 4 gcc/testsuite/g++.dg/modules/pr99242_a.H | 3 +++ gcc/testsuite/g++.dg/modules/pr99242_b.H | 3 +++ gcc/testsuite/g++.dg/modules/pr99242_c.H | 3 +++ gcc/testsuite/g++.dg/modules/pr99242_d.C | 7 +++ 5 files changed, 20 insertions(+) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 361dc3d953d1..8823ab71c600 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -353,6 +353,10 @@ append_imported_binding_slot (tree *slot, tree name, unsigned ix) tree new_vec = make_binding_vec (name, want); BINDING_VECTOR_NUM_CLUSTERS (new_vec) = have + 1; + BINDING_VECTOR_GLOBAL_DUPS_P (new_vec) + = BINDING_VECTOR_GLOBAL_DUPS_P (*slot); + BINDING_VECTOR_PARTITION_DUPS_P (new_vec) + = BINDING_VECTOR_PARTITION_DUPS_P (*slot); memcpy (BINDING_VECTOR_CLUSTER_BASE (new_vec), BINDING_VECTOR_CLUSTER_BASE (*slot), have * sizeof (binding_cluster)); diff --git a/gcc/testsuite/g++.dg/modules/pr99242_a.H b/gcc/testsuite/g++.dg/modules/pr99242_a.H new file mode 100644 index ..2df0b4184ab3 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99242_a.H @@ -0,0 +1,3 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } +bool __is_constant_evaluated(); diff --git a/gcc/testsuite/g++.dg/modules/pr99242_b.H b/gcc/testsuite/g++.dg/modules/pr99242_b.H new file mode 100644 index ..2df0b4184ab3 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99242_b.H @@ -0,0 +1,3 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } +bool __is_constant_evaluated(); diff --git a/gcc/testsuite/g++.dg/modules/pr99242_c.H b/gcc/testsuite/g++.dg/modules/pr99242_c.H new file mode 100644 index ..2df0b4184ab3 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99242_c.H @@ -0,0 +1,3 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } +bool __is_constant_evaluated(); diff --git a/gcc/testsuite/g++.dg/modules/pr99242_d.C b/gcc/testsuite/g++.dg/modules/pr99242_d.C new file mode 100644 index ..1046d1af9846 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99242_d.C @@ -0,0 +1,7 @@ +// { dg-additional-options "-fmodules-ts" } +bool __is_constant_evaluated(); +import "pr99242_a.H"; +void f() { __is_constant_evaluated(); } +import "pr99242_b.H"; +import "pr99242_c.H"; +void g() { __is_constant_evaluated(); }
[gcc r15-2005] c++/modules: Add testcase for fixed issue with usings [PR115798]
https://gcc.gnu.org/g:13757e50ff0b4e0dccfabc67b1322a2724bf3a5c commit r15-2005-g13757e50ff0b4e0dccfabc67b1322a2724bf3a5c Author: Nathaniel Shead Date: Fri Jul 12 22:59:19 2024 +1000 c++/modules: Add testcase for fixed issue with usings [PR115798] This issue was fixed by r15-2003-gd6bf4b1c932211, but seems worth adding to the testsuite. PR c++/115798 gcc/testsuite/ChangeLog: * g++.dg/modules/using-26_a.C: New test. * g++.dg/modules/using-26_b.C: New test. * g++.dg/modules/using-26_c.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/testsuite/g++.dg/modules/using-26_a.C | 15 +++ gcc/testsuite/g++.dg/modules/using-26_b.C | 10 ++ gcc/testsuite/g++.dg/modules/using-26_c.C | 9 + 3 files changed, 34 insertions(+) diff --git a/gcc/testsuite/g++.dg/modules/using-26_a.C b/gcc/testsuite/g++.dg/modules/using-26_a.C new file mode 100644 index ..adab83d42433 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-26_a.C @@ -0,0 +1,15 @@ +// PR c++/115798 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi base } + +module; +#include +export module base; + +export { + using ::int8_t; +} + +export namespace std { + using std::int8_t; +} diff --git a/gcc/testsuite/g++.dg/modules/using-26_b.C b/gcc/testsuite/g++.dg/modules/using-26_b.C new file mode 100644 index ..06ed599df41e --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-26_b.C @@ -0,0 +1,10 @@ +// PR c++/115798 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi xstd } + +export module xstd; +import base; + +export namespace std { + using std::int8_t; +} diff --git a/gcc/testsuite/g++.dg/modules/using-26_c.C b/gcc/testsuite/g++.dg/modules/using-26_c.C new file mode 100644 index ..68f45cacb82e --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-26_c.C @@ -0,0 +1,9 @@ +// PR c++/115798 +// { dg-additional-options "-fmodules-ts" } + +import xstd; +import base; + +int main() { + static_assert(__is_same(int8_t, std::int8_t)); +}
[gcc r15-2004] c++/modules: Handle redefinitions of using-decls
https://gcc.gnu.org/g:1f7a21c6e85d553e7b5114e5ca1395118478dddf commit r15-2004-g1f7a21c6e85d553e7b5114e5ca1395118478dddf Author: Nathaniel Shead Date: Fri Jul 5 13:52:01 2024 +1000 c++/modules: Handle redefinitions of using-decls This fixes an ICE exposed by supporting exported non-function using-decls. Sometimes when preparing to define a class, xref_tag will find a using-decl belonging to a different namespace, which triggers the checking_assert in modules handling. Ideally I feel that 'lookup_and_check_tag' should be told whether we're about to define the type and handle erroring on redefinitions itself to avoid this issue (and provide better diagnostics by acknowledging the using-declaration), but this is complicated with the current fragmentation of definition checking. So for this patch we just fixup the assertion and ensure that pushdecl properly errors on the conflicting declaration later. gcc/cp/ChangeLog: * decl.cc (xref_tag): Move assertion into condition. * name-lookup.cc (check_module_override): Check for conflicting types and using-decls. gcc/testsuite/ChangeLog: * g++.dg/modules/using-19_a.C: New test. * g++.dg/modules/using-19_b.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/decl.cc| 6 -- gcc/cp/name-lookup.cc | 32 +-- gcc/testsuite/g++.dg/modules/using-19_a.C | 18 + gcc/testsuite/g++.dg/modules/using-19_b.C | 10 ++ 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 4ffc9a6dad25..e7bb4fa30892 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -16737,12 +16737,14 @@ xref_tag (enum tag_types tag_code, tree name, if (CLASS_TYPE_P (t) && CLASSTYPE_IS_TEMPLATE (t)) maybe_tmpl = CLASSTYPE_TI_TEMPLATE (t); + /* FIXME: we should do a more precise check for redefinitions +of a conflicting using-declaration here, as these diagnostics +are not ideal. */ if (DECL_LANG_SPECIFIC (decl) && DECL_MODULE_IMPORT_P (decl) - && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL) + && CP_DECL_CONTEXT (decl) == current_namespace) { /* Push it into this TU's symbol slot. */ - gcc_checking_assert (current_namespace == CP_DECL_CONTEXT (decl)); if (maybe_tmpl != decl) /* We're in the template parm binding level. Pushtag has logic to slide under that, but we're diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index e5f8562105e1..361dc3d953d1 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -3782,18 +3782,30 @@ check_module_override (tree decl, tree mvec, bool hiding, /* Errors could cause there to be nothing. */ continue; + tree type = NULL_TREE; if (STAT_HACK_P (bind)) - /* We do not have to check STAT_TYPE here, the xref_tag -machinery deals with that problem. */ - bind = STAT_VISIBLE (bind); + { + /* If there was a matching STAT_TYPE here then xref_tag + should have found it, but we need to check anyway because + a conflicting using-declaration may exist. */ + if (STAT_TYPE_VISIBLE_P (bind)) + type = STAT_TYPE (bind); + bind = STAT_VISIBLE (bind); + } - for (ovl_iterator iter (bind); iter; ++iter) - if (!iter.using_p ()) - { - match = duplicate_decls (decl, *iter, hiding); - if (match) - goto matched; - } + if (type) + { + match = duplicate_decls (decl, strip_using_decl (type), hiding); + if (match) + goto matched; + } + + for (ovl_iterator iter (strip_using_decl (bind)); iter; ++iter) + { + match = duplicate_decls (decl, *iter, hiding); + if (match) + goto matched; + } } if (TREE_PUBLIC (scope) && TREE_PUBLIC (STRIP_TEMPLATE (decl)) diff --git a/gcc/testsuite/g++.dg/modules/using-19_a.C b/gcc/testsuite/g++.dg/modules/using-19_a.C new file mode 100644 index ..693a70ce7d46 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-19_a.C @@ -0,0 +1,18 @@ +// { dg-additional-options "-fmodules-ts -Wno-global-module" } +// { dg-module-cmi M } + +module; + +namespace hidden { + struct S {}; + enum E { e }; + void f(); +} + +export module M; +export namespace exposed { + using hidden::S; + using hidden::E; + using hidden::e; + using hidden::f; +} diff --git a/gcc/testsuite/g++.dg/modules/using-19_b.C b/gcc/testsuite/g++.dg/modules/using-19_b.C new file mode 100644 index ..dbe8d9f3c01e --- /dev/null ++
[gcc r15-2003] c++: Introduce USING_DECLs for non-function usings [PR114683]
https://gcc.gnu.org/g:d6bf4b1c93221118b3008a878ec508f6412dfc55 commit r15-2003-gd6bf4b1c93221118b3008a878ec508f6412dfc55 Author: Nathaniel Shead Date: Thu Jun 27 11:08:15 2024 +1000 c++: Introduce USING_DECLs for non-function usings [PR114683] With modules, a non-function using-declaration is not completely interchangable with the declaration that it refers to; in particular, such a using-declaration may be exported without revealing the name of the entity it refers to. This patch fixes this by building USING_DECLs for all using-declarations that bind a non-function from a different scope. These new decls can than have purviewness and exportingness attached to them without affecting the decl that they refer to. We do this for all such usings, not just usings that may be revealed in a module; this way we can verify the change in representation against the (more comprehensive) non-modules testsuites, and in a future patch we can use the locations of these using-decls to enhance relevant diagnostics. Another possible approach would be to reuse OVERLOADs for this, as is already done within add_binding_entity for modules. I didn't do this because lots of code (as well as the names of the accessors) makes assumptions that OVERLOADs refer to function overload sets, and so splitting this up reduced semantic burden and made it easier to avoid unintentional changes. This did mean that we need to move out the definitions of ovl_iterator::{purview,exporting}_p, because the structures for module decls are declared later on in cp-tree.h. Building USING_DECLs changed a couple of code paths when adjusting bindings; in particular, pushdecl recognises global using-declarations as usings now, and so checks fall through to update_binding. To not regress g++.dg/lookup/linkage2.C the checks for 'extern' declarations no longer were sufficient (they don't handle 'extern "C"'); but duplicate_decls performed all the relevant checks anyway. Otherwise in general we strip using-decls from all lookup_* functions where necessary. Over time for diagnostics purposes it would probably be good to slowly revert this (especially e.g. lookup_elaborated_type causes some diagnostic quality regressions here) but this patch doesn't do so to minimise churn. This patch also tries not to build USING_DECLs when just redeclaring an existing declaration, and instead reveals that declaration in-place. This requires reworking some logic handling CONST_DECLs in module streaming, since a non-using CONST_DECL may now be exported indepenently of its containing enum. 'add_binding_entity' needs to explicitly write the names of unscoped enumerators so that lazy loading will trigger when the name is found by name lookup; it does this by pretending that the enum declarations are always usings so that it doesn't double-write definitions. By also checking if the enumerator was marked purview/exported we can use that to override a non-purview/non-exported TYPE_DECL and ensure it's made visible regardless. When reading we should get the exported flag on the enumeration constant, and so should properly create a binding for it. We don't need to do anything to handle importedness as that checking is skipped for EK_USINGs. Some other places assume that module information for a CONST_DECL inherits module information from its containing type. This includes: - get_originating_module_decl, for determining if the name was imported or has module attachment; I don't /think/ this change should affect that, so I'm leaving this untouched. - binding_cmp, for sorting by exportedness; since now an enumerator could be exported without the containing decl being exported, we need to handle this here too. PR c++/114683 gcc/cp/ChangeLog: * cp-tree.h (class ovl_iterator): Move definitions of purview_p and exporting_p to name-lookup.cc. * module.cc (depset::hash::add_binding_entity): Strip using-decls. Remove workarounds. Handle CONST_DECLs with different purview/exported from their enum. (enum ct_bind_flags): Remove unnecessary cbf_wrapped flag. (module_state::write_cluster): Likewise. (module_state::read_cluster): Build USING_DECL for non-function usings. (binding_cmp): Handle CONST_DECLs with different purview and/or exported from their enum. (set_instantiating_module): Support CONST_DECLs. * name-lookup.cc (get_fixed_binding_slot): Strip USING_DECLs. (name_lookup::process_binding): Strip USING_DECLs. (name_lookup::process_module_binding): Remove workaround. (updat
[gcc r14-10407] c++/modules: Keep entity mapping info across duplicate_decls [PR99241]
https://gcc.gnu.org/g:08c2abffe0a903e8cf16b469813b7dd0fb41275a commit r14-10407-g08c2abffe0a903e8cf16b469813b7dd0fb41275a Author: Nathaniel Shead Date: Mon Jul 8 14:35:58 2024 +1000 c++/modules: Keep entity mapping info across duplicate_decls [PR99241] When duplicate_decls finds a match with an existing imported declaration, it clears DECL_LANG_SPECIFIC of the olddecl and replaces it with the contents of newdecl; this clears DECL_MODULE_ENTITY_P causing an ICE if the same declaration is imported again later. This fixes the issue by ensuring that the flag is transferred to newdecl before clearing so that it ends up on olddecl again. For future-proofing we also do the same with DECL_MODULE_KEYED_DECLS_P, though because we don't yet support textual redefinition merging we can't yet test this works as intended. I don't expect it's possible for a new declaration already to have extra keyed decls mismatching that of the old declaration though, so I don't do anything with 'keyed_map' at this time. PR c++/99241 gcc/cp/ChangeLog: * decl.cc (duplicate_decls): Merge module entity information. gcc/testsuite/ChangeLog: * g++.dg/modules/pr99241_a.H: New test. * g++.dg/modules/pr99241_b.H: New test. * g++.dg/modules/pr99241_c.C: New test. Signed-off-by: Nathaniel Shead (cherry picked from commit f04f9714fca40315360af109b9e5ca2305fd75db) Diff: --- gcc/cp/decl.cc | 10 ++ gcc/testsuite/g++.dg/modules/pr99241_a.H | 3 +++ gcc/testsuite/g++.dg/modules/pr99241_b.H | 3 +++ gcc/testsuite/g++.dg/modules/pr99241_c.C | 5 + 4 files changed, 21 insertions(+) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 568b2becd4d0..ca00e9aea201 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -3120,6 +3120,16 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (TREE_CODE (newdecl) == FIELD_DECL) DECL_PACKED (olddecl) = DECL_PACKED (newdecl); + /* Merge module entity mapping information. */ + if (DECL_LANG_SPECIFIC (olddecl) + && (DECL_MODULE_ENTITY_P (olddecl) + || DECL_MODULE_KEYED_DECLS_P (olddecl))) +{ + retrofit_lang_decl (newdecl); + DECL_MODULE_ENTITY_P (newdecl) = DECL_MODULE_ENTITY_P (olddecl); + DECL_MODULE_KEYED_DECLS_P (newdecl) = DECL_MODULE_KEYED_DECLS_P (olddecl); +} + /* The DECL_LANG_SPECIFIC information in OLDDECL will be replaced with that from NEWDECL below. */ if (DECL_LANG_SPECIFIC (olddecl)) diff --git a/gcc/testsuite/g++.dg/modules/pr99241_a.H b/gcc/testsuite/g++.dg/modules/pr99241_a.H new file mode 100644 index ..c7031f08eb5d --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99241_a.H @@ -0,0 +1,3 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } +void terminate(); diff --git a/gcc/testsuite/g++.dg/modules/pr99241_b.H b/gcc/testsuite/g++.dg/modules/pr99241_b.H new file mode 100644 index ..c7031f08eb5d --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99241_b.H @@ -0,0 +1,3 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } +void terminate(); diff --git a/gcc/testsuite/g++.dg/modules/pr99241_c.C b/gcc/testsuite/g++.dg/modules/pr99241_c.C new file mode 100644 index ..7f2b1bb43eae --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99241_c.C @@ -0,0 +1,5 @@ +// { dg-additional-options "-fmodules-ts -fno-module-lazy" } + +import "pr99241_a.H"; +void terminate(); +import "pr99241_b.H";
[gcc r15-1968] c++/modules: Keep entity mapping info across duplicate_decls [PR99241]
https://gcc.gnu.org/g:f04f9714fca40315360af109b9e5ca2305fd75db commit r15-1968-gf04f9714fca40315360af109b9e5ca2305fd75db Author: Nathaniel Shead Date: Mon Jul 8 14:35:58 2024 +1000 c++/modules: Keep entity mapping info across duplicate_decls [PR99241] When duplicate_decls finds a match with an existing imported declaration, it clears DECL_LANG_SPECIFIC of the olddecl and replaces it with the contents of newdecl; this clears DECL_MODULE_ENTITY_P causing an ICE if the same declaration is imported again later. This fixes the issue by ensuring that the flag is transferred to newdecl before clearing so that it ends up on olddecl again. For future-proofing we also do the same with DECL_MODULE_KEYED_DECLS_P, though because we don't yet support textual redefinition merging we can't yet test this works as intended. I don't expect it's possible for a new declaration already to have extra keyed decls mismatching that of the old declaration though, so I don't do anything with 'keyed_map' at this time. PR c++/99241 gcc/cp/ChangeLog: * decl.cc (duplicate_decls): Merge module entity information. gcc/testsuite/ChangeLog: * g++.dg/modules/pr99241_a.H: New test. * g++.dg/modules/pr99241_b.H: New test. * g++.dg/modules/pr99241_c.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/decl.cc | 10 ++ gcc/testsuite/g++.dg/modules/pr99241_a.H | 3 +++ gcc/testsuite/g++.dg/modules/pr99241_b.H | 3 +++ gcc/testsuite/g++.dg/modules/pr99241_c.C | 5 + 4 files changed, 21 insertions(+) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index d4c65a199329..edf4c155bf77 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -3139,6 +3139,16 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (TREE_CODE (newdecl) == FIELD_DECL) DECL_PACKED (olddecl) = DECL_PACKED (newdecl); + /* Merge module entity mapping information. */ + if (DECL_LANG_SPECIFIC (olddecl) + && (DECL_MODULE_ENTITY_P (olddecl) + || DECL_MODULE_KEYED_DECLS_P (olddecl))) +{ + retrofit_lang_decl (newdecl); + DECL_MODULE_ENTITY_P (newdecl) = DECL_MODULE_ENTITY_P (olddecl); + DECL_MODULE_KEYED_DECLS_P (newdecl) = DECL_MODULE_KEYED_DECLS_P (olddecl); +} + /* The DECL_LANG_SPECIFIC information in OLDDECL will be replaced with that from NEWDECL below. */ if (DECL_LANG_SPECIFIC (olddecl)) diff --git a/gcc/testsuite/g++.dg/modules/pr99241_a.H b/gcc/testsuite/g++.dg/modules/pr99241_a.H new file mode 100644 index ..c7031f08eb5d --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99241_a.H @@ -0,0 +1,3 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } +void terminate(); diff --git a/gcc/testsuite/g++.dg/modules/pr99241_b.H b/gcc/testsuite/g++.dg/modules/pr99241_b.H new file mode 100644 index ..c7031f08eb5d --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99241_b.H @@ -0,0 +1,3 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } +void terminate(); diff --git a/gcc/testsuite/g++.dg/modules/pr99241_c.C b/gcc/testsuite/g++.dg/modules/pr99241_c.C new file mode 100644 index ..7f2b1bb43eae --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99241_c.C @@ -0,0 +1,5 @@ +// { dg-additional-options "-fmodules-ts -fno-module-lazy" } + +import "pr99241_a.H"; +void terminate(); +import "pr99241_b.H";
[gcc r15-1882] c++: Simplify uses of LAMBDA_EXPR_EXTRA_SCOPE
https://gcc.gnu.org/g:24cb586cafd40f8fbea68641f97e3431ea76c1b8 commit r15-1882-g24cb586cafd40f8fbea68641f97e3431ea76c1b8 Author: Nathaniel Shead Date: Sat Jun 15 22:47:07 2024 +1000 c++: Simplify uses of LAMBDA_EXPR_EXTRA_SCOPE I noticed there already exists a getter to get the scope of a lambda from its type directly rather than needing to go via CLASSTYPE_LAMBDA_EXPR, we may as well use it. gcc/cp/ChangeLog: * module.cc (trees_out::get_merge_kind): Use LAMBDA_TYPE_EXTRA_SCOPE instead of LAMBDA_EXPR_EXTRA_SCOPE. (trees_out::key_mergeable): Likewise. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 7 ++- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index dc5d046f04d..da180244e03 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -10686,9 +10686,7 @@ trees_out::get_merge_kind (tree decl, depset *dep) g++.dg/modules/lambda-6_a.C. */ if (DECL_IMPLICIT_TYPEDEF_P (STRIP_TEMPLATE (decl)) && LAMBDA_TYPE_P (TREE_TYPE (decl))) - if (tree scope - = LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR -(TREE_TYPE (decl + if (tree scope = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl))) { /* Lambdas attached to fields are keyed to its class. */ if (TREE_CODE (scope) == FIELD_DECL) @@ -10993,8 +10991,7 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner, case MK_keyed: { gcc_checking_assert (LAMBDA_TYPE_P (TREE_TYPE (inner))); - tree scope = LAMBDA_EXPR_EXTRA_SCOPE (CLASSTYPE_LAMBDA_EXPR - (TREE_TYPE (inner))); + tree scope = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (inner)); gcc_checking_assert (TREE_CODE (scope) == VAR_DECL || TREE_CODE (scope) == FIELD_DECL || TREE_CODE (scope) == PARM_DECL
[gcc r15-964] c++/modules: Fix revealing with using-decls [PR114867]
https://gcc.gnu.org/g:85f15ea65a97686ad39af0c14b7dd9a9372e3a19 commit r15-964-g85f15ea65a97686ad39af0c14b7dd9a9372e3a19 Author: Nathaniel Shead Date: Sat Jun 1 01:14:44 2024 +1000 c++/modules: Fix revealing with using-decls [PR114867] This patch fixes a couple issues with the current handling of revealing declarations with using-decls. Firstly, doing 'remove_node' when handling function overload sets is not safe, because it not only mutates the OVERLOAD we're walking over but potentially any other references to this OVERLOAD that are cached from phase-1 template lookup. This causes the attached using-17 testcase to fail because the overload set in 'X::test()' no longer contains the 'ns::f(T)' template once instantiated at the end of the file. This patch works around this by simply not removing the old declaration. This does make the overload list potentially longer than it otherwise would have been, but only when re-exporting the same set of functions in a using-decl. Additionally, because 'ovl_insert' always prepends these newly inserted overloads, repeated exported using-decls won't continue to add declarations, as the first exported using-decl will be found before the original (unexported) declaration. Another, related, issue is that using-decls of GMF entities currently doesn't mark them as reachable unless they are also exported, and thus they may not be available in e.g. module implementation units. We solve this with a new flag on OVERLOADs set when they are declared within the module purview. This starts to run into the more general issue of handling using-decls of non-functions (see e.g. PR114863) but by just marking such GMF entities as purview we can work around this for now. This also allows us to get rid of the special-casing of exported using-decls in 'add_binding_entity', which was incorrect anyway: a non-exported using-decl still needs to be emitted anyway if it lives in the module purview, even if referring to a non-purview item. PR c++/114867 gcc/cp/ChangeLog: * cp-tree.h (OVL_PURVIEW_P): New. (ovl_iterator::purview_p): New. * module.cc (depset::hash::add_binding_entity): Only ignore entities not within module purview. Set OVL_PURVIEW_P on new OVERLOADs for emitted declarations. (module_state::read_cluster): Imported using-decls are always in purview, mark as OVL_PURVIEW_P. * name-lookup.h (enum WMB_Flags): New WMB_Purview flag. * name-lookup.cc (walk_module_binding): Set WMB_Purview as needed. (do_nonmember_using_decl): Don't remove from existing OVERLOADs. Also reveal non-exported decls. Also reveal 'extern "C"' decls. Add workaround to reveal non-function decls. * tree.cc (ovl_insert): Adjust to also set OVL_PURVIEW_P when needed. gcc/testsuite/ChangeLog: * g++.dg/modules/using-17_a.C: New test. * g++.dg/modules/using-17_b.C: New test. * g++.dg/modules/using-18_a.C: New test. * g++.dg/modules/using-18_b.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/cp-tree.h | 7 ++ gcc/cp/module.cc | 8 ++- gcc/cp/name-lookup.cc | 106 -- gcc/cp/name-lookup.h | 1 + gcc/cp/tree.cc| 12 ++-- gcc/testsuite/g++.dg/modules/using-17_a.C | 31 + gcc/testsuite/g++.dg/modules/using-17_b.C | 13 gcc/testsuite/g++.dg/modules/using-18_a.C | 29 gcc/testsuite/g++.dg/modules/using-18_b.C | 11 9 files changed, 161 insertions(+), 57 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6206482c602..565e4a9290e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -813,6 +813,8 @@ typedef struct ptrmem_cst * ptrmem_cst_t; #define OVL_LOOKUP_P(NODE) TREE_LANG_FLAG_4 (OVERLOAD_CHECK (NODE)) /* If set, this OVL_USING_P overload is exported. */ #define OVL_EXPORT_P(NODE) TREE_LANG_FLAG_5 (OVERLOAD_CHECK (NODE)) +/* If set, this OVL_USING_P overload is in the module purview. */ +#define OVL_PURVIEW_P(NODE)(OVERLOAD_CHECK (NODE)->base.public_flag) /* If set, this overload includes name-independent declarations. */ #define OVL_NAME_INDEPENDENT_DECL_P(NODE) \ TREE_LANG_FLAG_6 (OVERLOAD_CHECK (NODE)) @@ -887,6 +889,11 @@ class ovl_iterator { return (TREE_CODE (ovl) == USING_DECL || (TREE_CODE (ovl) == OVERLOAD && OVL_USING_P (ovl))); } + /* Whether this using is in the module purview. */ + bool purview_p () const + { +return OVL_PURVIEW_P (get_using ()); + } /* Whether this using is being exported. */ bool exporting_p () const { dif
[gcc r15-830] c++/modules: Improve diagnostic when redeclaring builtin in module [PR102345]
https://gcc.gnu.org/g:28b508233a12c13295f960a2cb8a4864879acfb4 commit r15-830-g28b508233a12c13295f960a2cb8a4864879acfb4 Author: Nathaniel Shead Date: Sat May 25 01:03:54 2024 +1000 c++/modules: Improve diagnostic when redeclaring builtin in module [PR102345] If a user mistakenly includes a standard library header within the module purview, they currently get a confusing "declaration conflicts with builtin" error. This patch updates the message to include "in module", to help guide the user towards the likely cause. PR c++/102345 gcc/cp/ChangeLog: * module.cc (module_may_redeclare): Update error message. gcc/testsuite/ChangeLog: * g++.dg/modules/enum-12.C: Test for updated error. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 8 +++- gcc/testsuite/g++.dg/modules/enum-12.C | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 6cd7d9e0b93..3f8f84bb9fd 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -19140,7 +19140,13 @@ module_may_redeclare (tree olddecl, tree newdecl) decl = newdecl ? newdecl : olddecl; location_t loc = newdecl ? DECL_SOURCE_LOCATION (newdecl) : input_location; if (DECL_IS_UNDECLARED_BUILTIN (olddecl)) -error_at (loc, "declaration %qD conflicts with builtin", decl); +{ + if (newdecl_attached_p) + error_at (loc, "declaring %qD in module %qs conflicts with builtin " + "in global module", decl, new_mod->get_flatname ()); + else + error_at (loc, "declaration %qD conflicts with builtin", decl); +} else if (DECL_LANG_SPECIFIC (old_inner) && DECL_MODULE_IMPORT_P (old_inner)) { auto_diagnostic_group d; diff --git a/gcc/testsuite/g++.dg/modules/enum-12.C b/gcc/testsuite/g++.dg/modules/enum-12.C index 064f220dedf..cf8f445e076 100644 --- a/gcc/testsuite/g++.dg/modules/enum-12.C +++ b/gcc/testsuite/g++.dg/modules/enum-12.C @@ -4,7 +4,7 @@ export module foo; namespace std { - enum class align_val_t : decltype(sizeof(int)) {}; // { dg-error "conflicts with builtin" } + enum class align_val_t : decltype(sizeof(int)) {}; // { dg-error "in module .foo. conflicts with builtin" } } // { dg-prune-output "not writing module" }
[gcc r14-10241] c++: Propagate using decls from partitions [PR114868]
https://gcc.gnu.org/g:782ad2033ea0709a25ef3e899cbb9491406146d5 commit r14-10241-g782ad2033ea0709a25ef3e899cbb9491406146d5 Author: Nathaniel Shead Date: Tue Apr 9 21:49:58 2024 +1000 c++: Propagate using decls from partitions [PR114868] The modules code currently neglects to set OVL_USING_P on the dependency created for a using-decl, which causes it not to remember that the OVL_EXPORT_P flag had been set on it when emitted from the primary interface unit. This patch ensures that it occurs. PR c++/114868 gcc/cp/ChangeLog: * module.cc (depset::hash::add_binding_entity): Propagate OVL_USING_P for using-declarations. gcc/testsuite/ChangeLog: * g++.dg/modules/using-15_a.C: New test. * g++.dg/modules/using-15_b.C: New test. * g++.dg/modules/using-15_c.C: New test. Signed-off-by: Nathaniel Shead (cherry picked from commit 0d0215b10dbbe39d655ceda4af283f288ec7680c) Diff: --- gcc/cp/module.cc | 6 ++ gcc/testsuite/g++.dg/modules/using-15_a.C | 14 ++ gcc/testsuite/g++.dg/modules/using-15_b.C | 6 ++ gcc/testsuite/g++.dg/modules/using-15_c.C | 8 4 files changed, 34 insertions(+) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 85c410aaa4c..b610b808240 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -13151,10 +13151,14 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) /* Ignore NTTP objects. */ return false; + bool unscoped_enum_const_p = false; if (!(flags & WMB_Using) && CP_DECL_CONTEXT (decl) != data->ns) { /* A using that lost its wrapper or an unscoped enum constant. */ + /* FIXME: Ensure that unscoped enums are differentiated from +'using enum' declarations when PR c++/114683 is fixed. */ + unscoped_enum_const_p = (TREE_CODE (decl) == CONST_DECL); flags = WMB_Flags (flags | WMB_Using); if (DECL_MODULE_EXPORT_P (TREE_CODE (decl) == CONST_DECL ? TYPE_NAME (TREE_TYPE (decl)) @@ -13215,6 +13219,8 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) if (flags & WMB_Using) { decl = ovl_make (decl, NULL_TREE); + if (!unscoped_enum_const_p) + OVL_USING_P (decl) = true; if (flags & WMB_Export) OVL_EXPORT_P (decl) = true; } diff --git a/gcc/testsuite/g++.dg/modules/using-15_a.C b/gcc/testsuite/g++.dg/modules/using-15_a.C new file mode 100644 index 000..3f4bb6c5914 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-15_a.C @@ -0,0 +1,14 @@ +// PR c++/114868 +// { dg-additional-options "-fmodules-ts -Wno-global-module" } +// { dg-module-cmi M:a } + +module; +namespace foo { + void a(); +} +export module M:a; + +namespace bar { + // propagate usings from partitions + export using foo::a; +} diff --git a/gcc/testsuite/g++.dg/modules/using-15_b.C b/gcc/testsuite/g++.dg/modules/using-15_b.C new file mode 100644 index 000..4b0cb745157 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-15_b.C @@ -0,0 +1,6 @@ +// PR c++/114868 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi M } + +export module M; +export import :a; diff --git a/gcc/testsuite/g++.dg/modules/using-15_c.C b/gcc/testsuite/g++.dg/modules/using-15_c.C new file mode 100644 index 000..74dd10a5413 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-15_c.C @@ -0,0 +1,8 @@ +// PR c++/114868 +// { dg-additional-options "-fmodules-ts" } +import M; + +int main() { + bar::a(); + foo::a(); // { dg-error "not been declared" } +}
[gcc r14-10240] c++: Fix instantiation of imported temploid friends [PR114275]
https://gcc.gnu.org/g:fd6fd88b1a93f4fb38f095688255ab5c00122810 commit r14-10240-gfd6fd88b1a93f4fb38f095688255ab5c00122810 Author: Nathaniel Shead Date: Mon Apr 29 17:00:13 2024 +1000 c++: Fix instantiation of imported temploid friends [PR114275] This patch fixes a number of issues with the handling of temploid friend declarations. The primary issue is that instantiations of friend declarations should attach the declaration to the same module as the befriending class, by [module.unit] p7.1 and [temp.friend] p2; this could be a different module from the current TU, and so needs special handling. The other main issue here is that we can't assume that just because name lookup didn't find a definition for a hidden class template, that it doesn't exist at all: it could be a non-exported entity that we've nevertheless streamed in from an imported module. We need to ensure that when instantiating template friend classes that we return the same TEMPLATE_DECL that we got from our imports, otherwise we will get later issues with 'duplicate_decls' (rightfully) complaining that they're different when trying to merge. This doesn't appear necessary for function templates due to the existing name lookup handling already finding these hidden declarations. (cherry-picked from commits b5f6a56940e70838a07e885de03a92e2bd64674a and ec2365e07537e8b17745d75c28a2b45bf33be119) PR c++/105320 PR c++/114275 gcc/cp/ChangeLog: * cp-tree.h (propagate_defining_module): Declare. (remove_defining_module): Declare. (lookup_imported_hidden_friend): Declare. * decl.cc (duplicate_decls): Also check if hidden decls can be redeclared in this module. Call remove_defining_module on to-be-freed newdecl. * module.cc (imported_temploid_friends): New. (init_modules): Initialize it. (trees_out::decl_value): Write it; don't consider imported temploid friends as attached to a module. (trees_in::decl_value): Read it for non-discarded decls. (get_originating_module_decl): Follow the owning decl for an imported temploid friend. (propagate_defining_module): New. (remove_defining_module): New. * name-lookup.cc (get_mergeable_namespace_binding): New. (lookup_imported_hidden_friend): New. * pt.cc (tsubst_friend_function): Propagate defining module for new friend functions. (tsubst_friend_class): Lookup imported hidden friends. Check for valid module attachment of existing names. Propagate defining module for new classes. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-friend-10_a.C: New test. * g++.dg/modules/tpl-friend-10_b.C: New test. * g++.dg/modules/tpl-friend-10_c.C: New test. * g++.dg/modules/tpl-friend-10_d.C: New test. * g++.dg/modules/tpl-friend-11_a.C: New test. * g++.dg/modules/tpl-friend-11_b.C: New test. * g++.dg/modules/tpl-friend-12_a.C: New test. * g++.dg/modules/tpl-friend-12_b.C: New test. * g++.dg/modules/tpl-friend-12_c.C: New test. * g++.dg/modules/tpl-friend-12_d.C: New test. * g++.dg/modules/tpl-friend-12_e.C: New test. * g++.dg/modules/tpl-friend-12_f.C: New test. * g++.dg/modules/tpl-friend-13_a.C: New test. * g++.dg/modules/tpl-friend-13_b.C: New test. * g++.dg/modules/tpl-friend-13_c.C: New test. * g++.dg/modules/tpl-friend-13_d.C: New test. * g++.dg/modules/tpl-friend-13_e.C: New test. * g++.dg/modules/tpl-friend-13_f.C: New test. * g++.dg/modules/tpl-friend-13_g.C: New test. * g++.dg/modules/tpl-friend-14_a.C: New test. * g++.dg/modules/tpl-friend-14_b.C: New test. * g++.dg/modules/tpl-friend-14_c.C: New test. * g++.dg/modules/tpl-friend-14_d.C: New test. * g++.dg/modules/tpl-friend-9.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Reviewed-by: Patrick Palka Diff: --- gcc/cp/cp-tree.h | 3 ++ gcc/cp/decl.cc | 41 -- gcc/cp/module.cc | 75 ++ gcc/cp/name-lookup.cc | 53 ++ gcc/cp/pt.cc | 32 ++- gcc/testsuite/g++.dg/modules/tpl-friend-10_a.C | 15 ++ gcc/testsuite/g++.dg/modules/tpl-friend-10_b.C | 5 ++ gcc/testsuite/g++.dg/modules/tpl-friend-10_c.C | 7 +++ gcc/testsuite/g++.dg/modules/tpl-friend-10_d.C | 8 +++ gcc/testsuite/g++.dg/modules/tpl-friend-11_a.C | 14 +
[gcc r14-10239] c++: Standardise errors for module_may_redeclare
https://gcc.gnu.org/g:557cddcc71c9025932b30f1f825dc600a82dfe03 commit r14-10239-g557cddcc71c9025932b30f1f825dc600a82dfe03 Author: Nathaniel Shead Date: Sun Apr 14 23:03:11 2024 +1000 c++: Standardise errors for module_may_redeclare Currently different places calling 'module_may_redeclare' all emit very similar but slightly different error messages, and handle different kinds of declarations differently. This patch makes the function perform its own error messages so that they're all in one place, and prepares it for use with temploid friends. gcc/cp/ChangeLog: * cp-tree.h (module_may_redeclare): Add default parameter. * decl.cc (duplicate_decls): Don't emit errors for failed module_may_redeclare. (xref_tag): Likewise. (start_enum): Likewise. * semantics.cc (begin_class_definition): Likewise. * module.cc (module_may_redeclare): Clean up logic. Emit error messages on failure. gcc/testsuite/ChangeLog: * g++.dg/modules/enum-12.C: Update error message. * g++.dg/modules/friend-5_b.C: Likewise. * g++.dg/modules/shadow-1_b.C: Likewise. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill (cherry picked from commit 2faf040335f9b49c33ba6d40cf317920f27ce431) Diff: --- gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.cc| 28 +-- gcc/cp/module.cc | 120 -- gcc/cp/semantics.cc | 6 +- gcc/testsuite/g++.dg/modules/enum-12.C| 2 +- gcc/testsuite/g++.dg/modules/friend-5_b.C | 2 +- gcc/testsuite/g++.dg/modules/shadow-1_b.C | 5 +- 7 files changed, 89 insertions(+), 76 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 64760a40215..d4a70807460 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7402,7 +7402,7 @@ inline bool module_exporting_p () extern module_state *get_module (tree name, module_state *parent = NULL, bool partition = false); -extern bool module_may_redeclare (tree decl); +extern bool module_may_redeclare (tree olddecl, tree newdecl = NULL); extern bool module_global_init_needed (); extern bool module_determine_import_inits (); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index fea66e838ce..93f81e42127 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -2279,18 +2279,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) && TREE_CODE (olddecl) != NAMESPACE_DECL && !hiding) { - if (!module_may_redeclare (olddecl)) - { - if (DECL_ARTIFICIAL (olddecl)) - error ("declaration %qD conflicts with builtin", newdecl); - else - { - error ("declaration %qD conflicts with import", newdecl); - inform (olddecl_loc, "import declared %q#D here", olddecl); - } - - return error_mark_node; - } + if (!module_may_redeclare (olddecl, newdecl)) + return error_mark_node; tree not_tmpl = STRIP_TEMPLATE (olddecl); if (DECL_LANG_SPECIFIC (not_tmpl) @@ -16633,12 +16623,7 @@ xref_tag (enum tag_types tag_code, tree name, { tree decl = TYPE_NAME (t); if (!module_may_redeclare (decl)) - { - auto_diagnostic_group d; - error ("cannot declare %qD in a different module", decl); - inform (DECL_SOURCE_LOCATION (decl), "previously declared here"); - return error_mark_node; - } + return error_mark_node; tree not_tmpl = STRIP_TEMPLATE (decl); if (DECL_LANG_SPECIFIC (not_tmpl) @@ -16986,12 +16971,7 @@ start_enum (tree name, tree enumtype, tree underlying_type, { tree decl = TYPE_NAME (enumtype); if (!module_may_redeclare (decl)) - { - auto_diagnostic_group d; - error ("cannot declare %qD in different module", decl); - inform (DECL_SOURCE_LOCATION (decl), "previously declared here"); - enumtype = error_mark_node; - } + enumtype = error_mark_node; else set_instantiating_module (decl); } diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 3bf863e15d4..c2f077d6fd8 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -19003,11 +19003,15 @@ get_importing_module (tree decl, bool flexible) return module->mod; } -/* Is it permissible to redeclare DECL. */ +/* Is it permissible to redeclare OLDDECL with NEWDECL. + + If NEWDECL is NULL, assumes that OLDDECL will be redeclared using + the current scope's module and attachment. */ bool -module_may_redeclare (tree decl) +module_may_redeclare (tree olddecl, tree newdecl) { + tree decl = olddecl; for (;;) { tree ctx = CP_DECL_CONTEXT (decl);
[gcc r15-824] c++/modules: Improve errors for bad module-directives [PR115200]
https://gcc.gnu.org/g:dae606a11eb99814e452b49241fa76f7678f53b8 commit r15-824-gdae606a11eb99814e452b49241fa76f7678f53b8 Author: Nathaniel Shead Date: Fri May 24 00:08:57 2024 +1000 c++/modules: Improve errors for bad module-directives [PR115200] This fixes an ICE when a module directive is not given at global scope. Although not explicitly mentioned, it seems implied from [basic.link] p1 and [module.global.frag] that a module-declaration must appear at the global scope after preprocessing. Apart from this the patch also slightly improves the errors given when accidentally using a module control-line in other situations where it is not expected. PR c++/115200 gcc/cp/ChangeLog: * parser.cc (cp_parser_error_1): Special-case unexpected module directives for better diagnostics. (cp_parser_module_declaration): Check that the module declaration is at global scope. (cp_parser_import_declaration): Sync error message with that in cp_parser_error_1. gcc/testsuite/ChangeLog: * g++.dg/modules/mod-decl-1.C: Update error messages. * g++.dg/modules/mod-decl-6.C: New test. * g++.dg/modules/mod-decl-7.C: New test. * g++.dg/modules/mod-decl-8.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/parser.cc | 26 +++--- gcc/testsuite/g++.dg/modules/mod-decl-1.C | 8 +--- gcc/testsuite/g++.dg/modules/mod-decl-6.C | 11 +++ gcc/testsuite/g++.dg/modules/mod-decl-7.C | 11 +++ gcc/testsuite/g++.dg/modules/mod-decl-8.C | 14 ++ 5 files changed, 64 insertions(+), 6 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 476ddc0d63a..779625144db 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -3230,6 +3230,19 @@ cp_parser_error_1 (cp_parser* parser, const char* gmsgid, return; } + if (cp_token_is_module_directive (token)) +{ + auto_diagnostic_group d; + error_at (token->location, "unexpected module directive"); + if (token->keyword != RID__EXPORT) + inform (token->location, "perhaps insert a line break after" + " %qs, or other disambiguation, to prevent this being" + " considered a module control-line", + (token->keyword == RID__MODULE) ? "module" : "import"); + cp_parser_skip_to_pragma_eol (parser, token); + return; +} + /* If this is actually a conflict marker, report it as such. */ if (token->type == CPP_LSHIFT || token->type == CPP_RSHIFT @@ -15135,12 +15148,19 @@ cp_parser_module_declaration (cp_parser *parser, module_parse mp_state, parser->lexer->in_pragma = true; cp_token *token = cp_lexer_consume_token (parser->lexer); + tree scope = current_scope (); if (flag_header_unit) { error_at (token->location, "module-declaration not permitted in header-unit"); goto skip_eol; } + else if (scope != global_namespace) +{ + error_at (token->location, "module-declaration must be at global scope"); + inform (DECL_SOURCE_LOCATION (scope), "scope opened here"); + goto skip_eol; +} else if (mp_state == MP_FIRST && !exporting && cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) { @@ -15217,9 +15237,9 @@ cp_parser_import_declaration (cp_parser *parser, module_parse mp_state, error_at (token->location, "post-module-declaration" " imports must be contiguous"); note_lexer: - inform (token->location, "perhaps insert a line break, or other" - " disambiguation, to prevent this being considered a" - " module control-line"); + inform (token->location, "perhaps insert a line break after" + " %, or other disambiguation, to prevent this" + " being considered a module control-line"); skip_eol: cp_parser_skip_to_pragma_eol (parser, token); } diff --git a/gcc/testsuite/g++.dg/modules/mod-decl-1.C b/gcc/testsuite/g++.dg/modules/mod-decl-1.C index 23d34483dd7..df398b3ef50 100644 --- a/gcc/testsuite/g++.dg/modules/mod-decl-1.C +++ b/gcc/testsuite/g++.dg/modules/mod-decl-1.C @@ -10,17 +10,19 @@ module foo.second; // { dg-error "only permitted as" } namespace Foo { -module third; // { dg-error "only permitted as" } +module third; // { dg-error "must be at global scope" } } struct Baz { - module forth; // { dg-error "expected" } + module forth; // { dg-error "unexpected module directive" } + // { dg-message "line break after .module." "" { target *-*-* } .-1 } }; void Bink () { - module fifth; // { dg-error "expected" } + module fifth; // { dg-error "unexpected module directive" } + // { dg-message "line break after .module." "" { target *-*-* } .-1 } } module a.; // { dg-error "only
[gcc r15-823] c++/modules: Remember that header units have CMIs
https://gcc.gnu.org/g:03531ec45f15aa187bbab7842a1eb6cf746a104b commit r15-823-g03531ec45f15aa187bbab7842a1eb6cf746a104b Author: Nathaniel Shead Date: Thu May 23 22:56:52 2024 +1000 c++/modules: Remember that header units have CMIs This appears to be an oversight in the definition of module_has_cmi_p. This change will allow us to use the function directly in more places that need to additional work only if generating a module CMI in the future, allowing us to do additional work only when we know we need it. gcc/cp/ChangeLog: * cp-tree.h (module_has_cmi_p): Also include header units. (module_maybe_has_cmi_p): Update comment. * module.cc (set_defining_module): Only need to track declarations for later exporting if the module may have a CMI. (set_defining_module_for_partial_spec): Likewise. * name-lookup.cc (pushdecl): Likewise. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/cp-tree.h | 7 +++ gcc/cp/module.cc | 4 ++-- gcc/cp/name-lookup.cc | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7ae5b876735..655850a9ab6 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7381,7 +7381,7 @@ inline bool module_interface_p () inline bool module_partition_p () { return module_kind & MK_PARTITION; } inline bool module_has_cmi_p () -{ return module_kind & (MK_INTERFACE | MK_PARTITION); } +{ return module_kind & (MK_INTERFACE | MK_PARTITION | MK_HEADER); } inline bool module_purview_p () { return module_kind & MK_PURVIEW; } @@ -7393,9 +7393,8 @@ inline bool named_module_purview_p () inline bool named_module_attach_p () { return named_module_p () && module_attach_p (); } -/* We don't know if this TU will have a CMI while parsing the GMF, - so tentatively assume that it might, for the purpose of determining - whether no-linkage decls could be used by an importer. */ +/* Like module_has_cmi_p, but tentatively assumes that this TU may have a + CMI if we haven't seen the module-declaration yet. */ inline bool module_maybe_has_cmi_p () { return module_has_cmi_p () || (named_module_p () && !module_purview_p ()); } diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 3ca963cb3e9..6cd7d9e0b93 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -19221,7 +19221,7 @@ set_defining_module (tree decl) gcc_checking_assert (!DECL_LANG_SPECIFIC (decl) || !DECL_MODULE_IMPORT_P (decl)); - if (module_p ()) + if (module_maybe_has_cmi_p ()) { /* We need to track all declarations within a module, not just those in the module purview, because we don't necessarily know yet if @@ -19261,7 +19261,7 @@ set_defining_module (tree decl) void set_defining_module_for_partial_spec (tree decl) { - if (module_p () + if (module_maybe_has_cmi_p () && DECL_IMPLICIT_TYPEDEF_P (decl) && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl))) vec_safe_push (partial_specializations, decl); diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 78f08acffaa..f1f8c19feb1 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -4103,7 +4103,7 @@ pushdecl (tree decl, bool hiding) if (level->kind == sk_namespace && TREE_PUBLIC (level->this_entity) - && module_p ()) + && module_maybe_has_cmi_p ()) maybe_record_mergeable_decl (slot, name, decl); } }
[gcc r15-822] c++/modules: Fix treatment of unnamed types
https://gcc.gnu.org/g:0173dcce92baa62a74929814a75edb75eeab1a54 commit r15-822-g0173dcce92baa62a74929814a75edb75eeab1a54 Author: Nathaniel Shead Date: Thu May 23 22:50:58 2024 +1000 c++/modules: Fix treatment of unnamed types In r14-9530 we relaxed "depending on type with no-linkage" errors for declarations that could actually be accessed from different TUs anyway. However, this also enabled it for unnamed types, which never work. In a normal module interface, an unnamed type is TU-local by [basic.link] p15.2, and so cannot be exposed or the program is ill-formed. We don't yet implement this checking but we should assume that we will later; currently supporting this actually causes ICEs when attempting to create the mangled name in some situations. For a header unit, by [module.import] p5.3 it is unspecified whether two TUs importing a header unit providing such a declaration are importing the same header unit. In this case, we would require name mangling changes to somehow allow the (anonymous) type exported by such a header unit to correspond across different TUs in the presence of other anonymous declarations, so for this patch just assume that this case would be an ODR violation instead. gcc/cp/ChangeLog: * tree.cc (no_linkage_check): Anonymous types can't be accessed in a different TU. gcc/testsuite/ChangeLog: * g++.dg/modules/linkage-1_a.C: Remove anonymous type test. * g++.dg/modules/linkage-1_b.C: Likewise. * g++.dg/modules/linkage-1_c.C: Likewise. * g++.dg/modules/linkage-2.C: Add note about anonymous types. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/tree.cc | 10 +- gcc/testsuite/g++.dg/modules/linkage-1_a.C | 4 gcc/testsuite/g++.dg/modules/linkage-1_b.C | 1 - gcc/testsuite/g++.dg/modules/linkage-1_c.C | 1 - gcc/testsuite/g++.dg/modules/linkage-2.C | 6 ++ 5 files changed, 7 insertions(+), 15 deletions(-) diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 0485a618c6c..fe3f034d000 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -2988,15 +2988,7 @@ no_linkage_check (tree t, bool relaxed_p) /* Only treat unnamed types as having no linkage if they're at namespace scope. This is core issue 966. */ if (TYPE_UNNAMED_P (t) && TYPE_NAMESPACE_SCOPE_P (t)) - { - if (relaxed_p - && TREE_PUBLIC (CP_TYPE_CONTEXT (t)) - && module_maybe_has_cmi_p ()) - /* This type could possibly be accessed outside this TU. */ - return NULL_TREE; - else - return t; - } + return t; for (r = CP_TYPE_CONTEXT (t); ; ) { diff --git a/gcc/testsuite/g++.dg/modules/linkage-1_a.C b/gcc/testsuite/g++.dg/modules/linkage-1_a.C index 750e31ff347..1d81312e94f 100644 --- a/gcc/testsuite/g++.dg/modules/linkage-1_a.C +++ b/gcc/testsuite/g++.dg/modules/linkage-1_a.C @@ -9,7 +9,3 @@ auto f() { } decltype(f()) g(); // { dg-warning "used but not defined" "" { target c++17_down } } export auto x = g(); - -struct {} s; -decltype(s) h(); // { dg-warning "used but not defined" "" { target c++17_down } } -export auto y = h(); diff --git a/gcc/testsuite/g++.dg/modules/linkage-1_b.C b/gcc/testsuite/g++.dg/modules/linkage-1_b.C index f23962d76b7..5bc0d1b888d 100644 --- a/gcc/testsuite/g++.dg/modules/linkage-1_b.C +++ b/gcc/testsuite/g++.dg/modules/linkage-1_b.C @@ -3,4 +3,3 @@ module M; decltype(f()) g() { return {}; } -decltype(s) h() { return {}; } diff --git a/gcc/testsuite/g++.dg/modules/linkage-1_c.C b/gcc/testsuite/g++.dg/modules/linkage-1_c.C index f1406b99032..9ff1491b67e 100644 --- a/gcc/testsuite/g++.dg/modules/linkage-1_c.C +++ b/gcc/testsuite/g++.dg/modules/linkage-1_c.C @@ -5,5 +5,4 @@ import M; int main() { auto a = x; - auto b = y; } diff --git a/gcc/testsuite/g++.dg/modules/linkage-2.C b/gcc/testsuite/g++.dg/modules/linkage-2.C index eb4d7b051af..d913d6a30fc 100644 --- a/gcc/testsuite/g++.dg/modules/linkage-2.C +++ b/gcc/testsuite/g++.dg/modules/linkage-2.C @@ -23,4 +23,10 @@ export void use() { h(); } +// Additionally, unnamed types have no linkage but are also TU-local, and thus +// cannot be exposed in a module interface unit. The non-TU-local entity 's' +// here is an exposure of this type, so this should be an error; we don't yet +// implement this checking however. +struct {} s; // { dg-error "TU-local" "" { xfail *-*-* } } + // { dg-prune-output "not writing module" }
[gcc r15-810] c++/modules: Ensure all partial specialisations are tracked [PR114947]
https://gcc.gnu.org/g:7fa0ffa4f789683ba80e93cd10546cb7bd2c3d8a commit r15-810-g7fa0ffa4f789683ba80e93cd10546cb7bd2c3d8a Author: Nathaniel Shead Date: Sun May 12 22:31:01 2024 +1000 c++/modules: Ensure all partial specialisations are tracked [PR114947] Constrained partial specialisations aren't all necessarily tracked on the instantiation table. The modules code uses a separate 'partial_specializations' table to track them instead to ensure that they get walked and emitted when emitting a module, but currently this does not always happen. The attached testcase fails in two ways. First, because the partial specialisation is just a declaration (and not a definition), 'set_defining_module' never ends up getting called on it and so it never gets added to the partial specialisation table. We fix this by ensuring that when partial specializations are created they always get added, and so we never miss one. To prevent adding partial specialisations multiple times we split this out as a new function. The second way it fails is that when exporting the primary interface for a module with partitions, we also re-walk the specializations of all imported partitions to merge them into a single BMI. So this patch ensures that after calling 'match_mergeable_specialization' we also ensure that if the name came from a partition it gets added to the specialization table so that a dependency is correctly created for it. PR c++/114947 gcc/cp/ChangeLog: * cp-tree.h (set_defining_module_for_partial_spec): Declare. * module.cc (trees_in::decl_value): Track partial specs coming from partitions. (set_defining_module): Don't track partial specialisations here anymore. (set_defining_module_for_partial_spec): New function. * pt.cc (process_partial_specialization): Call it. gcc/testsuite/ChangeLog: * g++.dg/modules/partial-4_a.C: New test. * g++.dg/modules/partial-4_b.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/cp-tree.h | 1 + gcc/cp/module.cc | 22 ++ gcc/cp/pt.cc | 2 ++ gcc/testsuite/g++.dg/modules/partial-4_a.C | 8 gcc/testsuite/g++.dg/modules/partial-4_b.C | 5 + 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ba9e848c177..7ae5b876735 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7420,6 +7420,7 @@ extern unsigned get_importing_module (tree, bool = false) ATTRIBUTE_PURE; /* Where current instance of the decl got declared/defined/instantiated. */ extern void set_instantiating_module (tree); extern void set_defining_module (tree); +extern void set_defining_module_for_partial_spec (tree); extern void maybe_key_decl (tree ctx, tree decl); extern void propagate_defining_module (tree decl, tree orig); extern void remove_defining_module (tree decl); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 520dd710549..3ca963cb3e9 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -8416,6 +8416,11 @@ trees_in::decl_value () add_mergeable_specialization (!is_type, &spec, decl, spec_flags); } + /* When making a CMI from a partition we're going to need to walk partial +specializations again, so make sure they're tracked. */ + if (state->is_partition () && (spec_flags & 2)) + set_defining_module_for_partial_spec (inner); + if (NAMESPACE_SCOPE_P (decl) && (mk == MK_named || mk == MK_unique || mk == MK_enum || mk == MK_friend_spec) @@ -19246,13 +19251,22 @@ set_defining_module (tree decl) vec_safe_push (class_members, decl); } } - else if (DECL_IMPLICIT_TYPEDEF_P (decl) - && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl))) - /* This is a partial or explicit specialization. */ - vec_safe_push (partial_specializations, decl); } } +/* Also remember DECL if it's a newly declared class template partial + specialization, because these are not necessarily added to the + instantiation tables. */ + +void +set_defining_module_for_partial_spec (tree decl) +{ + if (module_p () + && DECL_IMPLICIT_TYPEDEF_P (decl) + && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl))) +vec_safe_push (partial_specializations, decl); +} + void set_originating_module (tree decl, bool friend_p ATTRIBUTE_UNUSED) { diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index a95ce6eb3da..dfce1b3c359 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -5456,6 +5456,8 @@ process_partial_specialization (tree decl) gcc_checking_assert (!TI_PARTIAL_INFO (tinfo)); TI_PARTIAL_INFO (tinfo) = build_template_info (tmpl, NULL_TREE); + set_defining_modu
[gcc r15-762] c++: Strengthen checks on 'main'
https://gcc.gnu.org/g:292fc21a8d7aa2f16e61ac941e22ada6ddd85500 commit r15-762-g292fc21a8d7aa2f16e61ac941e22ada6ddd85500 Author: Nathaniel Shead Date: Sat May 11 22:25:44 2024 +1000 c++: Strengthen checks on 'main' This patch adds some missing requirements for legal main declarations, as according to [basic.start.main] p2. gcc/cp/ChangeLog: * decl.cc (grokfndecl): Check for main functions with language linkage or module attachment. (grokvardecl): Check for extern 'C' entities named main. gcc/testsuite/ChangeLog: * g++.dg/abi/main.C: Check pedwarn for main with linkage-spec. * g++.dg/modules/contracts-1_b.C: Don't declare main in named module. * g++.dg/modules/contracts-3_b.C: Likewise. * g++.dg/modules/contracts-4_d.C: Likewise. * g++.dg/modules/horcrux-1_a.C: Export declarations, so that... * g++.dg/modules/horcrux-1_b.C: Don't declare main in named module. * g++.dg/modules/main-1.C: New test. * g++.dg/parse/linkage5.C: New test. * g++.dg/parse/linkage6.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/decl.cc | 19 +++ gcc/testsuite/g++.dg/abi/main.C | 3 ++- gcc/testsuite/g++.dg/modules/contracts-1_b.C | 4 gcc/testsuite/g++.dg/modules/contracts-3_b.C | 4 gcc/testsuite/g++.dg/modules/contracts-4_d.C | 2 -- gcc/testsuite/g++.dg/modules/horcrux-1_a.C | 3 +++ gcc/testsuite/g++.dg/modules/horcrux-1_b.C | 2 +- gcc/testsuite/g++.dg/modules/main-1.C| 5 + gcc/testsuite/g++.dg/parse/linkage5.C| 14 ++ gcc/testsuite/g++.dg/parse/linkage6.C| 13 + 10 files changed, 53 insertions(+), 16 deletions(-) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 6fcab615d55..a992d54dc8f 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -10788,6 +10788,11 @@ grokfndecl (tree ctype, "cannot declare %<::main%> to be %qs", "consteval"); if (!publicp) error_at (location, "cannot declare %<::main%> to be static"); + if (current_lang_depth () != 0) + pedwarn (location, OPT_Wpedantic, "cannot declare %<::main%> with a" +" linkage specification"); + if (module_attach_p ()) + error_at (location, "cannot attach %<::main%> to a named module"); inlinep = 0; publicp = 1; } @@ -11287,10 +11292,16 @@ grokvardecl (tree type, DECL_INTERFACE_KNOWN (decl) = 1; if (DECL_NAME (decl) - && MAIN_NAME_P (DECL_NAME (decl)) - && scope == global_namespace) -error_at (DECL_SOURCE_LOCATION (decl), - "cannot declare %<::main%> to be a global variable"); + && MAIN_NAME_P (DECL_NAME (decl))) +{ + if (scope == global_namespace) + error_at (DECL_SOURCE_LOCATION (decl), + "cannot declare %<::main%> to be a global variable"); + else if (DECL_EXTERN_C_P (decl)) + error_at (DECL_SOURCE_LOCATION (decl), + "an entity named % cannot be declared with " + "C language linkage"); +} /* Check that the variable can be safely declared as a concept. Note that this also forbids explicit specializations. */ diff --git a/gcc/testsuite/g++.dg/abi/main.C b/gcc/testsuite/g++.dg/abi/main.C index 4c5f1ea213c..2797a16df5b 100644 --- a/gcc/testsuite/g++.dg/abi/main.C +++ b/gcc/testsuite/g++.dg/abi/main.C @@ -1,10 +1,11 @@ /* { dg-do compile } */ +/* { dg-additional-options "-Wno-error=pedantic" } /* Check if entry points get implicit C linkage. If they don't, compiler will * error on incompatible declarations */ int main(); -extern "C" int main(); +extern "C" int main(); // { dg-warning "linkage specification" } #ifdef __MINGW32__ diff --git a/gcc/testsuite/g++.dg/modules/contracts-1_b.C b/gcc/testsuite/g++.dg/modules/contracts-1_b.C index 30c15f6928b..aa36c8d6b1b 100644 --- a/gcc/testsuite/g++.dg/modules/contracts-1_b.C +++ b/gcc/testsuite/g++.dg/modules/contracts-1_b.C @@ -1,15 +1,11 @@ // { dg-module-do run } // { dg-additional-options "-fmodules-ts -fcontracts -fcontract-continuation-mode=on" } -module; #include -export module bar; -// { dg-module-cmi bar } import foo; template bool bar_fn_pre(T n) { printf("bar fn pre(%d)\n", n); return true; } -export template T bar_fn(T n) [[ pre: bar_fn_pre(n) && n > 0 ]] diff --git a/gcc/testsuite/g++.dg/modules/contracts-3_b.C b/gcc/testsuite/g++.dg/modules/contracts-3_b.C index b1d6375391b..1a29e2c3e5d 100644 --- a/gcc/testsuite/g++.dg/modules/contracts-3_b.C +++ b/gcc/testsuite/g++.dg/modules/contracts-3_b.C @@ -1,15 +1,11 @@ // { dg-module-do run } // { dg-additional-options "-fmodules-ts -fcontracts -fcontract-role=default:ignore,ignore,ignore" } -module; #include -export module bar; -// { dg-module-cmi bar } im
[gcc r14-10182] c++/modules: Stream unmergeable temporaries by value again [PR114856]
https://gcc.gnu.org/g:61a095b05c244a6e0b1aec36ee1607def00654ab commit r14-10182-g61a095b05c244a6e0b1aec36ee1607def00654ab Author: Nathaniel Shead Date: Tue Apr 30 22:29:57 2024 +1000 c++/modules: Stream unmergeable temporaries by value again [PR114856] In r14-9266-g2823b4d96d9ec4 I gave all temporary vars a DECL_CONTEXT, including those at namespace or global scope, so that they could be properly merged across importers. However, not all of these temporary vars are actually supposed to be mergeable. For instance, in the attached testcase we have an unnamed temporary var used in the NSDMI of a class member, which cannot properly merged -- but it also doesn't need to be, as it'll be thrown away when the class type itself is merged anyway. This patch reverts the change made above and instead makes a weaker adjustment that only causes temporary vars with linkage have a DECL_CONTEXT to merge from. This way these unnamed, "unmergeable" temporaries are properly streamed by value again. PR c++/114856 gcc/cp/ChangeLog: * call.cc (make_temporary_var_for_ref_to_temp): Set context for temporaries with linkage. * init.cc (create_temporary_var): Revert to only set context when in a function decl. gcc/testsuite/ChangeLog: * g++.dg/modules/pr114856.h: New test. * g++.dg/modules/pr114856_a.H: New test. * g++.dg/modules/pr114856_b.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Reviewed-by: Patrick Palka (cherry picked from commit e60032b382364897a58e67994baac896bcd03327) Diff: --- gcc/cp/call.cc| 3 +++ gcc/cp/init.cc| 2 +- gcc/testsuite/g++.dg/modules/pr114856.h | 12 gcc/testsuite/g++.dg/modules/pr114856_a.H | 5 + gcc/testsuite/g++.dg/modules/pr114856_b.C | 5 + 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index dbdd7c29fe88..38b9c4f08601 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -13800,6 +13800,9 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type) tree name = mangle_ref_init_variable (decl); DECL_NAME (var) = name; SET_DECL_ASSEMBLER_NAME (var, name); + + /* Set the context to make the variable mergeable in modules. */ + DECL_CONTEXT (var) = current_scope (); } else /* Create a new cleanup level if necessary. */ diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index a93ce00800c4..e758a8c8568b 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -4287,7 +4287,7 @@ create_temporary_var (tree type) TREE_USED (decl) = 1; DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; - DECL_CONTEXT (decl) = current_scope (); + DECL_CONTEXT (decl) = current_function_decl; return decl; } diff --git a/gcc/testsuite/g++.dg/modules/pr114856.h b/gcc/testsuite/g++.dg/modules/pr114856.h new file mode 100644 index ..b1a3c2cd8341 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr114856.h @@ -0,0 +1,12 @@ +// PR c++/114856 + +#include +struct A { + ~A(); +}; +struct V { + V(std::initializer_list); +}; +struct data { + V v{{}}; +}; diff --git a/gcc/testsuite/g++.dg/modules/pr114856_a.H b/gcc/testsuite/g++.dg/modules/pr114856_a.H new file mode 100644 index ..6195277dbde1 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr114856_a.H @@ -0,0 +1,5 @@ +// PR c++/114856 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +#include "pr114856.h" diff --git a/gcc/testsuite/g++.dg/modules/pr114856_b.C b/gcc/testsuite/g++.dg/modules/pr114856_b.C new file mode 100644 index ..f81dc8b81d5d --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr114856_b.C @@ -0,0 +1,5 @@ +// PR c++/114856 +// { dg-additional-options "-fmodules-ts" } + +#include "pr114856.h" +import "pr114856_a.H";
[gcc r15-310] c++/modules: Stream unmergeable temporaries by value again [PR114856]
https://gcc.gnu.org/g:e60032b382364897a58e67994baac896bcd03327 commit r15-310-ge60032b382364897a58e67994baac896bcd03327 Author: Nathaniel Shead Date: Tue Apr 30 22:29:57 2024 +1000 c++/modules: Stream unmergeable temporaries by value again [PR114856] In r14-9266-g2823b4d96d9ec4 I gave all temporary vars a DECL_CONTEXT, including those at namespace or global scope, so that they could be properly merged across importers. However, not all of these temporary vars are actually supposed to be mergeable. For instance, in the attached testcase we have an unnamed temporary var used in the NSDMI of a class member, which cannot properly merged -- but it also doesn't need to be, as it'll be thrown away when the class type itself is merged anyway. This patch reverts the change made above and instead makes a weaker adjustment that only causes temporary vars with linkage have a DECL_CONTEXT to merge from. This way these unnamed, "unmergeable" temporaries are properly streamed by value again. PR c++/114856 gcc/cp/ChangeLog: * call.cc (make_temporary_var_for_ref_to_temp): Set context for temporaries with linkage. * init.cc (create_temporary_var): Revert to only set context when in a function decl. gcc/testsuite/ChangeLog: * g++.dg/modules/pr114856.h: New test. * g++.dg/modules/pr114856_a.H: New test. * g++.dg/modules/pr114856_b.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Reviewed-by: Patrick Palka Diff: --- gcc/cp/call.cc| 3 +++ gcc/cp/init.cc| 2 +- gcc/testsuite/g++.dg/modules/pr114856.h | 12 gcc/testsuite/g++.dg/modules/pr114856_a.H | 5 + gcc/testsuite/g++.dg/modules/pr114856_b.C | 5 + 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 7c4ecf08c4bd..e058da7735fa 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -13802,6 +13802,9 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type) tree name = mangle_ref_init_variable (decl); DECL_NAME (var) = name; SET_DECL_ASSEMBLER_NAME (var, name); + + /* Set the context to make the variable mergeable in modules. */ + DECL_CONTEXT (var) = current_scope (); } else /* Create a new cleanup level if necessary. */ diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index c1b5b7425c9b..7bb98f445c37 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -4287,7 +4287,7 @@ create_temporary_var (tree type) TREE_USED (decl) = 1; DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; - DECL_CONTEXT (decl) = current_scope (); + DECL_CONTEXT (decl) = current_function_decl; return decl; } diff --git a/gcc/testsuite/g++.dg/modules/pr114856.h b/gcc/testsuite/g++.dg/modules/pr114856.h new file mode 100644 index ..b1a3c2cd8341 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr114856.h @@ -0,0 +1,12 @@ +// PR c++/114856 + +#include +struct A { + ~A(); +}; +struct V { + V(std::initializer_list); +}; +struct data { + V v{{}}; +}; diff --git a/gcc/testsuite/g++.dg/modules/pr114856_a.H b/gcc/testsuite/g++.dg/modules/pr114856_a.H new file mode 100644 index ..6195277dbde1 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr114856_a.H @@ -0,0 +1,5 @@ +// PR c++/114856 +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +#include "pr114856.h" diff --git a/gcc/testsuite/g++.dg/modules/pr114856_b.C b/gcc/testsuite/g++.dg/modules/pr114856_b.C new file mode 100644 index ..f81dc8b81d5d --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr114856_b.C @@ -0,0 +1,5 @@ +// PR c++/114856 +// { dg-additional-options "-fmodules-ts" } + +#include "pr114856.h" +import "pr114856_a.H";
[gcc r15-221] c++: Allow IS_FAKE_BASE_TYPE for union types [PR114954]
https://gcc.gnu.org/g:0c43c673b0d431ca02d83bf6fae9cd60e9a3d0a8 commit r15-221-g0c43c673b0d431ca02d83bf6fae9cd60e9a3d0a8 Author: Nathaniel Shead Date: Mon May 6 13:05:52 2024 +1000 c++: Allow IS_FAKE_BASE_TYPE for union types [PR114954] In some circumstances, unions can also have an __as_base type; we need to make sure that IS_FAKE_BASE_TYPE correctly recognises this. PR c++/114954 gcc/cp/ChangeLog: * cp-tree.h (IS_FAKE_BASE_TYPE): Also apply to unions. gcc/testsuite/ChangeLog: * g++.dg/modules/pr114954.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/cp-tree.h| 2 +- gcc/testsuite/g++.dg/modules/pr114954.C | 14 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4fadc9aaf48..db098c32f2d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2616,7 +2616,7 @@ struct GTY(()) lang_type { /* True iff NODE is the CLASSTYPE_AS_BASE version of some type. */ #define IS_FAKE_BASE_TYPE(NODE)\ - (TREE_CODE (NODE) == RECORD_TYPE \ + (RECORD_OR_UNION_TYPE_P (NODE) \ && TYPE_CONTEXT (NODE) && CLASS_TYPE_P (TYPE_CONTEXT (NODE))\ && CLASSTYPE_AS_BASE (TYPE_CONTEXT (NODE)) == (NODE)) diff --git a/gcc/testsuite/g++.dg/modules/pr114954.C b/gcc/testsuite/g++.dg/modules/pr114954.C new file mode 100644 index 000..a9787140808 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr114954.C @@ -0,0 +1,14 @@ +// PR c++/114954 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi main } + +export module main; + +template +union U { +private: + char a[N + 1]; + int b; +}; + +U<4> p;
[gcc r15-220] c++/modules: Fix dangling pointer with imported_temploid_friends
https://gcc.gnu.org/g:ec2365e07537e8b17745d75c28a2b45bf33be119 commit r15-220-gec2365e07537e8b17745d75c28a2b45bf33be119 Author: Nathaniel Shead Date: Fri May 3 19:36:17 2024 +1000 c++/modules: Fix dangling pointer with imported_temploid_friends I got notified by Linaro CI and by checking testresults that there seems to be some occasional failures in tpl-friend-4_b.C on some architectures and standards modes since r15-59-gb5f6a56940e708. I haven't been able to reproduce but looking at the backtrace I suspect the issue is that we're adding to the 'imported_temploid_friend' map a decl that is ultimately discarded, which then has its address reused by a later decl causing a failure in the assert in 'set_originating_module'. This patch fixes the problem by ensuring 'imported_temploid_friends' is correctly marked as a GTY root, and that 'duplicate_decls' properly removes entries from the map for declarations that it frees. PR c++/114275 gcc/cp/ChangeLog: * cp-tree.h (remove_defining_module): Declare. * decl.cc (duplicate_decls): Call remove_defining_module on to-be-freed newdecl. * module.cc (imported_temploid_friends): Mark as GTY root... (init_modules): ...and allocate from ggc. (trees_in::decl_value): Only track for declarations that won't be discarded. (remove_defining_module): New function. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Reviewed-by: Patrick Palka Diff: --- gcc/cp/cp-tree.h | 1 + gcc/cp/decl.cc | 4 gcc/cp/module.cc | 19 --- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 52d6841559c..4fadc9aaf48 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7420,6 +7420,7 @@ extern void set_instantiating_module (tree); extern void set_defining_module (tree); extern void maybe_key_decl (tree ctx, tree decl); extern void propagate_defining_module (tree decl, tree orig); +extern void remove_defining_module (tree decl); extern void mangle_module (int m, bool include_partition); extern void mangle_module_fini (); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 04a151c341c..b112b70659f 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -3340,6 +3340,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (flag_concepts) remove_constraints (newdecl); + /* And similarly for any module tracking data. */ + if (modules_p ()) +remove_defining_module (newdecl); + ggc_free (newdecl); return olddecl; diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 44dc81eed3e..520dd710549 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -2731,7 +2731,7 @@ static keyed_map_t *keyed_table; need to be attached to the same module as the temploid. This maps these decls to the temploid they are instantiated them, as there is no other easy way to get this information. */ -static hash_map *imported_temploid_friends; +static GTY((cache)) decl_tree_cache_map *imported_temploid_friends; // /* Tree streaming. The tree streaming is very specific to the tree @@ -8327,7 +8327,8 @@ trees_in::decl_value () if (TREE_CODE (inner) == FUNCTION_DECL || TREE_CODE (inner) == TYPE_DECL) if (tree owner = tree_node ()) - imported_temploid_friends->put (decl, owner); + if (is_new) + imported_temploid_friends->put (decl, owner); /* Regular typedefs will have a NULL TREE_TYPE at this point. */ unsigned tdef_flags = 0; @@ -19336,6 +19337,18 @@ propagate_defining_module (tree decl, tree orig) } } +/* DECL is being freed, clear data we don't need anymore. */ + +void +remove_defining_module (tree decl) +{ + if (!modules_p ()) +return; + + if (imported_temploid_friends) +imported_temploid_friends->remove (decl); +} + /* Create the flat name string. It is simplest to have it handy. */ void @@ -20550,7 +20563,7 @@ init_modules (cpp_reader *reader) entity_map = new entity_map_t (EXPERIMENT (1, 400)); vec_safe_reserve (entity_ary, EXPERIMENT (1, 400)); imported_temploid_friends - = new hash_map (EXPERIMENT (1, 400)); + = decl_tree_cache_map::create_ggc (EXPERIMENT (1, 400)); } #if CHECKING_P
[gcc r15-114] c++: Clear is_unbraced_* when parsing declaration_seq_opt [PR114917]
https://gcc.gnu.org/g:7317d62a1200dbd3685015e5d6b811497a27fe5f commit r15-114-g7317d62a1200dbd3685015e5d6b811497a27fe5f Author: Nathaniel Shead Date: Thu May 2 12:55:24 2024 +1000 c++: Clear is_unbraced_* when parsing declaration_seq_opt [PR114917] Currently we incorrectly retain "in_unbraced_linkage_specification_p" and "in_unbraced_export_declaration_p" when parsing a (braced) declaration-seq. This patch ensures that we clear these flags before parsing the toplevel declarations. Strictly speaking we don't need to save and restore the flags around the parsing because there's currently no way to provide new declarations within the unbraced context after the closing brace, but this patch does it anyway in case this ever changes and for consistency with other places that these flags are adjusted. PR c++/114917 gcc/cp/ChangeLog: * parser.cc (cp_parser_declaration_seq_opt): Clear parser->in_unbraced_* flags when parsing toplevel declarations. gcc/testsuite/ChangeLog: * g++.dg/modules/export-5_a.C: New test. * g++.dg/modules/export-5_b.C: New test. * g++.dg/parse/linkage4.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/parser.cc | 15 +++ gcc/testsuite/g++.dg/modules/export-5_a.C | 17 + gcc/testsuite/g++.dg/modules/export-5_b.C | 13 + gcc/testsuite/g++.dg/parse/linkage4.C | 11 +++ 4 files changed, 56 insertions(+) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 7c3cfcfcf4b..66ce161252c 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -15341,6 +15341,16 @@ cp_parser_module_export (cp_parser *parser) static void cp_parser_declaration_seq_opt (cp_parser* parser) { + bool saved_in_unbraced_linkage_specification_p += parser->in_unbraced_linkage_specification_p; + bool saved_in_unbraced_export_declaration_p += parser->in_unbraced_export_declaration_p; + + /* We're not in an unbraced linkage-specification + or export-declaration anymore. */ + parser->in_unbraced_linkage_specification_p = false; + parser->in_unbraced_export_declaration_p = false; + while (true) { cp_token *token = cp_lexer_peek_token (parser->lexer); @@ -15351,6 +15361,11 @@ cp_parser_declaration_seq_opt (cp_parser* parser) else cp_parser_toplevel_declaration (parser); } + + parser->in_unbraced_linkage_specification_p += saved_in_unbraced_linkage_specification_p; + parser->in_unbraced_export_declaration_p += saved_in_unbraced_export_declaration_p; } /* Parse a declaration. The distinction between name-declaration diff --git a/gcc/testsuite/g++.dg/modules/export-5_a.C b/gcc/testsuite/g++.dg/modules/export-5_a.C new file mode 100644 index 000..a325591ca8e --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/export-5_a.C @@ -0,0 +1,17 @@ +// PR c++/114917 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi M } + +export module M; + +export namespace ns { + template struct S {}; + template struct S { using a = int; }; + template <> struct S { using b = int; }; + template struct S; +}; + +export extern "C++" namespace ns { + template void foo() {} + template <> void foo() {} +} diff --git a/gcc/testsuite/g++.dg/modules/export-5_b.C b/gcc/testsuite/g++.dg/modules/export-5_b.C new file mode 100644 index 000..cb10e37c7fc --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/export-5_b.C @@ -0,0 +1,13 @@ +// PR c++/114917 +// { dg-additional-options "-fmodules-ts" } + +import M; + +int main() { + ns::S::a x{}; + ns::S::b y{}; + ns::S z{}; + + ns::foo(); + ns::foo(); +} diff --git a/gcc/testsuite/g++.dg/parse/linkage4.C b/gcc/testsuite/g++.dg/parse/linkage4.C new file mode 100644 index 000..10fcc77e9d5 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/linkage4.C @@ -0,0 +1,11 @@ +// PR c++/114917 +// { dg-do compile } + +extern "C++" namespace ns { + struct Incomplete; + Incomplete foo; // { dg-error "incomplete type" } +} + +extern "C" extern "C" { + static int bar; // { dg-bogus "invalid" } +}
[gcc r15-101] c++: Don't emit unused GMF partial specializations [PR114630]
https://gcc.gnu.org/g:02917ac4528e32d1b2d0da5f45ef5937c56942cd commit r15-101-g02917ac4528e32d1b2d0da5f45ef5937c56942cd Author: Nathaniel Shead Date: Thu Apr 11 19:15:35 2024 +1000 c++: Don't emit unused GMF partial specializations [PR114630] The change in r14-8408 to also emit partial specializations in the global module fragment caused the regression in the linked PR; this patch fixes this by restricting emitted GM partial specializations to those that are actually used. PR c++/114630 gcc/cp/ChangeLog: * module.cc (depset::hash::add_partial_entities): Mark GM specializations as unreached. (depset::hash::find_dependencies): Also reach entities in the DECL_TEMPLATE_SPECIALIZATIONS list. gcc/testsuite/ChangeLog: * g++.dg/modules/partial-3.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 75 gcc/testsuite/g++.dg/modules/partial-3.C | 20 + 2 files changed, 66 insertions(+), 29 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index f7725091f60..44dc81eed3e 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -13308,14 +13308,22 @@ depset::hash::add_partial_entities (vec *partial_classes) depset *dep = make_dependency (inner, depset::EK_DECL); if (dep->get_entity_kind () == depset::EK_REDIRECT) - /* We should have recorded the template as a partial - specialization. */ - gcc_checking_assert (dep->deps[0]->get_entity_kind () -== depset::EK_PARTIAL); + { + dep = dep->deps[0]; + /* We should have recorded the template as a partial +specialization. */ + gcc_checking_assert (dep->get_entity_kind () + == depset::EK_PARTIAL); + } else /* It was an explicit specialization, not a partial one. */ gcc_checking_assert (dep->get_entity_kind () == depset::EK_SPECIALIZATION); + + /* Only emit GM entities if reached. */ + if (!DECL_LANG_SPECIFIC (inner) + || !DECL_MODULE_PURVIEW_P (inner)) + dep->set_flag_bit (); } } @@ -13636,31 +13644,40 @@ depset::hash::find_dependencies (module_state *module) if (!walker.is_key_order () && TREE_CODE (decl) == TEMPLATE_DECL && !DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P (decl)) - /* Mark all the explicit & partial specializations as - reachable. */ - for (tree cons = DECL_TEMPLATE_INSTANTIATIONS (decl); -cons; cons = TREE_CHAIN (cons)) - { - tree spec = TREE_VALUE (cons); - if (TYPE_P (spec)) - spec = TYPE_NAME (spec); - int use_tpl; - node_template_info (spec, use_tpl); - if (use_tpl & 2) - { - depset *spec_dep = find_dependency (spec); - if (spec_dep->get_entity_kind () == EK_REDIRECT) - spec_dep = spec_dep->deps[0]; - if (spec_dep->is_unreached ()) - { - reached_unreached = true; - spec_dep->clear_flag_bit (); - dump (dumper::DEPEND) - && dump ("Reaching unreached specialization" - " %C:%N", TREE_CODE (spec), spec); - } - } - } + { + /* Mark all the explicit & partial specializations as +reachable. We search both specialization lists as some +constrained partial specializations for class types are +only found in DECL_TEMPLATE_SPECIALIZATIONS. */ + auto mark_reached = [this](tree spec) + { + if (TYPE_P (spec)) + spec = TYPE_NAME (spec); + int use_tpl; + node_template_info (spec, use_tpl); + if (use_tpl & 2) + { + depset *spec_dep = find_dependency (spec); + if (spec_dep->get_entity_kind () == EK_REDIRECT) + spec_dep = spec_dep->deps[0]; + if (spec_dep->is_unreached ()) + { + reached_unreached = true; + spec_dep->clear_flag_bit (); + dump (dumper::DEPEND) + && dump ("Reaching unreached specialization" +" %C:%N", TREE_CODE (spec), spe
[gcc r15-98] c++: Implement modules ABI for vtable emissions
https://gcc.gnu.org/g:ad30265ccfb211fca35789df2d1404cc12302219 commit r15-98-gad30265ccfb211fca35789df2d1404cc12302219 Author: Nathaniel Shead Date: Tue Apr 16 22:50:26 2024 +1000 c++: Implement modules ABI for vtable emissions This patch implements the changes described in https://github.com/itanium-cxx-abi/cxx-abi/pull/171. One restriction that is lifted in the ABI that hasn't been updated here is that the ABI no longer requires unique vtables to be emitted with vague linkage. I haven't changed this behaviour for this patch, but in the future we could look into changing the relevant target hook ('class_data_always_comdat') to default to 'false'. But the current behaviour is more forgiving to changes in key function identification. Since the ABI for vtables attached to named modules no longer depends on key methods, this also resolves the issue described in PR c++/105224. PR c++/105224 gcc/cp/ChangeLog: * class.cc (finish_struct_1): Also push classes attached to a module into the 'keyed_classes' list. * decl.cc (record_key_method_defined): Don't push classes attached to a named module into the 'keyed_classes' list. * module.cc (trees_in::read_class_def): Likewise. * decl2.cc (import_export_class): Uniquely emit vtables for non-template classes attached to a named module. (vtables_uniquely_emitted): New function. (import_export_decl): Update comments. Update with knowledge about new kinds of uniquely emitted vtables. gcc/testsuite/ChangeLog: * g++.dg/modules/virt-2_a.C: Update linkage requirements. * g++.dg/modules/virt-2_b.C: Likewise. * g++.dg/modules/virt-2_c.C: Likewise. * g++.dg/modules/virt-4_a.C: New test. * g++.dg/modules/virt-4_b.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/class.cc | 7 ++- gcc/cp/decl.cc | 8 ++- gcc/cp/decl2.cc | 102 +--- gcc/cp/module.cc| 12 ++-- gcc/testsuite/g++.dg/modules/virt-2_a.C | 3 - gcc/testsuite/g++.dg/modules/virt-2_b.C | 9 +-- gcc/testsuite/g++.dg/modules/virt-2_c.C | 10 ++-- gcc/testsuite/g++.dg/modules/virt-4_a.C | 31 ++ gcc/testsuite/g++.dg/modules/virt-4_b.C | 23 +++ 9 files changed, 151 insertions(+), 54 deletions(-) diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index 5f258729940..5ef7c71af61 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -7820,8 +7820,11 @@ finish_struct_1 (tree t) /* If a polymorphic class has no key method, we may emit the vtable in every translation unit where the class definition appears. If we're devirtualizing, we can look into the vtable even if we -aren't emitting it. */ - if (!CLASSTYPE_KEY_METHOD (t)) +aren't emitting it. + +Additionally, if the class is attached to a named module, make sure +to always emit the vtable in this TU. */ + if (!CLASSTYPE_KEY_METHOD (t) || module_attach_p ()) vec_safe_push (keyed_classes, t); } diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index df855334133..de0c02a39ee 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -18481,7 +18481,13 @@ record_key_method_defined (tree fndecl) { tree fnclass = DECL_CONTEXT (fndecl); if (fndecl == CLASSTYPE_KEY_METHOD (fnclass)) - vec_safe_push (keyed_classes, fnclass); + { + tree classdecl = TYPE_NAME (fnclass); + /* Classes attached to a named module are already handled. */ + if (!DECL_LANG_SPECIFIC (classdecl) + || !DECL_MODULE_ATTACH_P (classdecl)) + vec_safe_push (keyed_classes, fnclass); + } } } diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index b8dc55b51d9..1f84878b2b9 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -2422,17 +2422,26 @@ import_export_class (tree ctype) import_export = -1; else if (TYPE_POLYMORPHIC_P (ctype)) { - /* The ABI specifies that the virtual table and associated -information are emitted with the key method, if any. */ - tree method = CLASSTYPE_KEY_METHOD (ctype); - /* If weak symbol support is not available, then we must be -careful not to emit the vtable when the key function is -inline. An inline function can be defined in multiple -translation units. If we were to emit the vtable in each -translation unit containing a definition, we would get -multiple definition errors at link-time. */ - if (method && (flag_weak || ! DECL_DECLARED_INLINE_P (method))) - import_export = (DECL_REALLY_EXTERN (method) ? -1 : 1); + tree cdecl = TYPE_NAME (ctype); + if
[gcc r15-85] c++: Propagate using decls from partitions [PR114868]
https://gcc.gnu.org/g:0d0215b10dbbe39d655ceda4af283f288ec7680c commit r15-85-g0d0215b10dbbe39d655ceda4af283f288ec7680c Author: Nathaniel Shead Date: Tue Apr 9 21:49:58 2024 +1000 c++: Propagate using decls from partitions [PR114868] The modules code currently neglects to set OVL_USING_P on the dependency created for a using-decl, which causes it not to remember that the OVL_EXPORT_P flag had been set on it when emitted from the primary interface unit. This patch ensures that it occurs. PR c++/114868 gcc/cp/ChangeLog: * module.cc (depset::hash::add_binding_entity): Propagate OVL_USING_P for using-declarations. gcc/testsuite/ChangeLog: * g++.dg/modules/using-15_a.C: New test. * g++.dg/modules/using-15_b.C: New test. * g++.dg/modules/using-15_c.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 6 ++ gcc/testsuite/g++.dg/modules/using-15_a.C | 14 ++ gcc/testsuite/g++.dg/modules/using-15_b.C | 6 ++ gcc/testsuite/g++.dg/modules/using-15_c.C | 8 4 files changed, 34 insertions(+) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 5b8ff5bc483..fac0301d80e 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -13150,10 +13150,14 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) /* Ignore NTTP objects. */ return false; + bool unscoped_enum_const_p = false; if (!(flags & WMB_Using) && CP_DECL_CONTEXT (decl) != data->ns) { /* A using that lost its wrapper or an unscoped enum constant. */ + /* FIXME: Ensure that unscoped enums are differentiated from +'using enum' declarations when PR c++/114683 is fixed. */ + unscoped_enum_const_p = (TREE_CODE (decl) == CONST_DECL); flags = WMB_Flags (flags | WMB_Using); if (DECL_MODULE_EXPORT_P (TREE_CODE (decl) == CONST_DECL ? TYPE_NAME (TREE_TYPE (decl)) @@ -13214,6 +13218,8 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) if (flags & WMB_Using) { decl = ovl_make (decl, NULL_TREE); + if (!unscoped_enum_const_p) + OVL_USING_P (decl) = true; if (flags & WMB_Export) OVL_EXPORT_P (decl) = true; } diff --git a/gcc/testsuite/g++.dg/modules/using-15_a.C b/gcc/testsuite/g++.dg/modules/using-15_a.C new file mode 100644 index 000..3f4bb6c5914 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-15_a.C @@ -0,0 +1,14 @@ +// PR c++/114868 +// { dg-additional-options "-fmodules-ts -Wno-global-module" } +// { dg-module-cmi M:a } + +module; +namespace foo { + void a(); +} +export module M:a; + +namespace bar { + // propagate usings from partitions + export using foo::a; +} diff --git a/gcc/testsuite/g++.dg/modules/using-15_b.C b/gcc/testsuite/g++.dg/modules/using-15_b.C new file mode 100644 index 000..4b0cb745157 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-15_b.C @@ -0,0 +1,6 @@ +// PR c++/114868 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi M } + +export module M; +export import :a; diff --git a/gcc/testsuite/g++.dg/modules/using-15_c.C b/gcc/testsuite/g++.dg/modules/using-15_c.C new file mode 100644 index 000..74dd10a5413 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-15_c.C @@ -0,0 +1,8 @@ +// PR c++/114868 +// { dg-additional-options "-fmodules-ts" } +import M; + +int main() { + bar::a(); + foo::a(); // { dg-error "not been declared" } +}
[gcc r15-86] c++: Propagate hidden flag on decls from partitions
https://gcc.gnu.org/g:3032ebf0c9b769f02f494e97417a1b68ad59c884 commit r15-86-g3032ebf0c9b769f02f494e97417a1b68ad59c884 Author: Nathaniel Shead Date: Tue Apr 9 21:52:38 2024 +1000 c++: Propagate hidden flag on decls from partitions While working on some other fixes I noticed that the partition handling code used the wrong flag to propagate OVL_HIDDEN_P on exported bindings from partitions. This patch fixes that, and renames the flag to be clearer. gcc/cp/ChangeLog: * name-lookup.cc (walk_module_binding): Use the partition-specific hidden flag instead of the top-level decl_hidden. gcc/testsuite/ChangeLog: * g++.dg/modules/using-16_a.C: New test. * g++.dg/modules/using-16_b.C: New test. * g++.dg/modules/using-16_c.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/name-lookup.cc | 10 +- gcc/testsuite/g++.dg/modules/using-16_a.C | 11 +++ gcc/testsuite/g++.dg/modules/using-16_b.C | 12 gcc/testsuite/g++.dg/modules/using-16_c.C | 11 +++ 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 5d2319db43d..78f08acffaa 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -4290,19 +4290,19 @@ walk_module_binding (tree binding, bitmap partitions, count += callback (btype, flags, data); } - bool hidden = STAT_DECL_HIDDEN_P (bind); + bool part_hidden = STAT_DECL_HIDDEN_P (bind); for (ovl_iterator iter (MAYBE_STAT_DECL (STAT_DECL (bind))); iter; ++iter) { if (iter.hidden_p ()) - hidden = true; + part_hidden = true; gcc_checking_assert - (!(hidden && DECL_IS_UNDECLARED_BUILTIN (*iter))); + (!(part_hidden && DECL_IS_UNDECLARED_BUILTIN (*iter))); WMB_Flags flags = WMB_None; if (maybe_dups) flags = WMB_Flags (flags | WMB_Dups); - if (decl_hidden) + if (part_hidden) flags = WMB_Flags (flags | WMB_Hidden); if (iter.using_p ()) { @@ -4311,7 +4311,7 @@ walk_module_binding (tree binding, bitmap partitions, flags = WMB_Flags (flags | WMB_Export); } count += callback (*iter, flags, data); - hidden = false; + part_hidden = false; } } } diff --git a/gcc/testsuite/g++.dg/modules/using-16_a.C b/gcc/testsuite/g++.dg/modules/using-16_a.C new file mode 100644 index 000..25d8bca5d1c --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-16_a.C @@ -0,0 +1,11 @@ +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi M:S } + +export module M:S; + +namespace foo { + // propagate hidden from partitions + export struct S { +friend void f(S); + }; +}; diff --git a/gcc/testsuite/g++.dg/modules/using-16_b.C b/gcc/testsuite/g++.dg/modules/using-16_b.C new file mode 100644 index 000..3f704a913f4 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-16_b.C @@ -0,0 +1,12 @@ +// { dg-additional-options "-fmodules-ts -Wno-global-module" } +// { dg-module-cmi M } + +module; +namespace bar { + void f(int); +} +export module M; +export import :S; +namespace foo { + export using bar::f; +} diff --git a/gcc/testsuite/g++.dg/modules/using-16_c.C b/gcc/testsuite/g++.dg/modules/using-16_c.C new file mode 100644 index 000..5e46cd16013 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-16_c.C @@ -0,0 +1,11 @@ +// { dg-additional-options "-fmodules-ts" } +import M; + +int main() { + // this should be hidden and fail + foo::f(foo::S{}); // { dg-error "cannot convert" } + + // but these should be legal + foo::f(10); + f(foo::S{}); +}
[gcc r15-84] c++: Implement P2615 'Meaningful Exports' [PR107688]
https://gcc.gnu.org/g:79420dd344145819677b3f975bb305a778fcaf91 commit r15-84-g79420dd344145819677b3f975bb305a778fcaf91 Author: Nathaniel Shead Date: Mon Mar 4 23:58:30 2024 +1100 c++: Implement P2615 'Meaningful Exports' [PR107688] This clarifies which kinds of declarations may and may not be exported in various contexts. The patch additionally fixes up some small issues that were clarified by the paper. Most of the changes are with regards to export-declarations, which are applied for all standards modes that we support '-fmodules-ts' for. However there are also a couple of changes made to linkage specifiers ('extern "C"'); I've applied these as since C++20, to line up with when modules were actually introduced. PR c++/107688 gcc/cp/ChangeLog: * name-lookup.cc (push_namespace): Error when exporting namespace with internal linkage. * parser.h (struct cp_parser): Add new flag 'in_unbraced_export_declaration_p'. * parser.cc (cp_debug_parser): Print the new flag. (cp_parser_new): Initialise the new flag. (cp_parser_module_export): Set the new flag. (cp_parser_class_specifier): Clear and restore the new flag. (cp_parser_import_declaration): Imports can now appear directly in a linkage specification. (cp_parser_declaration): Categorise declarations as "name" or "special"; error on the later in contexts where the former is required. (cp_parser_class_head): Error when exporting a partial specialisation. gcc/testsuite/ChangeLog: * g++.dg/modules/contracts-1_a.C: Avoid now-illegal syntax. * g++.dg/modules/contracts-2_a.C: Likewise. * g++.dg/modules/contracts-3_a.C: Likewise. * g++.dg/modules/contracts-4_a.C: Likewise. * g++.dg/modules/lang-1_c.C: Clarify now-legal syntax. * g++.dg/modules/pr101582-1.C: Remove now-legal XFAILS. * g++.dg/template/crash71.C: Update error messages. * g++.dg/cpp2a/linkage-spec1.C: New test. * g++.dg/modules/export-3.C: New test. * g++.dg/modules/export-4_a.C: New test. * g++.dg/modules/export-4_b.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/name-lookup.cc| 10 ++- gcc/cp/parser.cc | 105 +-- gcc/cp/parser.h | 6 +- gcc/testsuite/g++.dg/cpp2a/linkage-spec1.C | 22 ++ gcc/testsuite/g++.dg/modules/contracts-1_a.C | 2 +- gcc/testsuite/g++.dg/modules/contracts-2_a.C | 2 +- gcc/testsuite/g++.dg/modules/contracts-3_a.C | 2 +- gcc/testsuite/g++.dg/modules/contracts-4_a.C | 2 +- gcc/testsuite/g++.dg/modules/export-3.C | 30 gcc/testsuite/g++.dg/modules/export-4_a.C| 23 ++ gcc/testsuite/g++.dg/modules/export-4_b.C| 13 gcc/testsuite/g++.dg/modules/lang-1_c.C | 2 +- gcc/testsuite/g++.dg/modules/pr101582-1.C| 8 +- gcc/testsuite/g++.dg/template/crash71.C | 4 +- 14 files changed, 197 insertions(+), 34 deletions(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 4dffc0e9acc..5d2319db43d 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -9143,8 +9143,14 @@ push_namespace (tree name, bool make_inline) { /* A public namespace is exported only if explicitly marked, or it contains exported entities. */ - if (TREE_PUBLIC (ns) && module_exporting_p ()) - DECL_MODULE_EXPORT_P (ns) = true; + if (module_exporting_p ()) + { + if (TREE_PUBLIC (ns)) + DECL_MODULE_EXPORT_P (ns) = true; + else if (!header_module_p ()) + error_at (input_location, + "exporting namespace with internal linkage"); + } if (module_purview_p ()) DECL_MODULE_PURVIEW_P (ns) = true; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index aefbffe8330..a2bc6f69000 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -560,6 +560,8 @@ cp_debug_parser (FILE *file, cp_parser *parser) & THIS_FORBIDDEN)); cp_debug_print_flag (file, "In unbraced linkage specification", parser->in_unbraced_linkage_specification_p); + cp_debug_print_flag (file, "In unbraced export declaration", + parser->in_unbraced_export_declaration_p); cp_debug_print_flag (file, "Parsing a declarator", parser->in_declarator_p); cp_debug_print_flag (file, "In template argument list", @@ -4425,6 +4427,9 @@ cp_parser_new (cp_lexer *lexer) /* We are not processing an `extern "C"' declaration. */ parser->in_unbraced_linkage_specification_p = false; + /* We aren't parsing an export-declara
[gcc r15-59] c++: Fix instantiation of imported temploid friends [PR114275]
https://gcc.gnu.org/g:b5f6a56940e70838a07e885de03a92e2bd64674a commit r15-59-gb5f6a56940e70838a07e885de03a92e2bd64674a Author: Nathaniel Shead Date: Mon Apr 29 17:00:13 2024 +1000 c++: Fix instantiation of imported temploid friends [PR114275] This patch fixes a number of issues with the handling of temploid friend declarations. The primary issue is that instantiations of friend declarations should attach the declaration to the same module as the befriending class, by [module.unit] p7.1 and [temp.friend] p2; this could be a different module from the current TU, and so needs special handling. The other main issue here is that we can't assume that just because name lookup didn't find a definition for a hidden class template, that it doesn't exist at all: it could be a non-exported entity that we've nevertheless streamed in from an imported module. We need to ensure that when instantiating template friend classes that we return the same TEMPLATE_DECL that we got from our imports, otherwise we will get later issues with 'duplicate_decls' (rightfully) complaining that they're different when trying to merge. This doesn't appear necessary for function templates due to the existing name lookup handling already finding these hidden declarations. PR c++/105320 PR c++/114275 gcc/cp/ChangeLog: * cp-tree.h (propagate_defining_module): Declare. (lookup_imported_hidden_friend): Declare. * decl.cc (duplicate_decls): Also check if hidden decls can be redeclared in this module. * module.cc (imported_temploid_friends): New. (init_modules): Initialize it. (trees_out::decl_value): Write it; don't consider imported temploid friends as attached to a module. (trees_in::decl_value): Read it. (get_originating_module_decl): Follow the owning decl for an imported temploid friend. (propagate_defining_module): New. * name-lookup.cc (get_mergeable_namespace_binding): New. (lookup_imported_hidden_friend): New. * pt.cc (tsubst_friend_function): Propagate defining module for new friend functions. (tsubst_friend_class): Lookup imported hidden friends. Check for valid module attachment of existing names. Propagate defining module for new classes. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-friend-10_a.C: New test. * g++.dg/modules/tpl-friend-10_b.C: New test. * g++.dg/modules/tpl-friend-10_c.C: New test. * g++.dg/modules/tpl-friend-10_d.C: New test. * g++.dg/modules/tpl-friend-11_a.C: New test. * g++.dg/modules/tpl-friend-11_b.C: New test. * g++.dg/modules/tpl-friend-12_a.C: New test. * g++.dg/modules/tpl-friend-12_b.C: New test. * g++.dg/modules/tpl-friend-12_c.C: New test. * g++.dg/modules/tpl-friend-12_d.C: New test. * g++.dg/modules/tpl-friend-12_e.C: New test. * g++.dg/modules/tpl-friend-12_f.C: New test. * g++.dg/modules/tpl-friend-13_a.C: New test. * g++.dg/modules/tpl-friend-13_b.C: New test. * g++.dg/modules/tpl-friend-13_c.C: New test. * g++.dg/modules/tpl-friend-13_d.C: New test. * g++.dg/modules/tpl-friend-13_e.C: New test. * g++.dg/modules/tpl-friend-13_f.C: New test. * g++.dg/modules/tpl-friend-13_g.C: New test. * g++.dg/modules/tpl-friend-14_a.C: New test. * g++.dg/modules/tpl-friend-14_b.C: New test. * g++.dg/modules/tpl-friend-14_c.C: New test. * g++.dg/modules/tpl-friend-14_d.C: New test. * g++.dg/modules/tpl-friend-9.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/cp-tree.h | 2 + gcc/cp/decl.cc | 37 --- gcc/cp/module.cc | 62 ++ gcc/cp/name-lookup.cc | 53 ++ gcc/cp/pt.cc | 29 +++- gcc/testsuite/g++.dg/modules/tpl-friend-10_a.C | 15 +++ gcc/testsuite/g++.dg/modules/tpl-friend-10_b.C | 5 +++ gcc/testsuite/g++.dg/modules/tpl-friend-10_c.C | 7 +++ gcc/testsuite/g++.dg/modules/tpl-friend-10_d.C | 8 gcc/testsuite/g++.dg/modules/tpl-friend-11_a.C | 14 ++ gcc/testsuite/g++.dg/modules/tpl-friend-11_b.C | 5 +++ gcc/testsuite/g++.dg/modules/tpl-friend-12_a.C | 10 + gcc/testsuite/g++.dg/modules/tpl-friend-12_b.C | 9 gcc/testsuite/g++.dg/modules/tpl-friend-12_c.C | 10 + gcc/testsuite/g++.dg/modules/tpl-friend-12_d.C | 8 gcc/testsuite/g++.dg/modules/tpl-friend-1
[gcc r15-58] c++: Standardise errors for module_may_redeclare
https://gcc.gnu.org/g:2faf040335f9b49c33ba6d40cf317920f27ce431 commit r15-58-g2faf040335f9b49c33ba6d40cf317920f27ce431 Author: Nathaniel Shead Date: Sun Apr 14 23:03:11 2024 +1000 c++: Standardise errors for module_may_redeclare Currently different places calling 'module_may_redeclare' all emit very similar but slightly different error messages, and handle different kinds of declarations differently. This patch makes the function perform its own error messages so that they're all in one place, and prepares it for use with temploid friends. gcc/cp/ChangeLog: * cp-tree.h (module_may_redeclare): Add default parameter. * decl.cc (duplicate_decls): Don't emit errors for failed module_may_redeclare. (xref_tag): Likewise. (start_enum): Likewise. * semantics.cc (begin_class_definition): Likewise. * module.cc (module_may_redeclare): Clean up logic. Emit error messages on failure. gcc/testsuite/ChangeLog: * g++.dg/modules/enum-12.C: Update error message. * g++.dg/modules/friend-5_b.C: Likewise. * g++.dg/modules/shadow-1_b.C: Likewise. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.cc| 28 +-- gcc/cp/module.cc | 120 -- gcc/cp/semantics.cc | 6 +- gcc/testsuite/g++.dg/modules/enum-12.C| 2 +- gcc/testsuite/g++.dg/modules/friend-5_b.C | 2 +- gcc/testsuite/g++.dg/modules/shadow-1_b.C | 5 +- 7 files changed, 89 insertions(+), 76 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bafdf63dc63..4ac8cf69869 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7401,7 +7401,7 @@ inline bool module_exporting_p () extern module_state *get_module (tree name, module_state *parent = NULL, bool partition = false); -extern bool module_may_redeclare (tree decl); +extern bool module_may_redeclare (tree olddecl, tree newdecl = NULL); extern bool module_global_init_needed (); extern bool module_determine_import_inits (); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 2af026d255d..91268ff631d 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -2279,18 +2279,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) && TREE_CODE (olddecl) != NAMESPACE_DECL && !hiding) { - if (!module_may_redeclare (olddecl)) - { - if (DECL_ARTIFICIAL (olddecl)) - error ("declaration %qD conflicts with builtin", newdecl); - else - { - error ("declaration %qD conflicts with import", newdecl); - inform (olddecl_loc, "import declared %q#D here", olddecl); - } - - return error_mark_node; - } + if (!module_may_redeclare (olddecl, newdecl)) + return error_mark_node; tree not_tmpl = STRIP_TEMPLATE (olddecl); if (DECL_LANG_SPECIFIC (not_tmpl) @@ -16626,12 +16616,7 @@ xref_tag (enum tag_types tag_code, tree name, { tree decl = TYPE_NAME (t); if (!module_may_redeclare (decl)) - { - auto_diagnostic_group d; - error ("cannot declare %qD in a different module", decl); - inform (DECL_SOURCE_LOCATION (decl), "previously declared here"); - return error_mark_node; - } + return error_mark_node; tree not_tmpl = STRIP_TEMPLATE (decl); if (DECL_LANG_SPECIFIC (not_tmpl) @@ -16979,12 +16964,7 @@ start_enum (tree name, tree enumtype, tree underlying_type, { tree decl = TYPE_NAME (enumtype); if (!module_may_redeclare (decl)) - { - auto_diagnostic_group d; - error ("cannot declare %qD in different module", decl); - inform (DECL_SOURCE_LOCATION (decl), "previously declared here"); - enumtype = error_mark_node; - } + enumtype = error_mark_node; else set_instantiating_module (decl); } diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 3bf863e15d4..c2f077d6fd8 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -19003,11 +19003,15 @@ get_importing_module (tree decl, bool flexible) return module->mod; } -/* Is it permissible to redeclare DECL. */ +/* Is it permissible to redeclare OLDDECL with NEWDECL. + + If NEWDECL is NULL, assumes that OLDDECL will be redeclared using + the current scope's module and attachment. */ bool -module_may_redeclare (tree decl) +module_may_redeclare (tree olddecl, tree newdecl) { + tree decl = olddecl; for (;;) { tree ctx = CP_DECL_CONTEXT (decl); @@ -19021,58 +19025,94 @@ module_may_redeclare (tree decl) decl = TYP
[gcc r14-10100] c++: Fix ICE with xobj parms and maybe incomplete decl-specifiers
https://gcc.gnu.org/g:7318f1a389769ab540f414fcba743e90051d466b commit r14-10100-g7318f1a389769ab540f414fcba743e90051d466b Author: Nathaniel Shead Date: Sat Apr 20 14:44:11 2024 +1000 c++: Fix ICE with xobj parms and maybe incomplete decl-specifiers This fixes a null dereference issue when decl_specifiers.type is not yet provided. gcc/cp/ChangeLog: * parser.cc (cp_parser_parameter_declaration): Check if decl_specifiers.type is null. gcc/testsuite/ChangeLog: * g++.dg/cpp23/explicit-obj-basic7.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/parser.cc | 5 +++-- gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C | 9 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index c23758cf5cf..598380dda08 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -25780,8 +25780,9 @@ cp_parser_parameter_declaration (cp_parser *parser, } if (xobj_param_p - && (declarator ? declarator->parameter_pack_p -: PACK_EXPANSION_P (decl_specifiers.type))) + && ((declarator && declarator->parameter_pack_p) + || (decl_specifiers.type + && PACK_EXPANSION_P (decl_specifiers.type { location_t xobj_param = make_location (decl_specifiers.locations[ds_this], diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C new file mode 100644 index 000..a474e97fc18 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-basic7.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++23 } } + +// Shouldn't ICE +struct S { + void a(this long); + void b(this const long); + void c(this long unsigned); + void c(this signed); +};
[gcc r14-10085] c++: Check if allocation functions are xobj members [PR114078]
https://gcc.gnu.org/g:cf51fe706ea0219beb5bb85e81606d372ca9635e commit r14-10085-gcf51fe706ea0219beb5bb85e81606d372ca9635e Author: Nathaniel Shead Date: Sat Apr 20 15:08:02 2024 +1000 c++: Check if allocation functions are xobj members [PR114078] A class allocation member function is implicitly 'static' by [class.free] p3, so cannot have an explicit object parameter. PR c++/114078 gcc/cp/ChangeLog: * decl.cc (grokdeclarator): Check allocation functions for xobj parameters. gcc/testsuite/ChangeLog: * g++.dg/cpp23/explicit-obj-ops-alloc.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/decl.cc | 6 ++ gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C | 11 +++ 2 files changed, 17 insertions(+) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 65ab64885ff..2af026d255d 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -13728,6 +13728,12 @@ grokdeclarator (const cp_declarator *declarator, inform (DECL_SOURCE_LOCATION (xobj_parm), "explicit object parameter declared here"); } + if (unqualified_id + && identifier_p (unqualified_id) + && IDENTIFIER_NEWDEL_OP_P (unqualified_id)) + error_at (DECL_SOURCE_LOCATION (xobj_parm), + "%qD cannot be an explicit object member " + "function", unqualified_id); } } tree pushed_scope = NULL_TREE; diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C new file mode 100644 index 000..8a277db7ef5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-ops-alloc.C @@ -0,0 +1,11 @@ +// PR c++/114078 +// { dg-do compile { target c++23 } } + +using size_t = decltype(sizeof(0)); + +struct S { + void* operator new(this size_t); // { dg-error "explicit object" } + void* operator new[](this size_t); // { dg-error "explicit object" } + void operator delete(this void*); // { dg-error "explicit object" } + void operator delete[](this void*); // { dg-error "explicit object" } +};
[gcc r14-9961] c++: Only emit exported GMF usings [PR114600]
https://gcc.gnu.org/g:3878e9aeb30cb192f769997c52743daf8190744c commit r14-9961-g3878e9aeb30cb192f769997c52743daf8190744c Author: Nathaniel Shead Date: Mon Apr 8 23:34:42 2024 +1000 c++: Only emit exported GMF usings [PR114600] A typo in r14-6978 made us emit too many things. This ensures that we don't emit using-declarations from the GMF that we don't need to. PR c++/114600 gcc/cp/ChangeLog: * module.cc (depset::hash::add_binding_entity): Require both WMB_Using and WMB_Export for GMF entities. gcc/testsuite/ChangeLog: * g++.dg/modules/using-14.C: New test. Signed-off-by: Nathaniel Shead Co-authored-by: Patrick Palka Diff: --- gcc/cp/module.cc| 2 +- gcc/testsuite/g++.dg/modules/using-14.C | 14 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 001430a4a8f..d94d8ff4df9 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -13090,7 +13090,7 @@ depset::hash::add_binding_entity (tree decl, WMB_Flags flags, void *data_) inner = DECL_TEMPLATE_RESULT (inner); if ((!DECL_LANG_SPECIFIC (inner) || !DECL_MODULE_PURVIEW_P (inner)) - && !(flags & (WMB_Using | WMB_Export))) + && !((flags & WMB_Using) && (flags & WMB_Export))) /* Ignore global module fragment entities unless explicitly exported with a using declaration. */ return false; diff --git a/gcc/testsuite/g++.dg/modules/using-14.C b/gcc/testsuite/g++.dg/modules/using-14.C new file mode 100644 index 000..0e15a952de5 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/using-14.C @@ -0,0 +1,14 @@ +// PR c++/114600 +// { dg-additional-options "-fmodules-ts -Wno-global-module -fdump-lang-module" } +// { dg-module-cmi M } + +module; +namespace std { + template struct A { int n; }; + template A f(); + namespace __swappable_details { using std::f; } +} +export module M; + +// The whole GMF should be discarded here +// { dg-final { scan-lang-dump "Wrote 0 clusters" module } }
[gcc r14-9959] c++: Setup aliases imported from modules [PR106820]
https://gcc.gnu.org/g:62a0ef0d02cbb74cd865c1db2ecb7ca1b11f87cd commit r14-9959-g62a0ef0d02cbb74cd865c1db2ecb7ca1b11f87cd Author: Nathaniel Shead Date: Sat Feb 17 23:10:49 2024 +1100 c++: Setup aliases imported from modules [PR106820] I wonder if more generally we need to be doing more work when importing definitions from header units especially to handle all the work that 'make_rtl_for_nonlocal_decl' and 'rest_of_decl_compilation' would have been performing. But this patch fixes at least one missing step. PR c++/106820 gcc/cp/ChangeLog: * module.cc (trees_in::decl_value): Assemble alias when needed. gcc/testsuite/ChangeLog: * g++.dg/modules/pr106820_a.H: New test. * g++.dg/modules/pr106820_b.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 9 + gcc/testsuite/g++.dg/modules/pr106820_a.H | 5 + gcc/testsuite/g++.dg/modules/pr106820_b.C | 8 3 files changed, 22 insertions(+) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index c6f71e11515..001430a4a8f 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -219,6 +219,7 @@ Classes used: #include "dumpfile.h" #include "bitmap.h" #include "cgraph.h" +#include "varasm.h" #include "tree-iterator.h" #include "cpplib.h" #include "mkdeps.h" @@ -8414,6 +8415,14 @@ trees_in::decl_value () if (state->is_header () && decl_tls_wrapper_p (decl)) note_vague_linkage_fn (decl); + + /* Setup aliases for the declaration. */ + if (tree alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl))) + { + alias = TREE_VALUE (TREE_VALUE (alias)); + alias = get_identifier (TREE_STRING_POINTER (alias)); + assemble_alias (decl, alias); + } } else { diff --git a/gcc/testsuite/g++.dg/modules/pr106820_a.H b/gcc/testsuite/g++.dg/modules/pr106820_a.H new file mode 100644 index 000..7d32d4e5fc3 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr106820_a.H @@ -0,0 +1,5 @@ +// PR c++/106820 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi {} } + +static int __gthrw___pthread_key_create() __attribute__((__weakref__("foo"))); diff --git a/gcc/testsuite/g++.dg/modules/pr106820_b.C b/gcc/testsuite/g++.dg/modules/pr106820_b.C new file mode 100644 index 000..247fe26e778 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr106820_b.C @@ -0,0 +1,8 @@ +// PR c++/106820 +// { dg-additional-options "-fmodules-ts" } + +import "pr106820_a.H"; + +int main() { + __gthrw___pthread_key_create(); +}
[gcc r14-9883] c++: Keep DECL_SAVED_TREE of cdtor instantiations in modules [PR104040]
https://gcc.gnu.org/g:0774240b4df9a9bc48ce33a9625788e402498f5a commit r14-9883-g0774240b4df9a9bc48ce33a9625788e402498f5a Author: Nathaniel Shead Date: Fri Mar 29 13:53:54 2024 +1100 c++: Keep DECL_SAVED_TREE of cdtor instantiations in modules [PR104040] A template instantiation still needs to have its DECL_SAVED_TREE so that its definition is emitted into the CMI. This way it can be emitted in the object file of any importers that use it, in case it doesn't end up getting emitted in this TU. This is true even for maybe-in-charge functions, because we don't currently stream the clones directly but instead regenerate them from this function. PR c++/104040 gcc/cp/ChangeLog: * semantics.cc (expand_or_defer_fn_1): Keep DECL_SAVED_TREE for all vague linkage cdtors with modules. gcc/testsuite/ChangeLog: * g++.dg/modules/pr104040_a.C: New test. * g++.dg/modules/pr104040_b.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/semantics.cc | 8 ++-- gcc/testsuite/g++.dg/modules/pr104040_a.C | 14 ++ gcc/testsuite/g++.dg/modules/pr104040_b.C | 8 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index a43ff6e2ab2..329c524a509 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -5029,9 +5029,13 @@ expand_or_defer_fn_1 (tree fn) /* We don't want to process FN again, so pretend we've written it out, even though we haven't. */ TREE_ASM_WRITTEN (fn) = 1; - /* If this is a constexpr function, keep DECL_SAVED_TREE. */ + /* If this is a constexpr function we still need the body to be +able to evaluate it. Similarly, with modules we only stream +the maybe-in-charge cdtor and regenerate the clones from it on +demand, so we also need to keep the body. Otherwise we don't +need it anymore. */ if (!DECL_DECLARED_CONSTEXPR_P (fn) - && !(modules_p () && DECL_DECLARED_INLINE_P (fn))) + && !(modules_p () && vague_linkage_p (fn))) DECL_SAVED_TREE (fn) = NULL_TREE; return false; } diff --git a/gcc/testsuite/g++.dg/modules/pr104040_a.C b/gcc/testsuite/g++.dg/modules/pr104040_a.C new file mode 100644 index 000..ea36ce0a798 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr104040_a.C @@ -0,0 +1,14 @@ +// PR c++/104040 +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi test } + +export module test; + +export template +struct test { + ~test() {} +}; + +test use() { + return {}; +} diff --git a/gcc/testsuite/g++.dg/modules/pr104040_b.C b/gcc/testsuite/g++.dg/modules/pr104040_b.C new file mode 100644 index 000..efe014673fb --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr104040_b.C @@ -0,0 +1,8 @@ +// PR c++/104040 +// { dg-additional-options "-fmodules-ts" } + +import test; + +int main() { + test t{}; +}
[gcc r14-9881] c++: Track declarations imported from partitions [PR99377]
https://gcc.gnu.org/g:77c0b5b23f91404004a9bf710981f6d615b63f57 commit r14-9881-g77c0b5b23f91404004a9bf710981f6d615b63f57 Author: Nathaniel Shead Date: Thu Apr 4 23:16:08 2024 +1100 c++: Track declarations imported from partitions [PR99377] The testcase in comment 15 of the linked PR is caused because the following assumption in depset::hash::make_dependency doesn't hold: if (DECL_LANG_SPECIFIC (not_tmpl) && DECL_MODULE_IMPORT_P (not_tmpl)) { /* Store the module number and index in cluster/section, so we don't have to look them up again. */ unsigned index = import_entity_index (decl); module_state *from = import_entity_module (index); /* Remap will be zero for imports from partitions, which we want to treat as-if declared in this TU. */ if (from->remap) { dep->cluster = index - from->entity_lwm; dep->section = from->remap; dep->set_flag_bit (); } } This is because at least for template specialisations, we first see the declaration in the header unit imported from the partition, and then the instantiation provided by the partition itself. This means that the 'import_entity_index' lookup doesn't report that the specialisation was declared in the partition and thus should be considered as-if it was part of the TU, and get emitted into the CMI. We always need to emit definitions from module partitions into the primary module interface's CMI, as unlike with other kinds of transitive imports the built CMIs for module partitions are not visible to importers. To fix this, this patch allows, as a special case for installing an entity from a partition, to overwrite the entity_map entry with the (later) index into the partition so that this assumption holds again. We only do this for the first time we override with a partition, so that entities are at least still reported as originating from the first imported partition that declares them (rather than the last); existing tests check for this and this seems to be a friendlier approach to go for, albeit slightly more expensive. PR c++/99377 gcc/cp/ChangeLog: * module.cc (trees_in::install_entity): Overwrite entity map index if installing from a partition. gcc/testsuite/ChangeLog: * g++.dg/modules/pr99377-3_a.H: New test. * g++.dg/modules/pr99377-3_b.C: New test. * g++.dg/modules/pr99377-3_c.C: New test. * g++.dg/modules/pr99377-3_d.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/module.cc | 13 + gcc/testsuite/g++.dg/modules/pr99377-3_a.H | 17 + gcc/testsuite/g++.dg/modules/pr99377-3_b.C | 10 ++ gcc/testsuite/g++.dg/modules/pr99377-3_c.C | 5 + gcc/testsuite/g++.dg/modules/pr99377-3_d.C | 8 5 files changed, 53 insertions(+) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 8aab9ea0bae..4e91fa6e052 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -7649,6 +7649,19 @@ trees_in::install_entity (tree decl) gcc_checking_assert (!existed); slot = ident; } + else if (state->is_partition ()) +{ + /* The decl is already in the entity map, but we see it again now from a +partition: we want to overwrite if the original decl wasn't also from +a (possibly different) partition. Otherwise, for things like template +instantiations, make_dependency might not realise that this is also +provided from a partition and should be considered part of this module +(and thus always emitted into the primary interface's CMI). */ + unsigned *slot = entity_map->get (DECL_UID (decl)); + module_state *imp = import_entity_module (*slot); + if (!imp->is_partition ()) + *slot = ident; +} return true; } diff --git a/gcc/testsuite/g++.dg/modules/pr99377-3_a.H b/gcc/testsuite/g++.dg/modules/pr99377-3_a.H new file mode 100644 index 000..580a7631ae1 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99377-3_a.H @@ -0,0 +1,17 @@ +// { dg-additional-options "-fmodule-header" } +// { dg-module-cmi {} } + +template +struct Widget +{ + Widget (int) { } + + bool First() const { return true; } + + bool Second () const { return true;} +}; + +inline void Frob (const Widget& w) noexcept +{ + w.First (); +} diff --git a/gcc/testsuite/g++.dg/modules/pr99377-3_b.C b/gcc/testsuite/g++.dg/modules/pr99377-3_b.C new file mode 100644 index 000..5cbce7b3544 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/pr99377-3_b.C @@ -0,0 +1,10 @@ +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi Foo:check } + +export module Foo:check; +import "pr99377-3_a.H"; + +export inline bool Ch
[gcc r14-9530] c++: Fix handling of no-linkage decls for modules
https://gcc.gnu.org/g:c4845edfeaf44756ad9672e8d143f1c8f5c4c0f6 commit r14-9530-gc4845edfeaf44756ad9672e8d143f1c8f5c4c0f6 Author: Nathaniel Shead Date: Sat Mar 16 22:00:29 2024 +1100 c++: Fix handling of no-linkage decls for modules When testing the changes for PR c++/112631 we discovered that currently we don't emit definitions of block-scope function declarations if they're not used in the module interface TU, which causes issues if they are used by importers. This patch fixes the handling of no-linkage declarations for C++20. In particular, a type declared in a function with vague linkage or declared in a module CMI could potentially be accessible outside its defining TU, and as such we can't assume that function declarations using that type can never be defined in another TU. A complication with handling this is that we're only strictly interested in declarations with a module CMI, but when parsing the global module fragment we don't yet know whether or not this module will have a CMI until we reach the "export module" line (or not). Since this case is IFNDR anyway (by [basic.def.odr] p11) we just tentatively assume while parsing the GMF that this module will have a CMI; once we see (or don't see) an 'export module' declaration we can commit to that knowledge for future declarations. gcc/cp/ChangeLog: * cp-tree.h (module_maybe_has_cmi_p): New function. * decl.cc (grokfndecl): Mark block-scope functions as public if they could be visible in other TUs. * decl2.cc (no_linkage_error): Don't error for declarations that could be defined in other TUs since C++20. Suppress duplicate errors from 'check_global_declaration'. * tree.cc (no_linkage_check): In relaxed mode, don't consider types in a module CMI to have no linkage. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/linkage-1.C: New test. * g++.dg/modules/block-decl-3.h: New test. * g++.dg/modules/block-decl-3_a.C: New test. * g++.dg/modules/block-decl-3_b.C: New test. * g++.dg/modules/block-decl-3_c.C: New test. * g++.dg/modules/linkage-1_a.C: New test. * g++.dg/modules/linkage-1_b.C: New test. * g++.dg/modules/linkage-1_c.C: New test. * g++.dg/modules/linkage-2.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/cp-tree.h | 6 + gcc/cp/decl.cc| 10 +- gcc/cp/decl2.cc | 39 ++- gcc/cp/tree.cc| 21 +++- gcc/testsuite/g++.dg/cpp2a/linkage-1.C| 18 +++ gcc/testsuite/g++.dg/modules/block-decl-3.h | 39 +++ gcc/testsuite/g++.dg/modules/block-decl-3_a.C | 157 ++ gcc/testsuite/g++.dg/modules/block-decl-3_b.C | 8 ++ gcc/testsuite/g++.dg/modules/block-decl-3_c.C | 30 + gcc/testsuite/g++.dg/modules/linkage-1_a.C| 15 +++ gcc/testsuite/g++.dg/modules/linkage-1_b.C| 6 + gcc/testsuite/g++.dg/modules/linkage-1_c.C| 9 ++ gcc/testsuite/g++.dg/modules/linkage-2.C | 26 + 13 files changed, 372 insertions(+), 12 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 05913861e06..52d53589e51 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7384,6 +7384,12 @@ inline bool named_module_purview_p () inline bool named_module_attach_p () { return named_module_p () && module_attach_p (); } +/* We don't know if this TU will have a CMI while parsing the GMF, + so tentatively assume that it might, for the purpose of determining + whether no-linkage decls could be used by an importer. */ +inline bool module_maybe_has_cmi_p () +{ return module_has_cmi_p () || (named_module_p () && !module_purview_p ()); } + /* We're currently exporting declarations. */ inline bool module_exporting_p () { return module_kind & MK_EXPORTING; } diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 7a97b867199..65ab64885ff 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -10756,9 +10756,15 @@ grokfndecl (tree ctype, /* Members of anonymous types and local classes have no linkage; make them internal. If a typedef is made later, this will be changed. */ - if (ctype && (!TREE_PUBLIC (TYPE_MAIN_DECL (ctype)) - || decl_function_context (TYPE_MAIN_DECL (ctype + if (ctype && !TREE_PUBLIC (TYPE_MAIN_DECL (ctype))) publicp = 0; + else if (ctype && decl_function_context (TYPE_MAIN_DECL (ctype))) +/* But members of local classes in a module CMI should have their + definitions exported, in case they are (directly or indirectly) + used by an importer. We don't just use module_has_cmi_p here + because for entities in the GMF we don't yet know whether this +
[gcc r14-9517] testsuite: Fix excess errors for new modules testcases on powerpc [PR114320]
https://gcc.gnu.org/g:6cb5ef37c2fac240b68d8ee438aba4885956269f commit r14-9517-g6cb5ef37c2fac240b68d8ee438aba4885956269f Author: Nathaniel Shead Date: Sat Mar 16 00:11:25 2024 +1100 testsuite: Fix excess errors for new modules testcases on powerpc [PR114320] On some configurations, PowerPC emits -Wpsabi warnings when using IEEE long doubles on a machine configured with IBM long double by default. This patch suppresses these warnings for this testcase. PR testsuite/114320 gcc/testsuite/ChangeLog: * g++.dg/modules/target-powerpc-1_a.C: Suppress -Wpsabi. * g++.dg/modules/target-powerpc-1_b.C: Likewise. Signed-off-by: Nathaniel Shead Diff: --- gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C | 2 +- gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C b/gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C index 693ed101ed5..01709e0eac0 100644 --- a/gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C +++ b/gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C @@ -1,7 +1,7 @@ // PR c++/98645 // { dg-do compile { target powerpc*-*-* } } // { dg-require-effective-target ppc_float128_sw } -// { dg-additional-options "-fmodules-ts -mfloat128 -mabi=ieeelongdouble" } +// { dg-additional-options "-fmodules-ts -mfloat128 -mabi=ieeelongdouble -Wno-psabi" } export module M; export __ibm128 i = 0.0; diff --git a/gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C b/gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C index d6b684b556d..b4209bc1550 100644 --- a/gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C +++ b/gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C @@ -1,7 +1,7 @@ // PR c++/98645 // { dg-module-do compile { target powerpc*-*-* } } // { dg-require-effective-target ppc_float128_sw } -// { dg-additional-options "-fmodules-ts -mfloat128 -mabi=ieeelongdouble" } +// { dg-additional-options "-fmodules-ts -mfloat128 -mabi=ieeelongdouble -Wno-psabi" } import M;
[gcc r14-9501] c++: Check module attachment instead of just purview when necessary [PR112631]
https://gcc.gnu.org/g:ead3075406ece9daaad65a01ae539150aee43f5a commit r14-9501-gead3075406ece9daaad65a01ae539150aee43f5a Author: Nathaniel Shead Date: Tue Mar 12 23:24:27 2024 +1100 c++: Check module attachment instead of just purview when necessary [PR112631] Block-scope declarations of functions or extern values are not allowed when attached to a named module. Similarly, class member functions are not inline if attached to a named module. However, in both these cases we currently only check if the declaration is within the module purview; it is possible for such a declaration to occur within the module purview but not be attached to a named module (e.g. in an 'extern "C++"' block). This patch makes the required adjustments. PR c++/112631 gcc/cp/ChangeLog: * cp-tree.h (named_module_attach_p): New function. * decl.cc (start_decl): Check for attachment not purview. (grokmethod): Likewise. gcc/testsuite/ChangeLog: * g++.dg/modules/block-decl-1_a.C: New test. * g++.dg/modules/block-decl-1_b.C: New test. * g++.dg/modules/block-decl-2.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/cp-tree.h | 2 ++ gcc/cp/decl.cc| 10 +- gcc/testsuite/g++.dg/modules/block-decl-1_a.C | 9 + gcc/testsuite/g++.dg/modules/block-decl-1_b.C | 10 ++ gcc/testsuite/g++.dg/modules/block-decl-2.C | 21 + 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 14895bc6585..05913861e06 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7381,6 +7381,8 @@ inline bool module_attach_p () inline bool named_module_purview_p () { return named_module_p () && module_purview_p (); } +inline bool named_module_attach_p () +{ return named_module_p () && module_attach_p (); } /* We're currently exporting declarations. */ inline bool module_exporting_p () diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index dbc3df24e77..7a97b867199 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -6092,10 +6092,10 @@ start_decl (const cp_declarator *declarator, { /* A function-scope decl of some namespace-scope decl. */ DECL_LOCAL_DECL_P (decl) = true; - if (named_module_purview_p ()) + if (named_module_attach_p ()) error_at (declarator->id_loc, - "block-scope extern declaration %q#D not permitted" - " in module purview", decl); + "block-scope extern declaration %q#D must not be" + " attached to a named module", decl); } /* Enter this declaration into the symbol table. Don't push the plain @@ -18907,10 +18907,10 @@ grokmethod (cp_decl_specifier_seq *declspecs, check_template_shadow (fndecl); /* p1779 ABI-Isolation makes inline not a default for in-class - definitions in named module purview. If the user explicitly + definitions attached to a named module. If the user explicitly made it inline, grokdeclarator will already have done the right things. */ - if ((!named_module_purview_p () + if ((!named_module_attach_p () || flag_module_implicit_inline /* Lambda's operator function remains inline. */ || LAMBDA_TYPE_P (DECL_CONTEXT (fndecl))) diff --git a/gcc/testsuite/g++.dg/modules/block-decl-1_a.C b/gcc/testsuite/g++.dg/modules/block-decl-1_a.C new file mode 100644 index 000..e7ffc629192 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/block-decl-1_a.C @@ -0,0 +1,9 @@ +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi bla } + +export module bla; + +export extern "C++" inline void fun() { + void oops(); // { dg-bogus "block-scope extern declaration" } + oops(); +} diff --git a/gcc/testsuite/g++.dg/modules/block-decl-1_b.C b/gcc/testsuite/g++.dg/modules/block-decl-1_b.C new file mode 100644 index 000..c0d724f25ac --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/block-decl-1_b.C @@ -0,0 +1,10 @@ +// { dg-module-do link } +// { dg-additional-options "-fmodules-ts" } + +import bla; + +void oops() {} + +int main() { + fun(); +} diff --git a/gcc/testsuite/g++.dg/modules/block-decl-2.C b/gcc/testsuite/g++.dg/modules/block-decl-2.C new file mode 100644 index 000..974e26f9b7a --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/block-decl-2.C @@ -0,0 +1,21 @@ +// { dg-additional-options "-fmodules-ts" } +// { dg-module-cmi !mod } + +export module mod; + +namespace { + void internal() {} +} + +export extern "C++" auto foo() { + struct X { +// `foo` is not attached to a named module, and as such +// `X::f` should be implicitly `inline` here +void f() { // { dg-error "references internal linkage entity" } + internal(); +} + }; + return X{}; +} + +// { dg-prune-output "failed to write compiled module"
[gcc r14-9439] c++: Support target-specific nodes when streaming modules [PR111224]
https://gcc.gnu.org/g:4aa87b856067d4911de8fb66b3a27659dc75ca6d commit r14-9439-g4aa87b856067d4911de8fb66b3a27659dc75ca6d Author: Nathaniel Shead Date: Sun Mar 10 22:06:18 2024 +1100 c++: Support target-specific nodes when streaming modules [PR111224] Some targets make use of POLY_INT_CSTs and other custom builtin types, which currently violate some assumptions when streaming. This patch adds support for them, such as types like Aarch64 __fp16, PowerPC __ibm128, and vector types thereof. This patch doesn't provide "full" support of AArch64 SVE, however, since for that we would need to support 'target' nodes (tracked in PR108080). Adding the new builtin types means that on Aarch64 we now have 217 global trees created on initialisation (up from 191), so this patch also slightly bumps the initial size of the fixed_trees allocation to 250. PR c++/98645 PR c++/98688 PR c++/111224 gcc/cp/ChangeLog: * module.cc (enum tree_tag): Add new tag for builtin types. (trees_out::start): POLY_INT_CSTs can be emitted. (trees_in::start): Likewise. (trees_out::core_vals): Stream POLY_INT_CSTs. (trees_in::core_vals): Likewise. (trees_out::type_node): Handle vectors with multiple coeffs. (trees_in::tree_node): Likewise. (init_modules): Register target-specific builtin types. Bump initial capacity slightly. gcc/testsuite/ChangeLog: * g++.dg/modules/target-aarch64-1_a.C: New test. * g++.dg/modules/target-aarch64-1_b.C: New test. * g++.dg/modules/target-powerpc-1_a.C: New test. * g++.dg/modules/target-powerpc-1_b.C: New test. * g++.dg/modules/target-powerpc-2_a.C: New test. * g++.dg/modules/target-powerpc-2_b.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Patrick Palka Diff: --- gcc/cp/module.cc | 32 --- gcc/testsuite/g++.dg/modules/target-aarch64-1_a.C | 17 gcc/testsuite/g++.dg/modules/target-aarch64-1_b.C | 13 + gcc/testsuite/g++.dg/modules/target-powerpc-1_a.C | 7 + gcc/testsuite/g++.dg/modules/target-powerpc-1_b.C | 10 +++ gcc/testsuite/g++.dg/modules/target-powerpc-2_a.C | 20 ++ gcc/testsuite/g++.dg/modules/target-powerpc-2_b.C | 12 + 7 files changed, 101 insertions(+), 10 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 99055523d91..8aab9ea0bae 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -5173,7 +5173,6 @@ trees_out::start (tree t, bool code_streamed) break; case FIXED_CST: -case POLY_INT_CST: gcc_unreachable (); /* Not supported in C++. */ break; @@ -5259,7 +5258,6 @@ trees_in::start (unsigned code) case FIXED_CST: case IDENTIFIER_NODE: -case POLY_INT_CST: case SSA_NAME: case TARGET_MEM_REF: case TRANSLATION_UNIT_DECL: @@ -6106,7 +6104,10 @@ trees_out::core_vals (tree t) break; case POLY_INT_CST: - gcc_unreachable (); /* Not supported in C++. */ + if (streaming_p ()) + for (unsigned ix = 0; ix != NUM_POLY_INT_COEFFS; ix++) + WT (POLY_INT_CST_COEFF (t, ix)); + break; case REAL_CST: if (streaming_p ()) @@ -6615,8 +6616,9 @@ trees_in::core_vals (tree t) break; case POLY_INT_CST: - /* Not suported in C++. */ - return false; + for (unsigned ix = 0; ix != NUM_POLY_INT_COEFFS; ix++) + RT (POLY_INT_CST_COEFF (t, ix)); + break; case REAL_CST: if (const void *bytes = buf (sizeof (real_value))) @@ -9068,8 +9070,8 @@ trees_out::type_node (tree type) if (streaming_p ()) { poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (type); - /* to_constant asserts that only coeff[0] is of interest. */ - wu (static_cast (nunits.to_constant ())); + for (unsigned ix = 0; ix != NUM_POLY_INT_COEFFS; ix++) + wu (nunits.coeffs[ix]); } break; } @@ -9630,9 +9632,11 @@ trees_in::tree_node (bool is_use) case VECTOR_TYPE: { - unsigned HOST_WIDE_INT nunits = wu (); + poly_uint64 nunits; + for (unsigned ix = 0; ix != NUM_POLY_INT_COEFFS; ix++) + nunits.coeffs[ix] = wu (); if (!get_overrun ()) - res = build_vector_type (res, static_cast (nunits)); + res = build_vector_type (res, nunits); } break; } @@ -20151,7 +20155,7 @@ init_modules (cpp_reader *reader) some global trees are lazily created and we don't want that to mess with our syndrome of fixed trees. */ unsigned crc = 0; - vec_alloc (fixed_trees, 200); + vec_alloc (fixed_trees, 250); dump () && dump ("+Creating globals");
[gcc r14-9375] c++: Redetermine whether to write vtables on stream-in [PR114229]
https://gcc.gnu.org/g:9ccd03dee4c35a24c6699a58a7251a5277a91cf5 commit r14-9375-g9ccd03dee4c35a24c6699a58a7251a5277a91cf5 Author: Nathaniel Shead Date: Thu Mar 7 23:09:03 2024 +1100 c++: Redetermine whether to write vtables on stream-in [PR114229] We currently always stream DECL_INTERFACE_KNOWN, which is needed since many kinds of declarations already have their interface determined at parse time. But for vtables and type-info declarations we need to re-evaluate on stream-in as whether they need to be emitted or not changes in each TU, so this patch clears DECL_INTERFACE_KNOWN on these kinds of declarations so that they can go through 'import_export_decl' again. Note that the precise details of the virt-2 tests will need to change when we implement the resolution of [1], for now I just updated the test to not fail with the new (current) semantics. [1]: https://github.com/itanium-cxx-abi/cxx-abi/pull/171 PR c++/114229 gcc/cp/ChangeLog: * module.cc (trees_out::core_bools): Redetermine DECL_INTERFACE_KNOWN on stream-in for vtables and tinfo. * decl2.cc (import_export_decl): Add fixme for ABI changes with module vtables and tinfo. gcc/testsuite/ChangeLog: * g++.dg/modules/virt-2_b.C: Update test to acknowledge that we now emit vtables here too. * g++.dg/modules/virt-3_a.C: New test. * g++.dg/modules/virt-3_b.C: New test. * g++.dg/modules/virt-3_c.C: New test. * g++.dg/modules/virt-3_d.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/decl2.cc | 4 gcc/cp/module.cc| 12 +++- gcc/testsuite/g++.dg/modules/virt-2_b.C | 5 ++--- gcc/testsuite/g++.dg/modules/virt-3_a.C | 9 + gcc/testsuite/g++.dg/modules/virt-3_b.C | 6 ++ gcc/testsuite/g++.dg/modules/virt-3_c.C | 3 +++ gcc/testsuite/g++.dg/modules/virt-3_d.C | 7 +++ 7 files changed, 42 insertions(+), 4 deletions(-) diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 1dddbaab38b..6c9fd415d40 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -3398,6 +3398,10 @@ import_export_decl (tree decl) unit. */ import_p = false; + /* FIXME: Since https://github.com/itanium-cxx-abi/cxx-abi/pull/171, + the ABI specifies that classes attached to named modules should + have their vtables uniquely emitted in the object for the module + unit in which it is defined. And similarly for RTTI structures. */ if (VAR_P (decl) && DECL_VTABLE_OR_VTT_P (decl)) { class_type = DECL_CONTEXT (decl); diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 53104753737..99055523d91 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -5376,7 +5376,17 @@ trees_out::core_bools (tree t) WB (t->decl_common.lang_flag_2); WB (t->decl_common.lang_flag_3); WB (t->decl_common.lang_flag_4); - WB (t->decl_common.lang_flag_5); + + { + /* This is DECL_INTERFACE_KNOWN: We should redetermine whether + we need to import or export any vtables or typeinfo objects + on stream-in. */ + bool interface_known = t->decl_common.lang_flag_5; + if (VAR_P (t) && (DECL_VTABLE_OR_VTT_P (t) || DECL_TINFO_P (t))) + interface_known = false; + WB (interface_known); + } + WB (t->decl_common.lang_flag_6); WB (t->decl_common.lang_flag_7); WB (t->decl_common.lang_flag_8); diff --git a/gcc/testsuite/g++.dg/modules/virt-2_b.C b/gcc/testsuite/g++.dg/modules/virt-2_b.C index e041f0721f9..2bc5eced013 100644 --- a/gcc/testsuite/g++.dg/modules/virt-2_b.C +++ b/gcc/testsuite/g++.dg/modules/virt-2_b.C @@ -21,8 +21,7 @@ int main () return !(Visit (&me) == 1); } -// We do not emit Visitor vtable -// but we do emit rtti here -// { dg-final { scan-assembler-not {_ZTVW3foo7Visitor:} } } +// Again, we emit Visitor vtable and rtti here +// { dg-final { scan-assembler {_ZTVW3foo7Visitor:} } } // { dg-final { scan-assembler {_ZTIW3foo7Visitor:} } } // { dg-final { scan-assembler {_ZTSW3foo7Visitor:} } } diff --git a/gcc/testsuite/g++.dg/modules/virt-3_a.C b/gcc/testsuite/g++.dg/modules/virt-3_a.C new file mode 100644 index 000..a7eae7f9d35 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/virt-3_a.C @@ -0,0 +1,9 @@ +// PR c++/114229 +// { dg-additional-options "-fmodules-ts -Wno-global-module" } +// { dg-module-cmi modA } + +module; +template struct basic_streambuf { virtual void overflow() { } }; +extern template struct basic_streambuf; +export module modA; +export basic_streambuf *p; diff --git a/gcc/testsuite/g++.dg/modules/virt-3_b.C b/gcc/testsuite/g++.dg/modules/virt-3_b.C new file mode 100644 index 000..4d87b965bbf --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/virt-3_b.C @@ -0,0 +1,6 @@ +// PR c++/114229 +// { dg-additional-option
[gcc r14-9357] c++: Fix ICE diagnosing incomplete type of overloaded function set [PR98356]
https://gcc.gnu.org/g:940586a63586941a9f2b973491afc8a15a96c98b commit r14-9357-g940586a63586941a9f2b973491afc8a15a96c98b Author: Nathaniel Shead Date: Tue Mar 5 01:59:41 2024 +1100 c++: Fix ICE diagnosing incomplete type of overloaded function set [PR98356] In the linked PR the result of 'get_first_fn' is a USING_DECL against the template parameter, to be filled in on instantiation. But we don't actually need to get the first set of the member functions: it's enough to know that we have a (possibly overloaded) member function at all. PR c++/98356 gcc/cp/ChangeLog: * typeck2.cc (cxx_incomplete_type_diagnostic): Don't assume 'member' will be a FUNCTION_DECL (or something like it). gcc/testsuite/ChangeLog: * g++.dg/pr98356.C: New test. Signed-off-by: Nathaniel Shead Diff: --- gcc/cp/typeck2.cc | 11 +-- gcc/testsuite/g++.dg/pr98356.C | 9 + 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 9608bdccd8b..31198b2f9f5 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -350,16 +350,15 @@ cxx_incomplete_type_diagnostic (location_t loc, const_tree value, bad_member: { tree member = TREE_OPERAND (value, 1); - if (is_overloaded_fn (member)) - member = get_first_fn (member); - - if (DECL_FUNCTION_MEMBER_P (member) - && ! flag_ms_extensions) + if (is_overloaded_fn (member) && !flag_ms_extensions) { gcc_rich_location richloc (loc); /* If "member" has no arguments (other than "this"), then add a fix-it hint. */ - if (type_num_arguments (TREE_TYPE (member)) == 1) + member = MAYBE_BASELINK_FUNCTIONS (member); + if (TREE_CODE (member) == FUNCTION_DECL + && DECL_OBJECT_MEMBER_FUNCTION_P (member) + && type_num_arguments (TREE_TYPE (member)) == 1) richloc.add_fixit_insert_after ("()"); complained = emit_diagnostic (diag_kind, &richloc, 0, "invalid use of member function %qD " diff --git a/gcc/testsuite/g++.dg/pr98356.C b/gcc/testsuite/g++.dg/pr98356.C new file mode 100644 index 000..acea238593b --- /dev/null +++ b/gcc/testsuite/g++.dg/pr98356.C @@ -0,0 +1,9 @@ +// PR c++/98356 +// { dg-do compile { target c++11 } } + +template class T> struct S { + using A = T; + using A::foo; + void foo (); + void bar () {foo.} // { dg-error "invalid use of member function" } +};
[gcc r14-9356] c++: Stream DECL_CONTEXT for template template parms [PR98881]
https://gcc.gnu.org/g:2f8a3da8ea30066d2201f8148714a8e89da5 commit r14-9356-g2f8a3da8ea30066d2201f8148714a8e89da5 Author: Nathaniel Shead Date: Tue Mar 5 15:17:09 2024 +1100 c++: Stream DECL_CONTEXT for template template parms [PR98881] When streaming in a nested template-template parameter as in the attached testcase, we end up reaching the containing template-template parameter in 'tpl_parms_fini'. We should not set the DECL_CONTEXT to this (nested) template-template parameter, as it should already be the struct that the outer template-template parameter is declared on. The precise logic for what DECL_CONTEXT should be for a template template parameter in various situations seems rather obscure. Rather than trying to determine the assumptions that need to hold, it seems simpler to just always re-stream the DECL_CONTEXT as needed for now. PR c++/98881 gcc/cp/ChangeLog: * module.cc (trees_out::tpl_parms_fini): Stream out DECL_CONTEXT for template template parameters. (trees_in::tpl_parms_fini): Read it. gcc/testsuite/ChangeLog: * g++.dg/modules/tpl-tpl-parm-3.h: New test. * g++.dg/modules/tpl-tpl-parm-3_a.H: New test. * g++.dg/modules/tpl-tpl-parm-3_b.C: New test. * g++.dg/modules/tpl-tpl-parm-3_c.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Patrick Palka Reviewed-by: Jason Merrill Diff: --- gcc/cp/module.cc| 41 ++--- gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3.h | 12 gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_a.H | 5 +++ gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_b.C | 5 +++ gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3_c.C | 15 + 5 files changed, 47 insertions(+), 31 deletions(-) diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 80b63a70a62..f7e8b357fc2 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -10126,23 +10126,12 @@ trees_out::tpl_parms_fini (tree tmpl, unsigned tpl_levels) tree dflt = TREE_PURPOSE (parm); tree_node (dflt); - if (streaming_p ()) - { - tree decl = TREE_VALUE (parm); - if (TREE_CODE (decl) == TEMPLATE_DECL) - { - tree ctx = DECL_CONTEXT (decl); - tree inner = DECL_TEMPLATE_RESULT (decl); - tree tpi = (TREE_CODE (inner) == TYPE_DECL - ? TEMPLATE_TYPE_PARM_INDEX (TREE_TYPE (decl)) - : DECL_INITIAL (inner)); - bool original = (TEMPLATE_PARM_LEVEL (tpi) - == TEMPLATE_PARM_ORIG_LEVEL (tpi)); - /* Original template template parms have a context -of their owning template. Reduced ones do not. */ - gcc_checking_assert (original ? ctx == tmpl : !ctx); - } - } + /* Template template parameters need a context of their owning +template. This is quite tricky to infer correctly on stream-in +(see PR c++/98881) so we'll just provide it directly. */ + tree decl = TREE_VALUE (parm); + if (TREE_CODE (decl) == TEMPLATE_DECL) + tree_node (DECL_CONTEXT (decl)); } } } @@ -10160,24 +10149,14 @@ trees_in::tpl_parms_fini (tree tmpl, unsigned tpl_levels) { tree parm = TREE_VEC_ELT (vec, ix); tree dflt = tree_node (); - if (get_overrun ()) - return false; TREE_PURPOSE (parm) = dflt; tree decl = TREE_VALUE (parm); if (TREE_CODE (decl) == TEMPLATE_DECL) - { - tree inner = DECL_TEMPLATE_RESULT (decl); - tree tpi = (TREE_CODE (inner) == TYPE_DECL - ? TEMPLATE_TYPE_PARM_INDEX (TREE_TYPE (decl)) - : DECL_INITIAL (inner)); - bool original = (TEMPLATE_PARM_LEVEL (tpi) - == TEMPLATE_PARM_ORIG_LEVEL (tpi)); - /* Original template template parms have a context -of their owning template. Reduced ones do not. */ - if (original) - DECL_CONTEXT (decl) = tmpl; - } + DECL_CONTEXT (decl) = tree_node (); + + if (get_overrun ()) + return false; } } return true; diff --git a/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3.h b/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3.h new file mode 100644 index 000..b0dcf353c23 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/tpl-tpl-parm-3.h @@ -0,0 +1,12 @@ +// PR c++/98881 + +template struct X {}; + +template typename TT> +struct X> { + template typename UU> + void f (X>&); +}; + +template class TT> struct Y; +template class UU> struct Y { }; diff --git a/gcc/testsuite/g++.dg/modules/tpl-tp
[gcc r14-9332] c++: Fix template deduction for conversion operators with xobj parameters [PR113629]
https://gcc.gnu.org/g:49d83e963aa453600088380aebd507e172eb80ad commit r14-9332-g49d83e963aa453600088380aebd507e172eb80ad Author: Nathaniel Shead Date: Wed Mar 6 00:43:22 2024 +1100 c++: Fix template deduction for conversion operators with xobj parameters [PR113629] Unification for conversion operators (DEDUCE_CONV) doesn't perform transformations like handling forwarding references. This is correct in general, but not for xobj parameters, which should be handled "normally" for the purposes of deduction: [temp.deduct.conv] only applies to the return type of the conversion function. PR c++/113629 gcc/cp/ChangeLog: * pt.cc (type_unification_real): Only use DEDUCE_CONV for the return type of a conversion function. gcc/testsuite/ChangeLog: * g++.dg/cpp23/explicit-obj-conv-op.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill Diff: --- gcc/cp/pt.cc | 12 +- gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C | 49 +++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index c4bc54a8fdb..a6e6c804130 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -23312,10 +23312,18 @@ type_unification_real (tree tparms, parameter pack is a non-deduced context. */ continue; + /* [temp.deduct.conv] only applies to the deduction of the return +type, which is always the first argument here. Other arguments +(notably, explicit object parameters) should undergo normal +call-like unification. */ + unification_kind_t kind = strict; + if (strict == DEDUCE_CONV && ia > 0) + kind = DEDUCE_CALL; + arg = args[ia]; ++ia; - if (unify_one_argument (tparms, full_targs, parm, arg, subr, strict, + if (unify_one_argument (tparms, full_targs, parm, arg, subr, kind, explain_p)) return 1; } @@ -23324,6 +23332,8 @@ type_unification_real (tree tparms, && parms != void_list_node && TREE_CODE (TREE_VALUE (parms)) == TYPE_PACK_EXPANSION) { + gcc_assert (strict != DEDUCE_CONV); + /* Unify the remaining arguments with the pack expansion type. */ tree argvec; tree parmvec = make_tree_vec (1); diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C new file mode 100644 index 000..a6ae4ea1dda --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-conv-op.C @@ -0,0 +1,49 @@ +// PR c++/113629 +// { dg-do compile { target c++23 } } + +template constexpr bool is_lvalue = false; +template constexpr bool is_lvalue = true; + +struct A { + constexpr operator bool(this auto&& self) { +return is_lvalue; + } +}; + +constexpr A a; +static_assert(static_cast(a)); +static_assert((bool)a); +static_assert(!static_cast(A{})); +static_assert(!(bool)A{}); + +struct B : A {}; + +constexpr B b; +static_assert(static_cast(b)); +static_assert((bool)b); +static_assert(!static_cast(B{})); +static_assert(!(bool)B{}); + +struct C { + template + explicit constexpr operator R(this T&&) { +return is_lvalue; + } +}; + +constexpr C c; +static_assert(static_cast(c)); +static_assert((bool)c); +static_assert(!static_cast(C{})); +static_assert(!(bool)C{}); + +struct D { + explicit constexpr operator bool(this const D&) { return true; } + explicit constexpr operator bool(this const D&&) { return false; } +}; + +constexpr D d; +static_assert(static_cast(d)); +static_assert((bool)d); +static_assert(!static_cast(D{})); +static_assert(!(bool)D{});