Hi,
in this old issue, we ICE after having reported an error. The problem
seems that start_preparsed_function doesn't directly inform the caller
that push_template_decl failed. If we adjust for that and pass back a
boolean to cp_parser_function_definition_from_specifiers_and_declarator
via start_function, then the parser knows how to clean up, ie, skip the
entire function, etc.
Patch works well in terms of testsuite, I would ask you to double check
in particular the pop_nested_class call which I added before the early
return from start_preparsed_function to compensate for the preceding
push_nested_class.
Tested x86_64-linux.
Thanks,
Paolo.
////////////////////////
/cp
2013-06-11 Paolo Carlini <paolo.carl...@oracle.com>
PR c++/38634
* decl.c (start_preparsed_function): Return a bool, false if
push_template_decl fails.
(start_function): Adjust.
* cp-tree.h: Update.
/testsuite
2013-06-11 Paolo Carlini <paolo.carl...@oracle.com>
PR c++/38634
* g++.dg/template/crash116.C: New.
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h (revision 199868)
+++ cp/cp-tree.h (working copy)
@@ -5202,8 +5202,9 @@ extern void finish_enum_value_list (tree);
extern void finish_enum (tree);
extern void build_enumerator (tree, tree, tree, location_t);
extern tree lookup_enumerator (tree, tree);
-extern void start_preparsed_function (tree, tree, int);
-extern int start_function (cp_decl_specifier_seq *, const
cp_declarator *, tree);
+extern bool start_preparsed_function (tree, tree, int);
+extern bool start_function (cp_decl_specifier_seq *,
+ const cp_declarator *, tree);
extern tree begin_function_body (void);
extern void finish_function_body (tree);
extern tree outer_curly_brace_block (tree);
Index: cp/decl.c
===================================================================
--- cp/decl.c (revision 199868)
+++ cp/decl.c (working copy)
@@ -13008,7 +13008,7 @@ check_function_type (tree decl, tree current_funct
error_mark_node if the function has never been defined, or
a BLOCK if the function has been defined somewhere. */
-void
+bool
start_preparsed_function (tree decl1, tree attrs, int flags)
{
tree ctype = NULL_TREE;
@@ -13107,8 +13107,13 @@ start_preparsed_function (tree decl1, tree attrs,
{
/* FIXME: Handle error_mark_node more gracefully. */
tree newdecl1 = push_template_decl (decl1);
- if (newdecl1 != error_mark_node)
- decl1 = newdecl1;
+ if (newdecl1 == error_mark_node)
+ {
+ if (ctype || DECL_STATIC_FUNCTION_P (decl1))
+ pop_nested_class ();
+ return false;
+ }
+ decl1 = newdecl1;
}
/* We are now in the scope of the function being defined. */
@@ -13219,7 +13224,7 @@ start_preparsed_function (tree decl1, tree attrs,
/* This function may already have been parsed, in which case just
return; our caller will skip over the body without parsing. */
if (DECL_INITIAL (decl1) != error_mark_node)
- return;
+ return true;
/* Initialize RTL machinery. We cannot do this until
CURRENT_FUNCTION_DECL and DECL_RESULT are set up. We do this
@@ -13381,17 +13386,19 @@ start_preparsed_function (tree decl1, tree attrs,
start_fname_decls ();
store_parm_decls (current_function_parms);
+
+ return true;
}
/* Like start_preparsed_function, except that instead of a
FUNCTION_DECL, this function takes DECLSPECS and DECLARATOR.
- Returns 1 on success. If the DECLARATOR is not suitable for a function
- (it defines a datum instead), we return 0, which tells
- yyparse to report a parse error. */
+ Returns true on success. If the DECLARATOR is not suitable
+ for a function, we return false, which tells the parser to
+ skip the entire function. */
-int
+bool
start_function (cp_decl_specifier_seq *declspecs,
const cp_declarator *declarator,
tree attrs)
@@ -13400,13 +13407,13 @@ start_function (cp_decl_specifier_seq *declspecs,
decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, &attrs);
if (decl1 == error_mark_node)
- return 0;
+ return false;
/* If the declarator is not suitable for a function definition,
cause a syntax error. */
if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL)
{
error ("invalid function declaration");
- return 0;
+ return false;
}
if (DECL_MAIN_P (decl1))
@@ -13415,9 +13422,7 @@ start_function (cp_decl_specifier_seq *declspecs,
gcc_assert (same_type_p (TREE_TYPE (TREE_TYPE (decl1)),
integer_type_node));
- start_preparsed_function (decl1, attrs, /*flags=*/SF_DEFAULT);
-
- return 1;
+ return start_preparsed_function (decl1, attrs, /*flags=*/SF_DEFAULT);
}
/* Returns true iff an EH_SPEC_BLOCK should be created in the body of
Index: testsuite/g++.dg/template/crash116.C
===================================================================
--- testsuite/g++.dg/template/crash116.C (revision 0)
+++ testsuite/g++.dg/template/crash116.C (working copy)
@@ -0,0 +1,13 @@
+// PR c++/38634
+
+template<int> struct A
+{
+ A();
+};
+
+template<int N, char> A<N>::A() // { dg-error "template|required" }
+{
+ struct B {};
+}
+
+A<0> a;