@@ -9053,8 +9053,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;
@@ -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-declaration. */
+ parser->in_unbraced_export_declaration_p = false;
+
/* We are not processing a declarator. */
parser->in_declarator_p = false;
@@ -15249,10 +15254,6 @@ cp_parser_import_declaration (cp_parser *parser, module_parse mp_state,
goto skip_eol;
cp_parser_require_pragma_eol (parser, token);
- if (parser->in_unbraced_linkage_specification_p)
- error_at (token->location, "import cannot appear directly in"
- " a linkage-specification");
-
if (mp_state == MP_PURVIEW_IMPORTS || mp_state == MP_PRIVATE_IMPORTS)
{
/* Module-purview imports must not be from source inclusion
@@ -15273,7 +15274,7 @@ cp_parser_import_declaration (cp_parser *parser, module_parse mp_state,
/* export-declaration.
- export declaration
+ export name-declaration
export { declaration-seq-opt } */
static void
@@ -15315,7 +15316,13 @@ cp_parser_module_export (cp_parser *parser)
|| cp_lexer_next_token_is_keyword (parser->lexer, RID__EXPORT))
error_at (token->location, "%<export%> not part of following"
" module-directive");
+
+ bool saved_in_unbraced_export_declaration_p
+ = parser->in_unbraced_export_declaration_p;
+ parser->in_unbraced_export_declaration_p = true;
cp_parser_declaration (parser, NULL_TREE);
+ parser->in_unbraced_export_declaration_p
+ = saved_in_unbraced_export_declaration_p;
}
module_kind = mk;
@@ -15346,27 +15353,29 @@ cp_parser_declaration_seq_opt (cp_parser* parser)
}
}
-/* Parse a declaration.
+/* Parse a declaration. The distinction between name-declaration
+ and special-declaration is only since C++20.
declaration:
+ name-declaration
+ special-declaration
+
+ name-declaration:
block-declaration
+ nodeclspec-function-declaration
function-definition
template-declaration
- explicit-instantiation
- explicit-specialization
+ deduction-guide (C++17)
linkage-specification
namespace-definition
+ empty-declaration
+ attribute-declaration
+ module-import-declaration (modules)
- C++17:
- deduction-guide
-
- modules:
- (all these are only allowed at the outermost level, check
- that semantically, for better diagnostics)
- module-declaration
- module-export-declaration
- module-import-declaration
- export-declaration
+ special-declaration:
+ explicit-instantiation
+ explicit-specialization
+ export-declaration (modules)
GNU extension:
@@ -15389,6 +15398,13 @@ cp_parser_declaration (cp_parser* parser, tree prefix_attrs)
return;
}
+ /* P2615: Determine if we're parsing a name-declaration specifically,
+ or if special-declarations are OK too. */
+ bool require_name_decl_p
+ = (parser->in_unbraced_export_declaration_p
+ || (parser->in_unbraced_linkage_specification_p
+ && cxx_dialect >= cxx20));
+
/* Try to figure out what kind of declaration is present. */
cp_token *token1 = cp_lexer_peek_token (parser->lexer);
cp_token *token2 = (token1->type == CPP_EOF
@@ -15496,13 +15512,30 @@ cp_parser_declaration (cp_parser* parser, tree prefix_attrs)
/* `template <>' indicates a template specialization. */
if (token2->type == CPP_LESS
&& cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_GREATER)
- cp_parser_explicit_specialization (parser);
+ {
+ if (require_name_decl_p)
+ {
+ auto_diagnostic_group d;
+ cp_token *token3 = cp_lexer_peek_nth_token (parser->lexer, 3);
+ location_t loc = make_location (token1, token1, token3);
+ error_at (loc, "explicit specializations are not permitted here");
+ if (parser->in_unbraced_export_declaration_p)
+ inform (loc, "a specialization is always exported alongside "
+ "its primary template");
+ }
+ cp_parser_explicit_specialization (parser);
+ }
/* `template <' indicates a template declaration. */
else if (token2->type == CPP_LESS)
cp_parser_template_declaration (parser, /*member_p=*/false);
/* Anything else must be an explicit instantiation. */
else
- cp_parser_explicit_instantiation (parser);
+ {
+ if (require_name_decl_p)
+ error_at (token1->location,
+ "explicit instantiations are not permitted here");
+ cp_parser_explicit_instantiation (parser);
+ }
}
/* If the next token is `export', it's new-style modules or
old-style template. */
@@ -15511,7 +15544,14 @@ cp_parser_declaration (cp_parser* parser, tree prefix_attrs)
if (!modules_p ())
cp_parser_template_declaration (parser, /*member_p=*/false);
else
- cp_parser_module_export (parser);
+ {
+ /* We check for nested exports in cp_parser_module_export. */
+ if (require_name_decl_p
+ && !parser->in_unbraced_export_declaration_p)
+ error_at (token1->location,
+ "export-declarations are not permitted here");
+ cp_parser_module_export (parser);
+ }
}
else if (cp_token_is_module_directive (token1))
{
@@ -16809,7 +16849,7 @@ cp_parser_function_specifier_opt (cp_parser* parser,
linkage-specification:
extern string-literal { declaration-seq [opt] }
- extern string-literal declaration */
+ extern string-literal name-declaration */
static void
cp_parser_linkage_specification (cp_parser* parser, tree prefix_attr)
@@ -26767,6 +26807,7 @@ cp_parser_class_specifier (cp_parser* parser)
unsigned char in_statement;
bool in_switch_statement_p;
bool saved_in_unbraced_linkage_specification_p;
+ bool saved_in_unbraced_export_declaration_p;
tree old_scope = NULL_TREE;
tree scope = NULL_TREE;
cp_token *closing_brace;
@@ -26818,6 +26859,10 @@ cp_parser_class_specifier (cp_parser* parser)
saved_in_unbraced_linkage_specification_p
= parser->in_unbraced_linkage_specification_p;
parser->in_unbraced_linkage_specification_p = false;
+ /* Or in an export-declaration. */
+ saved_in_unbraced_export_declaration_p
+ = parser->in_unbraced_export_declaration_p;
+ parser->in_unbraced_export_declaration_p = false;
/* 'this' from an enclosing non-static member function is unavailable. */
tree saved_ccp = current_class_ptr;
tree saved_ccr = current_class_ref;
@@ -27200,6 +27245,8 @@ cp_parser_class_specifier (cp_parser* parser)
= saved_num_template_parameter_lists;
parser->in_unbraced_linkage_specification_p
= saved_in_unbraced_linkage_specification_p;
+ parser->in_unbraced_export_declaration_p
+ = saved_in_unbraced_export_declaration_p;
current_class_ptr = saved_ccp;
current_class_ref = saved_ccr;
@@ -27487,6 +27534,20 @@ cp_parser_class_head (cp_parser* parser,
permerror (nested_name_specifier_token_start->location,
"extra qualification not allowed");
}
+ /* The name-declaration of an export-declaration shall not declare
+ a partial specialization. */
+ if (template_id_p
+ && parser->in_unbraced_export_declaration_p
+ && !processing_specialization
+ && !processing_explicit_instantiation)
+ {
+ auto_diagnostic_group d;
+ location_t loc = type_start_token->location;
+ error_at (loc, "declaration of partial specialization in unbraced "
+ "export-declaration");
+ inform (loc, "a specialization is always exported alongside its "
+ "primary template");
+ }
/* An explicit-specialization must be preceded by "template <>". If
it is not, try to recover gracefully. */
if (at_namespace_scope_p ()
@@ -312,9 +312,13 @@ struct GTY(()) cp_parser {
/* TRUE if the declaration we are parsing is part of a
linkage-specification of the form `extern string-literal
- declaration'. */
+ name-declaration'. */
bool in_unbraced_linkage_specification_p;
+ /* TRUE if the declaration we are parsing is part of an
+ export-declaration of the form 'export name-declaration'. */
+ bool in_unbraced_export_declaration_p;
+
/* TRUE if we are presently parsing a declarator, after the
direct-declarator. */
bool in_declarator_p;
new file mode 100644
@@ -0,0 +1,22 @@
+// PR c++/107688
+// P2615R1: Meaningful exports: Newly invalid declarations
+// { dg-do compile { target c++11 } }
+
+extern "C++" template <typename T> struct A {};
+
+extern "C++" template <typename T> struct A<T*> {};
+
+extern "C++" template <> struct A<int*> {};
+// { dg-error "explicit specializations are not permitted here" "" { target c++20 } .-1 }
+
+extern "C++" template struct A<int>;
+// { dg-error "explicit instantiations are not permitted here" "" { target c++20 } .-1 }
+
+
+// These should all still be valid, though
+extern "C++" {
+ template <typename T> struct B {};
+ template <typename T> struct B<T*> {};
+ template <> struct B<int*> {};
+ template struct B<int>;
+}
@@ -8,7 +8,7 @@ export module foo;
// { dg-module-cmi foo }
export int violation_count{0};
-extern "C++" export void handle_contract_violation(const std::experimental::contract_violation &violation)
+export extern "C++" void handle_contract_violation(const std::experimental::contract_violation &violation)
{
violation_count++;
printf("violation_count: %d\n", violation_count);
@@ -12,7 +12,7 @@ export module foo;
export int violation_count{0};
export int violation_line_sum{0};
-extern "C++" export void handle_contract_violation(const std::experimental::contract_violation &violation)
+export extern "C++" void handle_contract_violation(const std::experimental::contract_violation &violation)
{
violation_count++;
violation_line_sum += violation.line_number () * violation_count;
@@ -8,7 +8,7 @@ export module foo;
// { dg-module-cmi foo }
export int violation_count{0};
-extern "C++" export void handle_contract_violation(const std::experimental::contract_violation &violation)
+export extern "C++" void handle_contract_violation(const std::experimental::contract_violation &violation)
{
violation_count++;
printf("violation_count: %d\n", violation_count);
@@ -9,7 +9,7 @@ export module foo;
// { dg-module-cmi foo }
export int violation_count{0};
-extern "C++" export void handle_contract_violation(const std::experimental::contract_violation &violation)
+export extern "C++" void handle_contract_violation(const std::experimental::contract_violation &violation)
{
violation_count++;
printf("violation_count: %d\n", violation_count);
new file mode 100644
@@ -0,0 +1,30 @@
+// P2615R1 invalid declarations
+// PR c++/107688
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi !bad }
+
+export module bad;
+
+extern "C++" export void foo(); // { dg-error "export-declarations are not permitted here" "" { target c++20 } }
+
+export template <typename T> struct S {};
+
+export template <typename T> struct S<T*> {}; // { dg-error "partial specialization in unbraced export-declaration" }
+
+export template <> struct S<int*> {}; // { dg-error "explicit specializations are not permitted here" }
+
+export template struct S<int>; // { dg-error "explicit instantiations are not permitted here" }
+
+template <> export struct S<double>; // { dg-error "expected unqualified-id" }
+
+export export int x; // { dg-error ".export. may only occur once" }
+
+export { export int y; } // { dg-error ".export. may only occur once" }
+
+namespace {
+ export namespace ns {} // { dg-error "internal linkage" }
+}
+
+export namespace {} // { dg-error "internal linkage" }
+
+// { dg-prune-output "not writing module" }
new file mode 100644
@@ -0,0 +1,23 @@
+// P2615R1 valid declarations
+// PR c++/107688
+// { dg-additional-options "-fmodules-ts" }
+// { dg-module-cmi M }
+
+export module M;
+
+export {}
+export { static_assert(true); }
+
+export namespace Empty {}
+export using namespace Empty;
+
+export {
+ template <typename T> struct S {};
+ template <typename T> struct S<T*> { using a = int; };
+ template <> struct S<int*> { using b = int; };
+ template struct S<int>;
+}
+
+extern "C++" {
+ export void foo();
+}
new file mode 100644
@@ -0,0 +1,13 @@
+// PR c++/107688
+// { dg-additional-options "-fmodules-ts" }
+
+import M;
+
+using namespace Empty;
+
+int main() {
+ S<int> x;
+ S<int*>::b y;
+ S<int**>::a z;
+ foo();
+}
@@ -6,7 +6,7 @@ extern "C++"
}
extern "C"
-import "lang-1_a.H"; // { dg-error "cannot appear directly" }
+ import "lang-1_a.H"; // OK since p2615r1
extern "C" int cfunc (int); // { dg-error "conflicting declaration" }
extern "C" int cxxfunc (int);
@@ -1,3 +1,5 @@
// PR c++/30659
-extern "C" template A<char> foo(); // { dg-error "forbids|static data|expected|template" }
+extern "C" template A<char> foo();
+// { dg-error "forbids|static data|expected|template" "" { target c++17_down } .-1 }
+// { dg-error "permitted|forbids|static data|expected|template" "" { target c++20 } .-2 }