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). */
// 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);
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);
// 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);
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 ();
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));
}
}
/* 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;
}
--- /dev/null
+// 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" }