diff mbox

[C++] PR 38634

Message ID 51B50FDD.8040100@oracle.com
State New
Headers show

Commit Message

Paolo Carlini June 9, 2013, 11:29 p.m. UTC
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.carlini@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.carlini@oracle.com>

	PR c++/38634
	* g++.dg/template/crash116.C: New.
diff mbox

Patch

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;