@@ -20264,6 +20264,34 @@ cp_parser_class_head (cp_parser* parser,
}
virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
+ /* Make sure a top-level template-id declaration or definition is preceded
+ by "template" or "template <>". */
+ if (template_id_p
+ && at_namespace_scope_p ()
+ && parser->num_template_parameter_lists == 0
+ && !processing_explicit_instantiation)
+ {
+ if (cp_parser_next_token_starts_class_definition_p (parser))
+ {
+ error_at (type_start_token->location,
+ "an explicit specialization must be preceded by "
+ "%<template <>%>");
+ invalid_explicit_specialization_p = true;
+ /* Try to recover gracefully by taking the same action that would
+ have been taken by cp_parser_explicit_specialization. */
+ ++parser->num_template_parameter_lists;
+ begin_specialization ();
+ }
+ else if (cp_parser_declares_only_class_p (parser))
+ {
+ error_at (type_start_token->location,
+ "an explicit instantiation must be preceded by "
+ "%<template%>");
+ type = error_mark_node;
+ goto out;
+ }
+ }
+
/* If it's not a `:' or a `{' then we can't really be looking at a
class-head, since a class-head only appears as part of a
class-specifier. We have to detect this situation before calling
@@ -20275,6 +20303,16 @@ cp_parser_class_head (cp_parser* parser,
goto out;
}
+ if (processing_explicit_instantiation)
+ {
+ error_at (type_start_token->location,
+ "an explicit instantiation may not have a definition");
+ inform (type_start_token->location,
+ "use %<template <>%> to define an explicit specialization");
+ type = error_mark_node;
+ goto out;
+ }
+
/* At this point, we're going ahead with the class-specifier, even
if some other problem occurs. */
cp_parser_commit_to_tentative_parse (parser);
@@ -20346,20 +20384,7 @@ cp_parser_class_head (cp_parser* parser,
num_templates = 0;
}
}
- /* An explicit-specialization must be preceded by "template <>". If
- it is not, try to recover gracefully. */
- if (at_namespace_scope_p ()
- && parser->num_template_parameter_lists == 0
- && template_id_p)
- {
- error_at (type_start_token->location,
- "an explicit specialization must be preceded by %<template <>%>");
- invalid_explicit_specialization_p = true;
- /* Take the same action that would have been taken by
- cp_parser_explicit_specialization. */
- ++parser->num_template_parameter_lists;
- begin_specialization ();
- }
+
/* There must be no "return" statements between this point and the
end of this function; set "type "to the correct return value and
use "goto done;" to return. */
@@ -9,4 +9,4 @@ enum [[gnu::unused]] e; // { dg-warning "already defined" }
struct [[gnu::unused]] B *p; // { dg-warning "attributes" }
template <class T> struct A { };
-struct [[gnu::unused]] A<int>; // { dg-warning "attributes" }
+struct [[gnu::unused]] A<int> y; // { dg-warning "attributes" }
@@ -7,4 +7,4 @@ enum __attribute__((unused)) e; // { dg-warning "already defined" }
struct __attribute((unused)) B *p; // { dg-warning "attributes" }
template <class T> struct A { };
-struct __attribute((unused)) A<int>; // { dg-warning "attributes" }
+struct __attribute((unused)) A<int> y; // { dg-warning "attributes" }
@@ -2,4 +2,4 @@
template<int> struct A;
-struct __attribute__((unused)) A<0<; // { dg-error "template argument|unqualified-id" }
+template<> struct __attribute__((unused)) A<0<; // { dg-error "template argument|unqualified-id" }
new file mode 100644
@@ -0,0 +1,11 @@
+// PR c++/16160
+
+template <int N> struct X { };
+template <int N> struct Y { };
+template <int N> struct Z { };
+
+struct X<2>; // { dg-error "explicit instantiation" }
+
+struct Y<2> { }; // { dg-error "explicit specialization" }
+
+template struct Z<2> { }; // { dg-error "may not have a definition" }
@@ -11,10 +11,10 @@ void operator+ (int, bar&);
template <class T> class foo
{
public:
- friend void operator+ <> (int, T&);
+ friend void operator+ <> (int, T&); // { dg-error "int&" }
};
class baz;
-class foo<int>;
-class foo<baz>;
+template class foo<int>;
+template class foo<baz>;
@@ -1,5 +1,6 @@
// { dg-do assemble }
template <class T> class A;
+
// template <>
-class A<int>; // { dg-error "" "" { xfail *-*-* } } missing template header -
+class A<int>; // { dg-error "explicit instantiation" }