From 8fe4d24bebd6df659ab43ad5dd065a29c473f815 Mon Sep 17 00:00:00 2001
From: Nathan Sidwell <nathan@codesourcery.com>
Date: Mon, 13 Jun 2005 15:58:10 +0000
Subject: [PATCH] re PR c++/20789 (ICE with incomplete type in template)

cp:
	PR c++/20789
	* decl.c (cp_finish_decl): Clear runtime runtime initialization if
	in-class decl's initializer is bad.

	PR c++/21929
	* parser.c (struct cp_parser): Document that scope could be
	error_mark.
	(cp_parser_diagnose_invalid_type_name): Cope with error_mark for
	scope.
	(cp_parser_nested_name_specifier): Return NULL_TREE on error.
	(cp_parser_postfix_expression): Deal with null or error_mark
	scope.
	(cp_parser_elaborated_type_specifier): Adjust
	cp_parser_nested_name_specifier call.

	* parser (cp_parser_skip_to_end_of_block_or_statement): Cleanup.
testsuite:
	PR c++/21929
	* g++.dg/parse/crash26.C: New.

	PR c++/20789
	* g++.dg/init/member1.C: New.

From-SVN: r100880
---
 gcc/cp/ChangeLog                     | 19 +++++++
 gcc/cp/decl.c                        | 10 ++++
 gcc/cp/parser.c                      | 75 ++++++++++++++++------------
 gcc/testsuite/ChangeLog              |  8 +++
 gcc/testsuite/g++.dg/init/member1.C  | 18 +++++++
 gcc/testsuite/g++.dg/parse/crash26.C | 12 +++++
 6 files changed, 109 insertions(+), 33 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/init/member1.C
 create mode 100644 gcc/testsuite/g++.dg/parse/crash26.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index fa37b36f4ee6..00a029de5cb6 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,22 @@
+2005-06-13  Nathan Sidwell  <nathan@codesourcery.com>
+
+	PR c++/20789
+	* decl.c (cp_finish_decl): Clear runtime runtime initialization if
+	in-class decl's initializer is bad.
+
+	PR c++/21929
+	* parser.c (struct cp_parser): Document that scope could be
+	error_mark.
+	(cp_parser_diagnose_invalid_type_name): Cope with error_mark for
+	scope.
+	(cp_parser_nested_name_specifier): Return NULL_TREE on error.
+	(cp_parser_postfix_expression): Deal with null or error_mark
+	scope.
+	(cp_parser_elaborated_type_specifier): Adjust
+	cp_parser_nested_name_specifier call.
+
+	* parser (cp_parser_skip_to_end_of_block_or_statement): Cleanup.
+
 2005-06-12  Roger Sayle  <roger@eyesopen.com>
 
 	PR c++/21930
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 6b278ae2878e..c17d6f8f3724 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4834,6 +4834,16 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
 		     "initialized", decl);
 	      init = NULL_TREE;
 	    }
+	  if (DECL_EXTERNAL (decl) && init)
+	    {
+	      /* The static data member cannot be initialized by a
+		 non-constant when being declared.  */
+	      error ("%qD cannot be initialized by a non-constant expression"
+		     " when being declared", decl);
+	      DECL_INITIALIZED_IN_CLASS_P (decl) = 0;
+	      init = NULL_TREE;
+	    }
+	  
 	  /* Handle:
 
 	     [dcl.init]
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index cb389d24afe9..f56c9019ce69 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1217,7 +1217,8 @@ typedef struct cp_parser GTY(())
   /* The scope in which names should be looked up.  If NULL_TREE, then
      we look up names in the scope that is currently open in the
      source program.  If non-NULL, this is either a TYPE or
-     NAMESPACE_DECL for the scope in which we should look.
+     NAMESPACE_DECL for the scope in which we should look.  It can
+     also be ERROR_MARK, when we've parsed a bogus scope.
 
      This value is not cleared automatically after a name is looked
      up, so we must be careful to clear it before starting a new look
@@ -1225,7 +1226,7 @@ typedef struct cp_parser GTY(())
      will look up `Z' in the scope of `X', rather than the current
      scope.)  Unfortunately, it is difficult to tell when name lookup
      is complete, because we sometimes peek at a token, look it up,
-     and then decide not to consume it.  */
+     and then decide not to consume it.   */
   tree scope;
 
   /* OBJECT_SCOPE and QUALIFYING_SCOPE give the scopes in which the
@@ -2045,7 +2046,7 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree scope, tree id)
   if (TREE_CODE (decl) == TEMPLATE_DECL)
     error ("invalid use of template-name %qE without an argument list",
       decl);
-  else if (!parser->scope)
+  else if (!parser->scope || parser->scope == error_mark_node)
     {
       /* Issue an error message.  */
       error ("%qE does not name a type", id);
