Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/15? -- >8 --
The ICE in the linked PR is caused because when current_lang_name is lang_name_c, set_decl_linkage calls decl_linkage on the retrofitted declaration. This is problematic because at this point we haven't finished streaming the declaration, and so we crash when attempting to access these missing bits (such as the type). The only declarations we can reach here will be things like types that don't get a language linkage anyway, so it seems reasonable to just hardcode a C++ language linkage here to work around the issue. An alternative fix would be to override current_lang_name in lazy_load_binding instead, but this potentially is potentially confusing if we ever deliberately support `extern "C" import "header_unit.hpp";` to override the language linkage of imported declarations, so I went with this approach instead. While testing this I found that we don't currently complain about mismatching language linkages for variables, and module_may_redeclare doesn't cope well with implementation units, so this patch also fixes those issues. PR c++/122019 gcc/cp/ChangeLog: * module.cc (trees_in::install_entity): Don't be affected by global language linkage state. (trees_in::is_matching_decl): Check mismatching language linkage for variables too. (module_may_redeclare): Report the correct module name for partitions and implementation units. gcc/testsuite/ChangeLog: * g++.dg/modules/lang-4_a.C: New test. * g++.dg/modules/lang-4_b.C: New test. Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com> --- gcc/cp/module.cc | 35 +++++++++++++++---------- gcc/testsuite/g++.dg/modules/lang-4_a.C | 22 ++++++++++++++++ gcc/testsuite/g++.dg/modules/lang-4_b.C | 26 ++++++++++++++++++ 3 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/g++.dg/modules/lang-4_a.C create mode 100644 gcc/testsuite/g++.dg/modules/lang-4_b.C diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index d5c3a83c728..7b69e806328 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -8144,7 +8144,14 @@ trees_in::install_entity (tree decl) if (!DECL_LANG_SPECIFIC (not_tmpl) || !DECL_MODULE_ENTITY_P (not_tmpl)) { - retrofit_lang_decl (not_tmpl); + /* We don't want to use retrofit_lang_decl directly so that we aren't + affected by the language state when we load in. */ + if (!DECL_LANG_SPECIFIC (not_tmpl)) + { + maybe_add_lang_decl_raw (not_tmpl, false); + gcc_checking_assert (!VAR_OR_FUNCTION_DECL_P (not_tmpl)); + SET_DECL_LANGUAGE (not_tmpl, lang_cplusplus); + } DECL_MODULE_ENTITY_P (not_tmpl) = true; /* Insert into the entity hash (it cannot already be there). */ @@ -12320,7 +12327,15 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) // FIXME: do more precise errors at point of mismatch const char *mismatch_msg = nullptr; - if (TREE_CODE (d_inner) == FUNCTION_DECL) + + if (VAR_OR_FUNCTION_DECL_P (d_inner) + && DECL_EXTERN_C_P (d_inner) != DECL_EXTERN_C_P (e_inner)) + { + mismatch_msg = G_("conflicting language linkage for imported " + "declaration %#qD"); + goto mismatch; + } + else if (TREE_CODE (d_inner) == FUNCTION_DECL) { tree e_ret = fndecl_declared_return_type (existing); tree d_ret = fndecl_declared_return_type (decl); @@ -12337,13 +12352,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) tree e_type = TREE_TYPE (e_inner); tree d_type = TREE_TYPE (d_inner); - if (DECL_EXTERN_C_P (d_inner) != DECL_EXTERN_C_P (e_inner)) - { - mismatch_msg = G_("conflicting language linkage for imported " - "declaration %#qD"); - goto mismatch; - } - for (tree e_args = TYPE_ARG_TYPES (e_type), d_args = TYPE_ARG_TYPES (d_type); e_args != d_args && (e_args || d_args); @@ -21151,7 +21159,7 @@ module_may_redeclare (tree olddecl, tree newdecl) // FIXME: Should we be checking this in more places on the scope chain? return true; - module_state *old_mod = this_module (); + module_state *old_mod = get_primary (this_module ()); module_state *new_mod = old_mod; tree old_origin = get_originating_module_decl (decl); @@ -21161,7 +21169,7 @@ module_may_redeclare (tree olddecl, tree newdecl) if (DECL_LANG_SPECIFIC (old_inner) && DECL_MODULE_IMPORT_P (old_inner)) { unsigned index = import_entity_index (old_origin); - old_mod = import_entity_module (index); + old_mod = get_primary (import_entity_module (index)); } bool newdecl_attached_p = module_attach_p (); @@ -21174,7 +21182,7 @@ module_may_redeclare (tree olddecl, tree newdecl) if (DECL_LANG_SPECIFIC (new_inner) && DECL_MODULE_IMPORT_P (new_inner)) { unsigned index = import_entity_index (new_origin); - new_mod = import_entity_module (index); + new_mod = get_primary (import_entity_module (index)); } } @@ -21185,8 +21193,7 @@ module_may_redeclare (tree olddecl, tree newdecl) /* Both are GM entities, OK. */ return true; - if (new_mod == old_mod - || (new_mod && get_primary (new_mod) == get_primary (old_mod))) + if (new_mod == old_mod) /* Both attached to same named module, OK. */ return true; } diff --git a/gcc/testsuite/g++.dg/modules/lang-4_a.C b/gcc/testsuite/g++.dg/modules/lang-4_a.C new file mode 100644 index 00000000000..cef2aae00ed --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lang-4_a.C @@ -0,0 +1,22 @@ +// PR c++/122019 +// { dg-additional-options "-fmodules -Wno-global-module" } + +module; + +typedef int pthread_once_t; + +export module M; + +namespace ns { + using ::pthread_once_t; +} + +// note: non-function types don't have language linkage +extern "C++" enum E { c }; +extern "C" typedef int T; + +extern "C" int foo; +extern "C++" int bar; + +extern "C" int qux; +extern "C++" int zap; diff --git a/gcc/testsuite/g++.dg/modules/lang-4_b.C b/gcc/testsuite/g++.dg/modules/lang-4_b.C new file mode 100644 index 00000000000..2085ed15211 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/lang-4_b.C @@ -0,0 +1,26 @@ +// PR c++/122019 +// { dg-additional-options "-fmodules -Wno-global-module" } +// Language linkage for types, variables, and lazy-loading in extern contexts. + +module; + +extern "C" enum E { c }; +extern "C++" typedef int T; + +extern "C++" int foo; // { dg-message "existing" } +extern "C" int bar; // { dg-message "existing" } + +module M; + +extern "C" ns::pthread_once_t x; + +E e; +T t; + +extern "C" { int use1 = foo; } // { dg-message "during load" } +extern "C" { int use2 = bar; } // { dg-message "during load" } +// { dg-error "conflicting language linkage for imported declaration 'int foo'" "" { target *-*-* } 0 } +// { dg-error "conflicting language linkage for imported declaration 'int bar'" "" { target *-*-* } 0 } + +extern "C++" int qux; // { dg-error "conflicting declaration" } +extern "C" int zap; // { dg-error "conflicting declaration" } -- 2.51.0