This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ Patch] PRs 9781 10310 (ICE with illegal template)
- From: Scott Brumbaugh <scottb dot lists at verizon dot net>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 28 Aug 2003 15:22:54 -0700 (PDT)
- Subject: [C++ Patch] PRs 9781 10310 (ICE with illegal template)
Hi,
This patch attempts to fix PRs 9781 and 10310. I think these two PRs
are similar. They involve ICEs happening during the parse of a
template-id. Simplifying the test cases in the bug reports, the core
of the problem can be illustrated with this ambiguous declaration:
int f(x);
If x were a type this would declare f as a function taking an x
argument. However, if x is not defined then cp_parser_init_declarator
will assume that the f(x) is a variable f initialized with the value
of x. Even though the parser will eventually figure out that x is not
a valid initializer, the identifier for f will still be entered into
the name lookup tables as a variable because cp_parser_init_declarator
will call start_decl passing it the identifier node for f before
attempting to parse the x initializer.
We can use the above picture of how the parser handles the function
argument/variable initializer ambiguity to understand what is going on
in this ICE. Take the following template declaration which is similar
to the code sample in the bug report:
template <class T> int f(x);
This could be the declaration of a function template if x is a known
type. But, if x is undefined this is an erroneous declaration. It is
this erroneous declaration case where the declarator is interpreted as
a variable with an initializer that causes the ICE. Here
cp_parser_init_declarator will see f as a variable declarator-id and
call start_decl which will call push_template_decl. So a
template-decl tree node gets created for an integer declaration and
entered into the current socpe. The next time f is parsed by
cp_parser_template_id, the template-decl node for the the integer
template f will trigger the assert and ICE.
I think the place to fix this is in the parser where the sytax error
can be first recognized. That is in cp_parser_init_declarator, after
f is parsed as a declarator-id for a variable f but before start_decl
is called to enter it into the symbol table. We need to let
cp_parser_init_declarator know that a variable declaration is not
allowed because we are declaring a template.
I added another bit-flag to the variable declares_class_or_enum that
is passed between the different declaration productions. This
variable is currently used to tell wether a declaration is a class
definition or just a class declaration. I added another bit to say
that the current declaration is a template declaration. With this
proliferation of flags, I created a new enumeration variable to hold
them called enum cp_parser_declaration_kind. Because the variable
covers more cases than just classes and enumerations, I changed the
name used for this variable throughout to decl_kind.
In cp_parser_init_declarator, if decl_kind is set to
CP_PARSER_DECLARES_TEMPLATE and the declarator just parsed is an identifier
node then we know that we should not enter this template declaration into
the symbol table, instead we flag an error and return.
Patching the parser in the productions this way catches the error
quickly, rather than adding more logic to the tree and symbol table
handling. But, I don't like adding more flags to be passed around
between the production functions. I think a cleaner fix would be to
separate cp_parser_init_declarator into two separate functions,
cp_parser_decl and cp_parser_decl_initializer. The productions that
use it could then use logic to detect syntax errors like this one or
class definitions in function return types without needing to pass
more arguments. A testcase is included at the end.
This patch was compiled in with make bootstrap and tested against
the current testsuite with make check-g++.
Thanks,
Scott Brumbaugh
2003-08-28 Scott Brumbaugh <scottb.lists@verizon.net>
PR C++ 9781 10310
* parser.c add cp_parser_declaration_kind enumeration.
rename declarse_class_or_enum variable to decl_kind and
add bit flag for template declaration.
(cp_parser_explicit_instantiation) Add check for
cp_parser_declarator returning an IDENTIFIER_NODE.
(cp_parser_init_declarator) Likewise.
Index: parser.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.105
diff -c -3 -p -r1.105 parser.c
*** parser.c 27 Aug 2003 00:49:19 -0000 1.105
--- parser.c 28 Aug 2003 17:44:59 -0000
*************** typedef enum cp_parser_flags
*** 1046,1051 ****
--- 1046,1066 ----
CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2
} cp_parser_flags;
+ /* The type of declaration that this is. Useful for error checking. */
+
+ typedef enum cp_parser_declaration_kind
+ {
+ /* Initializer for variables of this type. */
+ CP_PARSER_DECL_KIND_NONE = 0,
+ /* This declaration declares a class or enumeration. */
+ CP_PARSER_DECLARES_CLASS = 0x01,
+ /* This declaration is a class or enumeration definition. */
+ CP_PARSER_DEFINES_CLASS = 0x02,
+ /* We have seen the template keyword in this declaration. */
+ CP_PARSER_DECLARES_TEMPLATE = 0x08
+
+ } cp_parser_declaration_kind;
+
/* The different kinds of declarators we want to parse. */
typedef enum cp_parser_declarator_kind
*************** static void cp_parser_block_declaration
*** 1406,1418 ****
static void cp_parser_simple_declaration
(cp_parser *, bool);
static tree cp_parser_decl_specifier_seq
! (cp_parser *, cp_parser_flags, tree *, int *);
static tree cp_parser_storage_class_specifier_opt
(cp_parser *);
static tree cp_parser_function_specifier_opt
(cp_parser *);
static tree cp_parser_type_specifier
! (cp_parser *, cp_parser_flags, bool, bool, int *, bool *);
static tree cp_parser_simple_type_specifier
(cp_parser *, cp_parser_flags, bool);
static tree cp_parser_type_name
--- 1421,1433 ----
static void cp_parser_simple_declaration
(cp_parser *, bool);
static tree cp_parser_decl_specifier_seq
! (cp_parser *, cp_parser_flags, tree *, unsigned *);
static tree cp_parser_storage_class_specifier_opt
(cp_parser *);
static tree cp_parser_function_specifier_opt
(cp_parser *);
static tree cp_parser_type_specifier
! (cp_parser *, cp_parser_flags, bool, bool, unsigned *, bool *);
static tree cp_parser_simple_type_specifier
(cp_parser *, cp_parser_flags, bool);
static tree cp_parser_type_name
*************** static void cp_parser_linkage_specificat
*** 1447,1453 ****
/* Declarators [gram.dcl.decl] */
static tree cp_parser_init_declarator
! (cp_parser *, tree, tree, bool, bool, int, bool *);
static tree cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, int *);
static tree cp_parser_direct_declarator
--- 1462,1468 ----
/* Declarators [gram.dcl.decl] */
static tree cp_parser_init_declarator
! (cp_parser *, tree, tree, bool, bool, unsigned, bool *);
static tree cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, int *);
static tree cp_parser_direct_declarator
*************** static bool cp_parser_simulate_error
*** 1676,1682 ****
static void cp_parser_check_type_definition
(cp_parser *);
static void cp_parser_check_for_definition_in_return_type
! (tree, int);
static tree cp_parser_non_constant_expression
(const char *);
static bool cp_parser_diagnose_invalid_type_name
--- 1691,1697 ----
static void cp_parser_check_type_definition
(cp_parser *);
static void cp_parser_check_for_definition_in_return_type
! (tree, unsigned);
static tree cp_parser_non_constant_expression
(const char *);
static bool cp_parser_diagnose_invalid_type_name
*************** cp_parser_check_type_definition (cp_pars
*** 1773,1779 ****
static void
cp_parser_check_for_definition_in_return_type (tree declarator,
! int declares_class_or_enum)
{
/* [dcl.fct] forbids type definitions in return types.
Unfortunately, it's not easy to know whether or not we are
--- 1788,1794 ----
static void
cp_parser_check_for_definition_in_return_type (tree declarator,
! unsigned declares_class_or_enum)
{
/* [dcl.fct] forbids type definitions in return types.
Unfortunately, it's not easy to know whether or not we are
*************** cp_parser_check_for_definition_in_return
*** 1784,1790 ****
declarator = TREE_OPERAND (declarator, 0);
if (declarator
&& TREE_CODE (declarator) == CALL_EXPR
! && declares_class_or_enum & 2)
error ("new types may not be defined in a return type");
}
--- 1799,1805 ----
declarator = TREE_OPERAND (declarator, 0);
if (declarator
&& TREE_CODE (declarator) == CALL_EXPR
! && declares_class_or_enum & CP_PARSER_DEFINES_CLASS)
error ("new types may not be defined in a return type");
}
*************** cp_parser_simple_declaration (cp_parser*
*** 6088,6094 ****
{
tree decl_specifiers;
tree attributes;
! int declares_class_or_enum;
bool saw_declarator;
/* Defer access checks until we know what is being declared; the
--- 6103,6109 ----
{
tree decl_specifiers;
tree attributes;
! unsigned decl_kind = CP_PARSER_DECL_KIND_NONE;
bool saw_declarator;
/* Defer access checks until we know what is being declared; the
*************** cp_parser_simple_declaration (cp_parser*
*** 6111,6117 ****
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&attributes,
! &declares_class_or_enum);
/* We no longer need to defer access checks. */
stop_deferring_access_checks ();
--- 6126,6132 ----
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&attributes,
! &decl_kind);
/* We no longer need to defer access checks. */
stop_deferring_access_checks ();
*************** cp_parser_simple_declaration (cp_parser*
*** 6154,6160 ****
decl = cp_parser_init_declarator (parser, decl_specifiers, attributes,
function_definition_allowed_p,
/*member_p=*/false,
! declares_class_or_enum,
&function_definition_p);
/* If an error occurred while parsing tentatively, exit quickly.
(That usually happens when in the body of a function; each
--- 6169,6175 ----
decl = cp_parser_init_declarator (parser, decl_specifiers, attributes,
function_definition_allowed_p,
/*member_p=*/false,
! decl_kind,
&function_definition_p);
/* If an error occurred while parsing tentatively, exit quickly.
(That usually happens when in the body of a function; each
*************** cp_parser_simple_declaration (cp_parser*
*** 6261,6282 ****
1: one of the decl-specifiers is an elaborated-type-specifier
2: one of the decl-specifiers is an enum-specifier or a
class-specifier
-
*/
static tree
cp_parser_decl_specifier_seq (cp_parser* parser,
cp_parser_flags flags,
tree* attributes,
! int* declares_class_or_enum)
{
tree decl_specs = NULL_TREE;
bool friend_p = false;
bool constructor_possible_p = !parser->in_declarator_p;
- /* Assume no class or enumeration type is declared. */
- *declares_class_or_enum = 0;
-
/* Assume there are no attributes. */
*attributes = NULL_TREE;
--- 6276,6293 ----
1: one of the decl-specifiers is an elaborated-type-specifier
2: one of the decl-specifiers is an enum-specifier or a
class-specifier
*/
static tree
cp_parser_decl_specifier_seq (cp_parser* parser,
cp_parser_flags flags,
tree* attributes,
! unsigned* decl_kind)
{
tree decl_specs = NULL_TREE;
bool friend_p = false;
bool constructor_possible_p = !parser->in_declarator_p;
/* Assume there are no attributes. */
*attributes = NULL_TREE;
*************** cp_parser_decl_specifier_seq (cp_parser*
*** 6371,6377 ****
a type-specifier. */
if (!decl_spec && !constructor_p)
{
! int decl_spec_declares_class_or_enum;
bool is_cv_qualifier;
decl_spec
--- 6382,6388 ----
a type-specifier. */
if (!decl_spec && !constructor_p)
{
! unsigned decl_spec_declares_class_or_enum = CP_PARSER_DECL_KIND_NONE;
bool is_cv_qualifier;
decl_spec
*************** cp_parser_decl_specifier_seq (cp_parser*
*** 6381,6387 ****
&decl_spec_declares_class_or_enum,
&is_cv_qualifier);
! *declares_class_or_enum |= decl_spec_declares_class_or_enum;
/* If this type-specifier referenced a user-defined type
(a typedef, class-name, etc.), then we can't allow any
--- 6392,6398 ----
&decl_spec_declares_class_or_enum,
&is_cv_qualifier);
! *decl_kind |= decl_spec_declares_class_or_enum;
/* If this type-specifier referenced a user-defined type
(a typedef, class-name, etc.), then we can't allow any
*************** cp_parser_template_argument (cp_parser*
*** 7969,7975 ****
static void
cp_parser_explicit_instantiation (cp_parser* parser)
{
! int declares_class_or_enum;
tree decl_specifiers;
tree attributes;
tree extension_specifier = NULL_TREE;
--- 7980,7986 ----
static void
cp_parser_explicit_instantiation (cp_parser* parser)
{
! unsigned decl_kind = CP_PARSER_DECL_KIND_NONE;
tree decl_specifiers;
tree attributes;
tree extension_specifier = NULL_TREE;
*************** cp_parser_explicit_instantiation (cp_par
*** 7997,8007 ****
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&attributes,
! &declares_class_or_enum);
/* If there was exactly one decl-specifier, and it declared a class,
and there's no declarator, then we have an explicit type
instantiation. */
! if (declares_class_or_enum && cp_parser_declares_only_class_p (parser))
{
tree type;
--- 8008,8018 ----
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&attributes,
! &decl_kind);
/* If there was exactly one decl-specifier, and it declared a class,
and there's no declarator, then we have an explicit type
instantiation. */
! if ((decl_kind & CP_PARSER_DECLARES_CLASS) && cp_parser_declares_only_class_p (parser))
{
tree type;
*************** cp_parser_explicit_instantiation (cp_par
*** 8022,8035 ****
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
/*ctor_dtor_or_conv_p=*/NULL);
cp_parser_check_for_definition_in_return_type (declarator,
! declares_class_or_enum);
! decl = grokdeclarator (declarator, decl_specifiers,
! NORMAL, 0, NULL);
! /* Turn access control back on for names used during
! template instantiation. */
! pop_deferring_access_checks ();
! /* Do the explicit instantiation. */
! do_decl_instantiation (decl, extension_specifier);
}
/* We're done with the instantiation. */
end_explicit_instantiation ();
--- 8033,8054 ----
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
/*ctor_dtor_or_conv_p=*/NULL);
cp_parser_check_for_definition_in_return_type (declarator,
! decl_kind);
!
! if (TREE_CODE (declarator) == IDENTIFIER_NODE)
! {
! error ("explicit instantiation of non-template `%D'", declarator);
! }
! else
! {
! decl = grokdeclarator (declarator, decl_specifiers,
! NORMAL, 0, NULL);
! /* Turn access control back on for names used during
! template instantiation. */
! pop_deferring_access_checks ();
! /* Do the explicit instantiation. */
! do_decl_instantiation (decl, extension_specifier);
! }
}
/* We're done with the instantiation. */
end_explicit_instantiation ();
*************** cp_parser_type_specifier (cp_parser* par
*** 8126,8132 ****
cp_parser_flags flags,
bool is_friend,
bool is_declaration,
! int* declares_class_or_enum,
bool* is_cv_qualifier)
{
tree type_spec = NULL_TREE;
--- 8145,8151 ----
cp_parser_flags flags,
bool is_friend,
bool is_declaration,
! unsigned* declares_class_or_enum,
bool* is_cv_qualifier)
{
tree type_spec = NULL_TREE;
*************** cp_parser_type_specifier (cp_parser* par
*** 8135,8141 ****
/* Assume this type-specifier does not declare a new type. */
if (declares_class_or_enum)
! *declares_class_or_enum = false;
/* And that it does not specify a cv-qualifier. */
if (is_cv_qualifier)
*is_cv_qualifier = false;
--- 8154,8162 ----
/* Assume this type-specifier does not declare a new type. */
if (declares_class_or_enum)
! *declares_class_or_enum &=
! ~(CP_PARSER_DECLARES_CLASS | CP_PARSER_DEFINES_CLASS);
!
/* And that it does not specify a cv-qualifier. */
if (is_cv_qualifier)
*is_cv_qualifier = false;
*************** cp_parser_type_specifier (cp_parser* par
*** 8166,8172 ****
if (cp_parser_parse_definitely (parser))
{
if (declares_class_or_enum)
! *declares_class_or_enum = 2;
return type_spec;
}
--- 8187,8193 ----
if (cp_parser_parse_definitely (parser))
{
if (declares_class_or_enum)
! *declares_class_or_enum |= CP_PARSER_DEFINES_CLASS;
return type_spec;
}
*************** cp_parser_type_specifier (cp_parser* par
*** 8180,8186 ****
/* We're declaring a class or enum -- unless we're using
`typename'. */
if (declares_class_or_enum && keyword != RID_TYPENAME)
! *declares_class_or_enum = 1;
return type_spec;
case RID_CONST:
--- 8201,8207 ----
/* We're declaring a class or enum -- unless we're using
`typename'. */
if (declares_class_or_enum && keyword != RID_TYPENAME)
! *declares_class_or_enum |= CP_PARSER_DECLARES_CLASS;
return type_spec;
case RID_CONST:
*************** cp_parser_init_declarator (cp_parser* pa
*** 9264,9270 ****
tree prefix_attributes,
bool function_definition_allowed_p,
bool member_p,
! int declares_class_or_enum,
bool* function_definition_p)
{
cp_token *token;
--- 9285,9291 ----
tree prefix_attributes,
bool function_definition_allowed_p,
bool member_p,
! unsigned class_enum_or_templ,
bool* function_definition_p)
{
cp_token *token;
*************** cp_parser_init_declarator (cp_parser* pa
*** 9303,9309 ****
return error_mark_node;
cp_parser_check_for_definition_in_return_type (declarator,
! declares_class_or_enum);
/* Figure out what scope the entity declared by the DECLARATOR is
located in. `grokdeclarator' sometimes changes the scope, so
--- 9324,9340 ----
return error_mark_node;
cp_parser_check_for_definition_in_return_type (declarator,
! class_enum_or_templ);
!
!
! if (class_enum_or_templ &&
! class_enum_or_templ & CP_PARSER_DECLARES_TEMPLATE
! && TREE_CODE (declarator) == IDENTIFIER_NODE
! && !member_p)
! {
! error ("template declaration of `%D'", declarator);
! return error_mark_node;
! }
/* Figure out what scope the entity declared by the DECLARATOR is
located in. `grokdeclarator' sometimes changes the scope, so
*************** static tree
*** 10434,10440 ****
cp_parser_parameter_declaration (cp_parser *parser,
bool template_parm_p)
{
! int declares_class_or_enum;
bool greater_than_is_operator_p;
tree decl_specifiers;
tree attributes;
--- 10465,10471 ----
cp_parser_parameter_declaration (cp_parser *parser,
bool template_parm_p)
{
! unsigned decl_kind = CP_PARSER_DECL_KIND_NONE;
bool greater_than_is_operator_p;
tree decl_specifiers;
tree attributes;
*************** cp_parser_parameter_declaration (cp_pars
*** 10464,10470 ****
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_NONE,
&attributes,
! &declares_class_or_enum);
/* If an error occurred, there's no reason to attempt to parse the
rest of the declaration. */
if (cp_parser_error_occurred (parser))
--- 10495,10501 ----
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_NONE,
&attributes,
! &decl_kind);
/* If an error occurred, there's no reason to attempt to parse the
rest of the declaration. */
if (cp_parser_error_occurred (parser))
*************** cp_parser_function_definition (cp_parser
*** 10669,10675 ****
tree declarator;
tree fn;
cp_token *token;
! int declares_class_or_enum;
bool member_p;
/* The saved value of the PEDANTIC flag. */
int saved_pedantic;
--- 10700,10706 ----
tree declarator;
tree fn;
cp_token *token;
! unsigned decl_kind = CP_PARSER_DECL_KIND_NONE;
bool member_p;
/* The saved value of the PEDANTIC flag. */
int saved_pedantic;
*************** cp_parser_function_definition (cp_parser
*** 10705,10711 ****
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&attributes,
! &declares_class_or_enum);
/* Figure out whether this declaration is a `friend'. */
if (friend_p)
*friend_p = cp_parser_friend_p (decl_specifiers);
--- 10736,10742 ----
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&attributes,
! &decl_kind);
/* Figure out whether this declaration is a `friend'. */
if (friend_p)
*friend_p = cp_parser_friend_p (decl_specifiers);
*************** cp_parser_function_definition (cp_parser
*** 10744,10750 ****
}
cp_parser_check_for_definition_in_return_type (declarator,
! declares_class_or_enum);
/* If we are in a class scope, then we must handle
function-definitions specially. In particular, we save away the
--- 10775,10781 ----
}
cp_parser_check_for_definition_in_return_type (declarator,
! decl_kind);
/* If we are in a class scope, then we must handle
function-definitions specially. In particular, we save away the
*************** cp_parser_member_declaration (cp_parser*
*** 11725,11731 ****
tree decl_specifiers;
tree prefix_attributes;
tree decl;
! int declares_class_or_enum;
bool friend_p;
cp_token *token;
int saved_pedantic;
--- 11756,11762 ----
tree decl_specifiers;
tree prefix_attributes;
tree decl;
! unsigned decl_kind = CP_PARSER_DECL_KIND_NONE;
bool friend_p;
cp_token *token;
int saved_pedantic;
*************** cp_parser_member_declaration (cp_parser*
*** 11768,11774 ****
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&prefix_attributes,
! &declares_class_or_enum);
/* Check for an invalid type-name. */
if (cp_parser_diagnose_invalid_type_name (parser))
return;
--- 11799,11805 ----
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&prefix_attributes,
! &decl_kind);
/* Check for an invalid type-name. */
if (cp_parser_diagnose_invalid_type_name (parser))
return;
*************** cp_parser_member_declaration (cp_parser*
*** 11805,11811 ****
{
/* If the `friend' keyword was present, the friend must
be introduced with a class-key. */
! if (!declares_class_or_enum)
error ("a class-key must be used when declaring a friend");
/* In this case:
--- 11836,11842 ----
{
/* If the `friend' keyword was present, the friend must
be introduced with a class-key. */
! if (!decl_kind & CP_PARSER_DECLARES_CLASS)
error ("a class-key must be used when declaring a friend");
/* In this case:
*************** cp_parser_member_declaration (cp_parser*
*** 11940,11946 ****
}
cp_parser_check_for_definition_in_return_type
! (declarator, declares_class_or_enum);
/* Look for an asm-specification. */
asm_specification = cp_parser_asm_specification_opt (parser);
--- 11971,11977 ----
}
cp_parser_check_for_definition_in_return_type
! (declarator, decl_kind);
/* Look for an asm-specification. */
asm_specification = cp_parser_asm_specification_opt (parser);
*************** cp_parser_constructor_declarator_p (cp_p
*** 13462,13468 ****
CP_PARSER_FLAGS_NONE,
/*is_friend=*/false,
/*is_declarator=*/true,
! /*declares_class_or_enum=*/NULL,
/*is_cv_qualifier=*/NULL);
/* Leave the scope of the class. */
if (type)
--- 13493,13499 ----
CP_PARSER_FLAGS_NONE,
/*is_friend=*/false,
/*is_declarator=*/true,
! /*decl_kind=*/NULL,
/*is_cv_qualifier=*/NULL);
/* Leave the scope of the class. */
if (type)
*************** cp_parser_single_declaration (cp_parser*
*** 13674,13680 ****
bool member_p,
bool* friend_p)
{
! int declares_class_or_enum;
tree decl = NULL_TREE;
tree decl_specifiers;
tree attributes;
--- 13705,13711 ----
bool member_p,
bool* friend_p)
{
! unsigned decl_kind = CP_PARSER_DECLARES_TEMPLATE;
tree decl = NULL_TREE;
tree decl_specifiers;
tree attributes;
*************** cp_parser_single_declaration (cp_parser*
*** 13691,13703 ****
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&attributes,
! &declares_class_or_enum);
/* Gather up the access checks that occurred the
decl-specifier-seq. */
stop_deferring_access_checks ();
/* Check for the declaration of a template class. */
! if (declares_class_or_enum)
{
if (cp_parser_declares_only_class_p (parser))
{
--- 13722,13735 ----
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&attributes,
! &decl_kind);
/* Gather up the access checks that occurred the
decl-specifier-seq. */
stop_deferring_access_checks ();
/* Check for the declaration of a template class. */
! if (decl_kind &
! (CP_PARSER_DECLARES_CLASS | CP_PARSER_DEFINES_CLASS))
{
if (cp_parser_declares_only_class_p (parser))
{
*************** cp_parser_single_declaration (cp_parser*
*** 13718,13730 ****
if (!decl
&& (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
|| !value_member (error_mark_node, decl_specifiers)))
! decl = cp_parser_init_declarator (parser,
! decl_specifiers,
! attributes,
! /*function_definition_allowed_p=*/false,
! member_p,
! declares_class_or_enum,
! /*function_definition_p=*/NULL);
pop_deferring_access_checks ();
--- 13750,13762 ----
if (!decl
&& (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
|| !value_member (error_mark_node, decl_specifiers)))
! decl = cp_parser_init_declarator (parser,
! decl_specifiers,
! attributes,
! /*function_definition_allowed_p=*/false,
! member_p,
! decl_kind,
! /*function_definition_p=*/NULL);
pop_deferring_access_checks ();
// { dg-do compile }
//
// PR 9781 10310
template<bool> void foo(BOGUS) { // { dg-error "" }
sizeof (BOGUS);
}
template void foo<true>(BOGUS); // { dg-error "" }
template void operator<<(int, foo<int>); // { dg-error "" }