re PR c++/27102 (ICE with invalid class name in function template)
PR c++/27102 * class.c (currently_open_class): Tidy. * decl.c (grokdeclarator): If we encounter an erroneous declarator, assume that we have already issued an error message and return. Return error_mark_node instead of NULL_TREE in more places. Issue errors about function definitions that do not have a function declarator. Check for complete types for all function definitions. * cp-tree.h (cp_error_declarator): Remove. (currently_open_class): Change return type. * parser.c (cp_parser_id_expression): Add optional_p parameter. (cp_parser_parse_diagnose_invalid_type_name): Adjust calls. (cp_parser_id_expression): Likewise. (cp_parser_unqualified_id): If the name is optional, return NULL_TREE. (cp_parser_postfix_dot_deref_expression): Adjust calls. (cp_parser_type_parameter): Likewise. (cp_parser_unqualified_id): Likewise. (cp_parser_direct_declarator): Likewise. (cp_parser_declarator_id): Add optional_p parameter. (cp_parser_function_definition_from_specifiers_and_declarator): Assume that start_function indicates failure only if it has issued an error. (cp_parser_omp_var_list_no_open): Adjust calls. PR c++/27102 * g++.dg/template/crash35.C: Tweak error markers. * g++.dg/template/crash46.C: New test. * g++.old-deja/g++.brendan/friend4.C: Tweak error markers. * g++.old-deja/g++.pt/incomplete1.C: Likewise. From-SVN: r113081
This commit is contained in:
parent
74c96e0c14
commit
fa6098f817
|
@ -1,3 +1,30 @@
|
|||
2006-04-19 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
PR c++/27102
|
||||
* class.c (currently_open_class): Tidy.
|
||||
* decl.c (grokdeclarator): If we encounter an erroneous
|
||||
declarator, assume that we have already issued an error message
|
||||
and return. Return error_mark_node instead of NULL_TREE in more
|
||||
places. Issue errors about function definitions that do not have
|
||||
a function declarator. Check for complete types for all function
|
||||
definitions.
|
||||
* cp-tree.h (cp_error_declarator): Remove.
|
||||
(currently_open_class): Change return type.
|
||||
* parser.c (cp_parser_id_expression): Add optional_p parameter.
|
||||
(cp_parser_parse_diagnose_invalid_type_name): Adjust calls.
|
||||
(cp_parser_id_expression): Likewise.
|
||||
(cp_parser_unqualified_id): If the name is optional, return
|
||||
NULL_TREE.
|
||||
(cp_parser_postfix_dot_deref_expression): Adjust calls.
|
||||
(cp_parser_type_parameter): Likewise.
|
||||
(cp_parser_unqualified_id): Likewise.
|
||||
(cp_parser_direct_declarator): Likewise.
|
||||
(cp_parser_declarator_id): Add optional_p parameter.
|
||||
(cp_parser_function_definition_from_specifiers_and_declarator):
|
||||
Assume that start_function indicates failure only if it has issued
|
||||
an error.
|
||||
(cp_parser_omp_var_list_no_open): Adjust calls.
|
||||
|
||||
2006-04-17 Janis Johnson <janis187@us.ibm.com>
|
||||
|
||||
PR c++/26114, c++/26115
|
||||
|
|
|
@ -5496,25 +5496,33 @@ pop_class_stack (void)
|
|||
--current_class_stack[current_class_depth - 1].hidden;
|
||||
}
|
||||
|
||||
/* Returns 1 if current_class_type is either T or a nested type of T.
|
||||
We start looking from 1 because entry 0 is from global scope, and has
|
||||
no type. */
|
||||
/* Returns 1 if the class type currently being defined is either T or
|
||||
a nested type of T. */
|
||||
|
||||
int
|
||||
bool
|
||||
currently_open_class (tree t)
|
||||
{
|
||||
int i;
|
||||
if (current_class_type && same_type_p (t, current_class_type))
|
||||
return 1;
|
||||
for (i = current_class_depth - 1; i > 0; --i)
|
||||
|
||||
/* We start looking from 1 because entry 0 is from global scope,
|
||||
and has no type. */
|
||||
for (i = current_class_depth; i > 0; --i)
|
||||
{
|
||||
if (current_class_stack[i].hidden)
|
||||
break;
|
||||
if (current_class_stack[i].type
|
||||
&& same_type_p (current_class_stack [i].type, t))
|
||||
return 1;
|
||||
tree c;
|
||||
if (i == current_class_depth)
|
||||
c = current_class_type;
|
||||
else
|
||||
{
|
||||
if (current_class_stack[i].hidden)
|
||||
break;
|
||||
c = current_class_stack[i].type;
|
||||
}
|
||||
if (!c)
|
||||
continue;
|
||||
if (same_type_p (c, t))
|
||||
return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If either current_class_type or one of its enclosing classes are derived
|
||||
|
|
|
@ -3691,9 +3691,6 @@ struct cp_declarator {
|
|||
} u;
|
||||
};
|
||||
|
||||
/* An erroneous declarator. */
|
||||
extern cp_declarator *cp_error_declarator;
|
||||
|
||||
/* A parameter list indicating for a function with no parameters,
|
||||
e.g "int f(void)". */
|
||||
extern cp_parameter_declarator *no_parameters;
|
||||
|
@ -3750,7 +3747,7 @@ extern tree get_vtable_decl (tree, int);
|
|||
extern void resort_type_method_vec (void *, void *,
|
||||
gt_pointer_operator, void *);
|
||||
extern bool add_method (tree, tree, tree);
|
||||
extern int currently_open_class (tree);
|
||||
extern bool currently_open_class (tree);
|
||||
extern tree currently_open_derived_class (tree);
|
||||
extern tree finish_struct (tree, tree);
|
||||
extern void finish_struct_1 (tree);
|
||||
|
|
|
@ -6956,7 +6956,7 @@ grokdeclarator (const cp_declarator *declarator,
|
|||
break;
|
||||
|
||||
case cdk_error:
|
||||
break;
|
||||
return error_mark_node;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
|
@ -6966,11 +6966,15 @@ grokdeclarator (const cp_declarator *declarator,
|
|||
break;
|
||||
}
|
||||
|
||||
/* A function definition's declarator must have the form of
|
||||
a function declarator. */
|
||||
|
||||
/* [dcl.fct.edf]
|
||||
|
||||
The declarator in a function-definition shall have the form
|
||||
D1 ( parameter-declaration-clause) ... */
|
||||
if (funcdef_flag && innermost_code != cdk_function)
|
||||
return NULL_TREE;
|
||||
{
|
||||
error ("function definition does not declare parameters");
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
if (((dname && IDENTIFIER_OPNAME_P (dname)) || flags == TYPENAME_FLAG)
|
||||
&& innermost_code != cdk_function
|
||||
|
@ -7711,6 +7715,20 @@ grokdeclarator (const cp_declarator *declarator,
|
|||
pedwarn ("extra qualification %<%T::%> on member %qs",
|
||||
ctype, name);
|
||||
}
|
||||
else if (/* If the qualifying type is already complete, then we
|
||||
can skip the following checks. */
|
||||
!COMPLETE_TYPE_P (ctype)
|
||||
/* If a function is being defined, then the qualifing
|
||||
type must be complete. The qualifing type may be
|
||||
incomplete for a declaration only if the qualitying
|
||||
type is one of the classes presently being defined,
|
||||
or if it is a dependent type. */
|
||||
&& (funcdef_flag
|
||||
|| !(dependent_type_p (ctype)
|
||||
|| currently_open_class (ctype)))
|
||||
/* Check that the qualifing type is complete. */
|
||||
&& !complete_type_or_else (ctype, NULL_TREE))
|
||||
return error_mark_node;
|
||||
else if (TREE_CODE (type) == FUNCTION_TYPE)
|
||||
{
|
||||
tree sname = declarator->u.id.unqualified_name;
|
||||
|
@ -7736,23 +7754,10 @@ grokdeclarator (const cp_declarator *declarator,
|
|||
TYPE_ARG_TYPES (type));
|
||||
}
|
||||
else if (declspecs->specs[(int)ds_typedef]
|
||||
|| COMPLETE_TYPE_P (complete_type (ctype)))
|
||||
&& current_class_type)
|
||||
{
|
||||
/* Have to move this code elsewhere in this function.
|
||||
this code is used for i.e., typedef int A::M; M *pm;
|
||||
|
||||
It is? How? jason 10/2/94 */
|
||||
|
||||
if (current_class_type)
|
||||
{
|
||||
error ("cannot declare member %<%T::%s%> within %qT",
|
||||
ctype, name, current_class_type);
|
||||
return void_type_node;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cxx_incomplete_type_error (NULL_TREE, ctype);
|
||||
error ("cannot declare member %<%T::%s%> within %qT",
|
||||
ctype, name, current_class_type);
|
||||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -780,7 +780,8 @@ static cp_parameter_declarator *make_parameter_declarator
|
|||
static cp_declarator *make_ptrmem_declarator
|
||||
(cp_cv_quals, tree, cp_declarator *);
|
||||
|
||||
cp_declarator *cp_error_declarator;
|
||||
/* An erroneous declarator. */
|
||||
static cp_declarator *cp_error_declarator;
|
||||
|
||||
/* The obstack on which declarators and related data structures are
|
||||
allocated. */
|
||||
|
@ -1389,9 +1390,9 @@ static bool cp_parser_translation_unit
|
|||
static tree cp_parser_primary_expression
|
||||
(cp_parser *, bool, bool, bool, cp_id_kind *);
|
||||
static tree cp_parser_id_expression
|
||||
(cp_parser *, bool, bool, bool *, bool);
|
||||
(cp_parser *, bool, bool, bool *, bool, bool);
|
||||
static tree cp_parser_unqualified_id
|
||||
(cp_parser *, bool, bool, bool);
|
||||
(cp_parser *, bool, bool, bool, bool);
|
||||
static tree cp_parser_nested_name_specifier_opt
|
||||
(cp_parser *, bool, bool, bool, bool);
|
||||
static tree cp_parser_nested_name_specifier
|
||||
|
@ -1536,7 +1537,7 @@ static enum tree_code cp_parser_ptr_operator
|
|||
static cp_cv_quals cp_parser_cv_qualifier_seq_opt
|
||||
(cp_parser *);
|
||||
static tree cp_parser_declarator_id
|
||||
(cp_parser *);
|
||||
(cp_parser *, bool);
|
||||
static tree cp_parser_type_id
|
||||
(cp_parser *);
|
||||
static void cp_parser_type_specifier_seq
|
||||
|
@ -2142,7 +2143,8 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser)
|
|||
/*template_keyword_p=*/false,
|
||||
/*check_dependency_p=*/true,
|
||||
/*template_p=*/NULL,
|
||||
/*declarator_p=*/true);
|
||||
/*declarator_p=*/true,
|
||||
/*optional_p=*/false);
|
||||
/* After the id-expression, there should be a plain identifier,
|
||||
otherwise this is not a simple variable declaration. Also, if
|
||||
the scope is dependent, we cannot do much. */
|
||||
|
@ -3021,7 +3023,8 @@ cp_parser_primary_expression (cp_parser *parser,
|
|||
/*template_keyword_p=*/false,
|
||||
/*check_dependency_p=*/true,
|
||||
&template_p,
|
||||
/*declarator_p=*/false);
|
||||
/*declarator_p=*/false,
|
||||
/*optional_p=*/false);
|
||||
if (id_expression == error_mark_node)
|
||||
return error_mark_node;
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
|
@ -3154,7 +3157,8 @@ cp_parser_id_expression (cp_parser *parser,
|
|||
bool template_keyword_p,
|
||||
bool check_dependency_p,
|
||||
bool *template_p,
|
||||
bool declarator_p)
|
||||
bool declarator_p,
|
||||
bool optional_p)
|
||||
{
|
||||
bool global_scope_p;
|
||||
bool nested_name_specifier_p;
|
||||
|
@ -3197,7 +3201,8 @@ cp_parser_id_expression (cp_parser *parser,
|
|||
/* Process the final unqualified-id. */
|
||||
unqualified_id = cp_parser_unqualified_id (parser, *template_p,
|
||||
check_dependency_p,
|
||||
declarator_p);
|
||||
declarator_p,
|
||||
/*optional_p=*/false);
|
||||
/* Restore the SAVED_SCOPE for our caller. */
|
||||
parser->scope = saved_scope;
|
||||
parser->object_scope = saved_object_scope;
|
||||
|
@ -3255,7 +3260,8 @@ cp_parser_id_expression (cp_parser *parser,
|
|||
else
|
||||
return cp_parser_unqualified_id (parser, template_keyword_p,
|
||||
/*check_dependency_p=*/true,
|
||||
declarator_p);
|
||||
declarator_p,
|
||||
optional_p);
|
||||
}
|
||||
|
||||
/* Parse an unqualified-id.
|
||||
|
@ -3284,7 +3290,8 @@ static tree
|
|||
cp_parser_unqualified_id (cp_parser* parser,
|
||||
bool template_keyword_p,
|
||||
bool check_dependency_p,
|
||||
bool declarator_p)
|
||||
bool declarator_p,
|
||||
bool optional_p)
|
||||
{
|
||||
cp_token *token;
|
||||
|
||||
|
@ -3505,6 +3512,8 @@ cp_parser_unqualified_id (cp_parser* parser,
|
|||
/* Fall through. */
|
||||
|
||||
default:
|
||||
if (optional_p)
|
||||
return NULL_TREE;
|
||||
cp_parser_error (parser, "expected unqualified-id");
|
||||
return error_mark_node;
|
||||
}
|
||||
|
@ -4501,7 +4510,8 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
|
|||
cp_parser_optional_template_keyword (parser),
|
||||
/*check_dependency_p=*/true,
|
||||
&template_p,
|
||||
/*declarator_p=*/false));
|
||||
/*declarator_p=*/false,
|
||||
/*optional_p=*/false));
|
||||
/* In general, build a SCOPE_REF if the member name is qualified.
|
||||
However, if the name was not dependent and has already been
|
||||
resolved; there is no need to build the SCOPE_REF. For example;
|
||||
|
@ -8623,7 +8633,8 @@ cp_parser_type_parameter (cp_parser* parser)
|
|||
/*template_keyword_p=*/false,
|
||||
/*check_dependency_p=*/true,
|
||||
/*template_p=*/&is_template,
|
||||
/*declarator_p=*/false);
|
||||
/*declarator_p=*/false,
|
||||
/*optional_p=*/false);
|
||||
if (TREE_CODE (default_argument) == TYPE_DECL)
|
||||
/* If the id-expression was a template-id that refers to
|
||||
a template-class, we already have the declaration here,
|
||||
|
@ -9177,7 +9188,8 @@ cp_parser_template_argument (cp_parser* parser)
|
|||
/*template_keyword_p=*/false,
|
||||
/*check_dependency_p=*/true,
|
||||
&template_p,
|
||||
/*declarator_p=*/false);
|
||||
/*declarator_p=*/false,
|
||||
/*optional_p=*/false);
|
||||
/* If the next token isn't a `,' or a `>', then this argument wasn't
|
||||
really finished. */
|
||||
if (!cp_parser_next_token_ends_template_argument_p (parser))
|
||||
|
@ -10624,7 +10636,8 @@ cp_parser_using_declaration (cp_parser* parser)
|
|||
identifier = cp_parser_unqualified_id (parser,
|
||||
/*template_keyword_p=*/false,
|
||||
/*check_dependency_p=*/true,
|
||||
/*declarator_p=*/true);
|
||||
/*declarator_p=*/true,
|
||||
/*optional_p=*/false);
|
||||
|
||||
/* The function we call to handle a using-declaration is different
|
||||
depending on what scope we are in. */
|
||||
|
@ -11515,25 +11528,31 @@ cp_parser_direct_declarator (cp_parser* parser,
|
|||
tree qualifying_scope;
|
||||
tree unqualified_name;
|
||||
special_function_kind sfk;
|
||||
bool abstract_ok;
|
||||
|
||||
/* Parse a declarator-id */
|
||||
if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
|
||||
abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER);
|
||||
if (abstract_ok)
|
||||
cp_parser_parse_tentatively (parser);
|
||||
unqualified_name = cp_parser_declarator_id (parser);
|
||||
unqualified_name
|
||||
= cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok);
|
||||
qualifying_scope = parser->scope;
|
||||
if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
|
||||
if (abstract_ok)
|
||||
{
|
||||
if (!cp_parser_parse_definitely (parser))
|
||||
unqualified_name = error_mark_node;
|
||||
else if (qualifying_scope
|
||||
|| (TREE_CODE (unqualified_name)
|
||||
!= IDENTIFIER_NODE))
|
||||
else if (unqualified_name
|
||||
&& (qualifying_scope
|
||||
|| (TREE_CODE (unqualified_name)
|
||||
!= IDENTIFIER_NODE)))
|
||||
{
|
||||
cp_parser_error (parser, "expected unqualified-id");
|
||||
unqualified_name = error_mark_node;
|
||||
}
|
||||
}
|
||||
|
||||
if (!unqualified_name)
|
||||
return NULL;
|
||||
if (unqualified_name == error_mark_node)
|
||||
{
|
||||
declarator = cp_error_declarator;
|
||||
|
@ -11853,7 +11872,7 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
|
|||
unqualified-id. */
|
||||
|
||||
static tree
|
||||
cp_parser_declarator_id (cp_parser* parser)
|
||||
cp_parser_declarator_id (cp_parser* parser, bool optional_p)
|
||||
{
|
||||
tree id;
|
||||
/* The expression must be an id-expression. Assume that qualified
|
||||
|
@ -11874,8 +11893,9 @@ cp_parser_declarator_id (cp_parser* parser)
|
|||
/*template_keyword_p=*/false,
|
||||
/*check_dependency_p=*/false,
|
||||
/*template_p=*/NULL,
|
||||
/*declarator_p=*/true);
|
||||
if (BASELINK_P (id))
|
||||
/*declarator_p=*/true,
|
||||
optional_p);
|
||||
if (id && BASELINK_P (id))
|
||||
id = BASELINK_FUNCTIONS (id);
|
||||
return id;
|
||||
}
|
||||
|
@ -15298,7 +15318,6 @@ cp_parser_function_definition_from_specifiers_and_declarator
|
|||
if (!success_p)
|
||||
{
|
||||
/* Skip the entire function. */
|
||||
error ("invalid function declaration");
|
||||
cp_parser_skip_to_end_of_block_or_statement (parser);
|
||||
fn = error_mark_node;
|
||||
}
|
||||
|
@ -17786,7 +17805,8 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
|
|||
name = cp_parser_id_expression (parser, /*template_p=*/false,
|
||||
/*check_dependency_p=*/true,
|
||||
/*template_p=*/NULL,
|
||||
/*declarator_p=*/false);
|
||||
/*declarator_p=*/false,
|
||||
/*optional_p=*/false);
|
||||
if (name == error_mark_node)
|
||||
goto skip_comma;
|
||||
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
2006-04-19 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
PR c++/27102
|
||||
* g++.dg/template/crash35.C: Tweak error markers.
|
||||
* g++.dg/template/crash46.C: New test.
|
||||
* g++.old-deja/g++.brendan/friend4.C: Tweak error markers.
|
||||
* g++.old-deja/g++.pt/incomplete1.C: Likewise.
|
||||
|
||||
2006-04-19 Andreas Krebbel <krebbel1@de.ibm.com>
|
||||
|
||||
PR rtl-optimization/14261
|
||||
|
|
|
@ -5,5 +5,5 @@ template <typename T> struct C; // { dg-error "declaration" }
|
|||
|
||||
template <typename T> void C<T>::f() // { dg-error "invalid|template" }
|
||||
{
|
||||
const foo bar; // { dg-error "name a type" }
|
||||
const foo bar;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// PR c++/27102
|
||||
|
||||
template <class T>
|
||||
void T::foo() {} // { dg-error "invalid" }
|
||||
|
|
@ -2,5 +2,5 @@
|
|||
// GROUPS passed friends
|
||||
// do_friend should complain that foo was declared as a friend of
|
||||
// A before A was defined
|
||||
struct A;
|
||||
struct A; // { dg-error "forward" }
|
||||
struct B { friend A::foo (); };// { dg-error "" } .*
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
// Inspired by by 756. We'd ICE when trying to define a member of an
|
||||
// incomplete template type.
|
||||
|
||||
template<class X> struct ObjCount; // { dg-error "" } forward decl
|
||||
template<class X> struct ObjCount;
|
||||
|
||||
template<class X> int ObjCount<X>::m; // { dg-error "" } undefined type
|
||||
|
|
Loading…
Reference in New Issue