extern tree get_originating_module_decl (tree) ATTRIBUTE_PURE;
extern int get_originating_module (tree, bool for_mangle = false) ATTRIBUTE_PURE;
extern unsigned get_importing_module (tree, bool = false) ATTRIBUTE_PURE;
+extern void check_module_decl_linkage (tree);
/* Where current instance of the decl got declared/defined/instantiated. */
extern void set_instantiating_module (tree);
}
cp_finish_decl (decl, init, init_const_expr_p, asmspec_tree, flags);
+ check_module_decl_linkage (decl);
}
/* DECLARATOR and DECLSPECS correspond to a class member. The other
DECL_MODULE_ATTACH_P (decl) = true;
}
- if (!module_exporting_p ())
+ /* It is ill-formed to export a declaration with internal linkage. However,
+ at the point this function is called we don't yet always know whether this
+ declaration has internal linkage; instead we defer this check for callers
+ to do once visibility has been determined. */
+ if (module_exporting_p ())
+ DECL_MODULE_EXPORT_P (decl) = true;
+}
+
+/* Checks whether DECL within a module unit has valid linkage for its kind.
+ Must be called after visibility for DECL has been finalised. */
+
+void
+check_module_decl_linkage (tree decl)
+{
+ if (!module_has_cmi_p ())
return;
- // FIXME: Check ill-formed linkage
- DECL_MODULE_EXPORT_P (decl) = true;
+ /* An internal-linkage declaration cannot be generally be exported.
+ But it's OK to export any declaration from a header unit, including
+ internal linkage declarations. */
+ if (!header_module_p ()
+ && DECL_MODULE_EXPORT_P (decl)
+ && decl_linkage (decl) == lk_internal)
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "exporting declaration %qD with internal linkage", decl);
+ DECL_MODULE_EXPORT_P (decl) = false;
+ }
}
/* DECL is keyed to CTX for odr purposes. */
/* Process a namespace-alias declaration. */
void
-do_namespace_alias (tree alias, tree name_space)
+do_namespace_alias (location_t loc, tree alias, tree name_space)
{
if (name_space == error_mark_node)
return;
name_space = ORIGINAL_NAMESPACE (name_space);
/* Build the alias. */
- alias = build_lang_decl (NAMESPACE_DECL, alias, void_type_node);
+ alias = build_lang_decl_loc (loc, NAMESPACE_DECL, alias, void_type_node);
DECL_NAMESPACE_ALIAS (alias) = name_space;
DECL_EXTERNAL (alias) = 1;
DECL_CONTEXT (alias) = FROB_CONTEXT (current_scope ());
return;
set_originating_module (alias);
+ check_module_decl_linkage (alias);
/* Emit debug info for namespace alias. */
if (!building_stmt_list_p ())
/* Set type visibility now if this is a forward declaration. */
TREE_PUBLIC (decl) = 1;
determine_visibility (decl);
+ check_module_decl_linkage (decl);
return type;
}
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 (name)
+ {
+ auto_diagnostic_group d;
+ error_at (input_location, "exporting namespace %qD with "
+ "internal linkage", ns);
+ inform (input_location, "%qD has internal linkage because "
+ "it was declared in an unnamed namespace", ns);
+ }
+ else
+ error_at (input_location, "exporting unnamed namespace");
+ }
}
if (module_purview_p ())
DECL_MODULE_PURVIEW_P (ns) = true;
extern void set_decl_namespace (tree, tree, bool);
extern void push_decl_namespace (tree);
extern void pop_decl_namespace (void);
-extern void do_namespace_alias (tree, tree);
+extern void do_namespace_alias (location_t, tree, tree);
extern tree do_class_using_decl (tree, tree);
extern tree lookup_arg_dependent (tree, tree, vec<tree, va_gc> *);
extern tree search_anon_aggr (tree, tree, bool = false);
/* Look for the `namespace' keyword. */
cp_parser_require_keyword (parser, RID_NAMESPACE, RT_NAMESPACE);
/* Look for the identifier. */
+ location_t id_location = cp_lexer_peek_token (parser->lexer)->location;
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
return;
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
/* Register the alias in the symbol table. */
- do_namespace_alias (identifier, namespace_specifier);
+ do_namespace_alias (id_location, identifier, namespace_specifier);
}
/* Parse a qualified-namespace-specifier.
check_member_template (decl);
}
+ check_module_decl_linkage (decl);
+
return decl;
}
`explicit' constructor cannot be used. */
((is_direct_init || !is_initialized)
? LOOKUP_NORMAL : LOOKUP_IMPLICIT));
+ check_module_decl_linkage (decl);
}
else if ((cxx_dialect != cxx98) && friend_p
&& decl && TREE_CODE (decl) == FUNCTION_DECL)
/* Finish the function. */
fn = finish_function (inline_p);
+ check_module_decl_linkage (fn);
if (modules_p ()
&& !inline_p
/* Add FN to the queue of functions to be parsed later. */
vec_safe_push (unparsed_funs_with_definitions, fn);
+ check_module_decl_linkage (fn);
+
return fn;
}
tree decl = build_lang_decl_loc (loc, CONCEPT_DECL, *id, boolean_type_node);
DECL_CONTEXT (decl) = current_scope ();
DECL_INITIAL (decl) = init;
+ TREE_PUBLIC (decl) = true;
if (attrs)
cplus_decl_attributes (&decl, attrs, 0);
set_originating_module (decl, false);
+ check_module_decl_linkage (decl);
/* Push the enclosing template. */
return push_template_decl (decl);
export namespace ns {} // { dg-error "internal linkage" }
}
-export namespace {} // { dg-error "internal linkage" }
+export namespace {} // { dg-error "exporting unnamed namespace" }
--- /dev/null
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi !bad }
+
+export module bad;
+namespace global {}
+
+export static int x = 123; // { dg-error "internal linkage" }
+export static void f(); // { dg-error "internal linkage" }
+export static void g() {} // { dg-error "internal linkage" }
+export template <typename T> static void t(); // { dg-error "internal linkage" }
+export template <typename T> static void u() {} // { dg-error "internal linkage" }
+
+namespace {
+ export int y = 456; // { dg-error "internal linkage" }
+ export void h(); // { dg-error "internal linkage" }
+ export void i() {} // { dg-error "internal linkage" }
+ export template <typename T> void v(); // { dg-error "internal linkage" }
+ export template <typename T> void w() {} // { dg-error "internal linkage" }
+
+ export namespace ns {} // { dg-error "internal linkage" }
+ export namespace alias = global; // { dg-error "internal linkage" }
+
+ export struct A {}; // { dg-error "internal linkage" }
+ export template <typename T> struct B {}; // { dg-error "internal linkage" }
+
+ export enum E {}; // { dg-error "internal linkage" }
+ export enum class F {}; // { dg-error "internal linkage" }
+
+ export template <typename T> using U = int; // { dg-error "internal linkage" }
+
+#if __cplusplus >= 202002L
+ export template <typename T> concept C = true; // { dg-error "internal linkage" "" { target c++20 } }
+#endif
+}
+
+export namespace {} // { dg-error "exporting unnamed namespace" }
tree name = get_identifier (id);
tree target = convert_in (target_in);
- do_namespace_alias (name, target);
+ do_namespace_alias (input_location, name, target);
return 1;
}