re PR c++/18747 ("template<> int i;" accepted)

PR c++/18747
	* pt.c (check_template_variable): New.
	(num_template_headers_for_class): Split out...
	* decl.c (grokdeclarator): ...from here.
	(start_decl): Remove redundant diagnostic.
	* cp-tree.h: Declare them
	* parser.c (cp_parser_single_declaration): Call check_template_variable.
.
Co-Authored-By: Jason Merrill <jason@redhat.com>

From-SVN: r190842
This commit is contained in:
Paolo Carlini 2012-08-31 21:35:33 +00:00 committed by Jason Merrill
parent be279f8651
commit 1dec70fa4c
7 changed files with 103 additions and 35 deletions

View File

@ -1,3 +1,14 @@
2012-08-31 Paolo Carlini <paolo.carlini@oracle.com>
Jason Merrill <jason@redhat.com>
PR c++/18747
* pt.c (check_template_variable): New.
(num_template_headers_for_class): Split out...
* decl.c (grokdeclarator): ...from here.
(start_decl): Remove redundant diagnostic.
* cp-tree.h: Declare them
* parser.c (cp_parser_single_declaration): Call check_template_variable.
2012-08-31 Ollie Wild <aaw@google.com>
PR c++/54197

View File

@ -5316,6 +5316,8 @@ extern void end_specialization (void);
extern void begin_explicit_instantiation (void);
extern void end_explicit_instantiation (void);
extern tree check_explicit_specialization (tree, tree, int, int);
extern int num_template_headers_for_class (tree);
extern void check_template_variable (tree);
extern tree make_auto (void);
extern tree do_auto_deduction (tree, tree, tree);
extern tree type_uses_auto (tree);

View File

@ -4461,11 +4461,6 @@ start_decl (const cp_declarator *declarator,
context, DECL_NAME (decl));
DECL_CONTEXT (decl) = DECL_CONTEXT (field);
}
if (processing_specialization
&& template_class_depth (context) == 0
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (context))
error ("template header not allowed in member definition "
"of explicitly specialized class");
/* Static data member are tricky; an in-class initialization
still doesn't provide a definition, so the in-class
declaration will have DECL_EXTERNAL set, but will have an
@ -9564,36 +9559,9 @@ grokdeclarator (const cp_declarator *declarator,
&& declarator->u.id.qualifying_scope
&& MAYBE_CLASS_TYPE_P (declarator->u.id.qualifying_scope))
{
tree t;
ctype = declarator->u.id.qualifying_scope;
ctype = TYPE_MAIN_VARIANT (ctype);
t = ctype;
while (t != NULL_TREE && CLASS_TYPE_P (t))
{
/* You're supposed to have one `template <...>' for every
template class, but you don't need one for a full
specialization. For example:
template <class T> struct S{};
template <> struct S<int> { void f(); };
void S<int>::f () {}
is correct; there shouldn't be a `template <>' for the
definition of `S<int>::f'. */
if (CLASSTYPE_TEMPLATE_SPECIALIZATION (t)
&& !any_dependent_template_arguments_p (CLASSTYPE_TI_ARGS (t)))
/* T is an explicit (not partial) specialization. All
containing classes must therefore also be explicitly
specialized. */
break;
if ((CLASSTYPE_USE_TEMPLATE (t) || CLASSTYPE_IS_TEMPLATE (t))
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)))
template_count += 1;
t = TYPE_MAIN_DECL (t);
t = DECL_CONTEXT (t);
}
template_count = num_template_headers_for_class (ctype);
if (ctype == current_class_type)
{

View File

@ -21310,8 +21310,8 @@ cp_parser_perform_template_parameter_access_checks (VEC (deferred_access_check,g
}
/* Parse a `decl-specifier-seq [opt] init-declarator [opt] ;' or
`function-definition' sequence. MEMBER_P is true, this declaration
appears in a class scope.
`function-definition' sequence that follows a template header.
If MEMBER_P is true, this declaration appears in a class scope.
Returns the DECL for the declared entity. If FRIEND_P is non-NULL,
*FRIEND_P is set to TRUE iff the declaration is a friend. */
@ -21431,6 +21431,9 @@ cp_parser_single_declaration (cp_parser* parser,
"explicit template specialization cannot have a storage class");
decl = error_mark_node;
}
if (decl && TREE_CODE (decl) == VAR_DECL)
check_template_variable (decl);
}
/* Look for a trailing `;' after the declaration. */

View File

@ -2208,6 +2208,66 @@ copy_default_args_to_explicit_spec (tree decl)
TREE_TYPE (decl) = new_type;
}
/* Return the number of template headers we expect to see for a definition
or specialization of CTYPE or one of its non-template members. */
int
num_template_headers_for_class (tree ctype)
{
int template_count = 0;
tree t = ctype;
while (t != NULL_TREE && CLASS_TYPE_P (t))
{
/* You're supposed to have one `template <...>' for every
template class, but you don't need one for a full
specialization. For example:
template <class T> struct S{};
template <> struct S<int> { void f(); };
void S<int>::f () {}
is correct; there shouldn't be a `template <>' for the
definition of `S<int>::f'. */
if (CLASSTYPE_TEMPLATE_SPECIALIZATION (t)
&& !any_dependent_template_arguments_p (CLASSTYPE_TI_ARGS (t)))
/* T is an explicit (not partial) specialization. All
containing classes must therefore also be explicitly
specialized. */
break;
if ((CLASSTYPE_USE_TEMPLATE (t) || CLASSTYPE_IS_TEMPLATE (t))
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)))
template_count += 1;
t = TYPE_MAIN_DECL (t);
t = DECL_CONTEXT (t);
}
return template_count;
}
/* Do a simple sanity check on the template headers that precede the
variable declaration DECL. */
void
check_template_variable (tree decl)
{
tree ctx = CP_DECL_CONTEXT (decl);
int wanted = num_template_headers_for_class (ctx);
if (!TYPE_P (ctx) || !CLASSTYPE_TEMPLATE_INFO (ctx))
permerror (DECL_SOURCE_LOCATION (decl),
"%qD is not a static data member of a class template", decl);
else if (template_header_count > wanted)
{
pedwarn (DECL_SOURCE_LOCATION (decl), 0,
"too many template headers for %D (should be %d)",
decl, wanted);
if (CLASSTYPE_TEMPLATE_SPECIALIZATION (ctx))
inform (DECL_SOURCE_LOCATION (decl),
"members of an explicitly specialized class are defined "
"without a template header");
}
}
/* Check to see if the function just declared, as indicated in
DECLARATOR, and in DECL, is a specialization of a function
template. We may also discover that the declaration is an explicit

View File

@ -1,3 +1,9 @@
2012-08-31 Paolo Carlini <paolo.carlini@oracle.com>
Jason Merrill <jason@redhat.com>
PR c++/18747
* g++.dg/parse/error50.C: New.
2012-08-31 Jakub Jelinek <jakub@redhat.com>
PR c/54428

View File

@ -0,0 +1,18 @@
// PR c++/18747
template<> int i; // { dg-error "template" }
struct A
{
static int i;
};
template<> int A::i; // { dg-error "template" }
template <class T>
struct B
{
static T i;
};
template<> template <> int B<int>::i; // { dg-error "should be 1" }