mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-31 15:31:11 +08:00
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:
parent
be279f8651
commit
1dec70fa4c
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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. */
|
||||
|
60
gcc/cp/pt.c
60
gcc/cp/pt.c
@ -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
|
||||
|
@ -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
|
||||
|
18
gcc/testsuite/g++.dg/parse/error50.C
Normal file
18
gcc/testsuite/g++.dg/parse/error50.C
Normal 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" }
|
Loading…
x
Reference in New Issue
Block a user