@@ -2313,36 +2314,48 @@ cp_parser_consume_semicolon_at_end_of_statement (cp_parser *parser)
 static void
 cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser)
 {
-  unsigned nesting_depth = 0;
+  int nesting_depth = 0;
 
-  while (true)
+  while (nesting_depth >= 0)
     {
-      cp_token *token;
-
-      /* Peek at the next token.  */
-      token = cp_lexer_peek_token (parser->lexer);
-      /* If we've run out of tokens, stop.  */
+      cp_token *token = cp_lexer_peek_token (parser->lexer);
+      
       if (token->type == CPP_EOF)
 	break;
-      /* If the next token is a `;', we have reached the end of the
-	 statement.  */
-      if (token->type == CPP_SEMICOLON && !nesting_depth)
+
+      switch (token->type)
 	{
-	  /* Consume the `;'.  */
-	  cp_lexer_consume_token (parser->lexer);
+	case CPP_EOF:
+	  /* If we've run out of tokens, stop.  */
+	  nesting_depth = -1;
+	  continue;
+
+	case CPP_SEMICOLON:
+	  /* Stop if this is an unnested ';'. */
+	  if (!nesting_depth)
+	    nesting_depth = -1;
+	  break;
+
+	case CPP_CLOSE_BRACE:
+	  /* Stop if this is an unnested '}', or closes the outermost
+	     nesting level.  */
+	  nesting_depth--;
+	  if (!nesting_depth)
+	    nesting_depth = -1;
+	  break;
+	  
+	case CPP_OPEN_BRACE:
+	  /* Nest. */
+	  nesting_depth++;
+	  break;
+
+	default:
 	  break;
 	}
+      
       /* Consume the token.  */
-      token = cp_lexer_consume_token (parser->lexer);
-      /* If the next token is a non-nested `}', then we have reached
-	 the end of the current block.  */
-      if (token->type == CPP_CLOSE_BRACE
-	  && (nesting_depth == 0 || --nesting_depth == 0))
-	break;
-      /* If it the next token is a `{', then we are entering a new
-	 block.  Consume the entire block.  */
-      if (token->type == CPP_OPEN_BRACE)
-	++nesting_depth;
+      cp_lexer_consume_token (parser->lexer);
+      
     }
 }
 
@@ -3664,9 +3677,7 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
 /* Parse a nested-name-specifier.  See
    cp_parser_nested_name_specifier_opt for details.  This function
    behaves identically, except that it will an issue an error if no
-   nested-name-specifier is present, and it will return
-   ERROR_MARK_NODE, rather than NULL_TREE, if no nested-name-specifier
-   is present.  */
+   nested-name-specifier is present.  */
 
 static tree
 cp_parser_nested_name_specifier (cp_parser *parser,
@@ -3688,7 +3699,6 @@ cp_parser_nested_name_specifier (cp_parser *parser,
     {
       cp_parser_error (parser, "expected nested-name-specifier");
       parser->scope = NULL_TREE;
-      return error_mark_node;
     }
 
   return scope;
@@ -3973,7 +3983,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
 	  id = cp_parser_identifier (parser);
 
 	/* Don't process id if nested name specifier is invalid.  */
-	if (scope == error_mark_node)
+	if (!scope || scope == error_mark_node)
 	  return error_mark_node;
 	/* If we look up a template-id in a non-dependent qualifying
 	   scope, there's no need to create a dependent type.  */
@@ -9871,12 +9881,11 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
   /* Look for the nested-name-specifier.  */
   if (tag_type == typename_type)
     {
-      if (cp_parser_nested_name_specifier (parser,
+      if (!cp_parser_nested_name_specifier (parser,
 					   /*typename_keyword_p=*/true,
 					   /*check_dependency_p=*/true,
 					   /*type_p=*/true,
-					   is_declaration)
-	  == error_mark_node)
+					    is_declaration))
 	return error_mark_node;
     }
   else
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index af6d1b13266e..8fb457e66516 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2005-06-13  Nathan Sidwell  <nathan@codesourcery.com>
+
+	PR c++/21929
+	* g++.dg/parse/crash26.C: New.
+
+	PR c++/20789
+	* g++.dg/init/member1.C: New.
+
 2005-06-13  Jakub Jelinek  <jakub@redhat.com>
 
 	* gfortran.dg/altreturn_1.f90: New test.
diff --git a/gcc/testsuite/g++.dg/init/member1.C b/gcc/testsuite/g++.dg/init/member1.C
new file mode 100644
index 000000000000..1c89d5a1d43d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/member1.C
@@ -0,0 +1,18 @@
+// Copyright (C) 2005 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 13 Jun 2005 <nathan@codesourcery.com>
+
+// Origin:   Ivan Godard <igodard@pacbell.net>
+// Bug 20789: ICE on invalid
+
+template<typename> struct A;
+
+template<int> struct B {};
+
+template<typename T> struct C
+{
+  static const int i = A<T>::i;  // { dg-error "incomplete" }
+  static const int j = i;      // { dg-error "initialized by a non-const" }
+  B<j> b;  // { dg-error "not a valid template arg" }
+};
+
+C<int> c;
diff --git a/gcc/testsuite/g++.dg/parse/crash26.C b/gcc/testsuite/g++.dg/parse/crash26.C
new file mode 100644
index 000000000000..2b4f165f8b9a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash26.C
@@ -0,0 +1,12 @@
+// Copyright (C) 2005 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 13 Jun 2005 <nathan@codesourcery.com>
+
+// Origin:  Volker Reichelt <reichelt@gcc.gnu.org>
+// Bug 21929: ICE on invalid
+
+template<int> struct A
+{
+    struct B;
+};
+
+template<> struct A<void>::B {}; // { dg-error "mismatch|expected|name a type|extra" }
-- 
GitLab