diff options
author | Mark Mitchell <mark@codesourcery.com> | 2006-04-19 16:58:23 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2006-04-19 16:58:23 +0000 |
commit | fa6098f8177ea7e73cfdcc291209cd47d40196ee (patch) | |
tree | 8697179a09947548fbbcca23b0493738bd1f5cb1 | |
parent | 74c96e0c149acb69337d704bfcd32d1e60724307 (diff) | |
download | gcc-fa6098f8177ea7e73cfdcc291209cd47d40196ee.zip gcc-fa6098f8177ea7e73cfdcc291209cd47d40196ee.tar.gz gcc-fa6098f8177ea7e73cfdcc291209cd47d40196ee.tar.bz2 |
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
-rw-r--r-- | gcc/cp/ChangeLog | 27 | ||||
-rw-r--r-- | gcc/cp/class.c | 34 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 5 | ||||
-rw-r--r-- | gcc/cp/decl.c | 47 | ||||
-rw-r--r-- | gcc/cp/parser.c | 70 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/crash35.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/crash46.C | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.brendan/friend4.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/incomplete1.C | 2 |
10 files changed, 136 insertions, 66 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7852572..2d80e52 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 0edade8..cc26cb8 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b488be6..f82ab32 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 3d8c2f8..9e101c1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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))) - { - /* 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 + && current_class_type) { - cxx_incomplete_type_error (NULL_TREE, ctype); + error ("cannot declare member %<%T::%s%> within %qT", + ctype, name, current_class_type); return error_mark_node; } } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index fede4df..13c7362 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 44a9b9f..f3783b4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 diff --git a/gcc/testsuite/g++.dg/template/crash35.C b/gcc/testsuite/g++.dg/template/crash35.C index dd8aa2f..348d91d 100644 --- a/gcc/testsuite/g++.dg/template/crash35.C +++ b/gcc/testsuite/g++.dg/template/crash35.C @@ -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; } diff --git a/gcc/testsuite/g++.dg/template/crash46.C b/gcc/testsuite/g++.dg/template/crash46.C new file mode 100644 index 0000000..6fbda7c --- /dev/null +++ b/gcc/testsuite/g++.dg/template/crash46.C @@ -0,0 +1,5 @@ +// PR c++/27102 + +template <class T> +void T::foo() {} // { dg-error "invalid" } + diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/friend4.C b/gcc/testsuite/g++.old-deja/g++.brendan/friend4.C index af33199..4d436e5 100644 --- a/gcc/testsuite/g++.old-deja/g++.brendan/friend4.C +++ b/gcc/testsuite/g++.old-deja/g++.brendan/friend4.C @@ -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 "" } .* diff --git a/gcc/testsuite/g++.old-deja/g++.pt/incomplete1.C b/gcc/testsuite/g++.old-deja/g++.pt/incomplete1.C index 37c30a4..9189df2 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/incomplete1.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/incomplete1.C @@ -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 |