This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH: PR 27665


This patch fixes PR c++/27665, a tricky ICE on valid code.

When parsing something like:

+  class A<N>::B::C X;

we need to determine whether A<N> is the abstract definition of A, or
some instantiation thereof.  For example, in the scope of A's
definition, A<N> is the abstract definition, while, in the body of:

  template <int N> void f() { ... }

it's just an instantiation.  This patch refines the test used to
determine which of these two situations we are in, and then adjusts a
couple of other spots as necessary.

Tested on x86_64-unknown-linux-gnu, applied to mainline.  I'll
backport this to 4.1 shortly.

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2006-06-14  Mark Mitchell  <mark@codesourcery.com>

	PR c++/27665
	* parser.c (cp_parser_unqualified_id): Use constructor_name_p to
	identify destructors.
	(cp_parser_nested_name_specifier_opt): Remove invalid
	optimization.
	(cp_parser_template_id): Refine heuristic for determining whether
	we are entering a scope.

2006-06-14  Mark Mitchell  <mark@codesourcery.com>

	PR c++/27665
	* g++.dg/template/crash52.C: New test.

Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 114635)
+++ gcc/cp/parser.c	(working copy)
@@ -3374,12 +3374,12 @@ cp_parser_unqualified_id (cp_parser* par
 	qualifying_scope = parser->qualifying_scope;
 
 	/* If the name is of the form "X::~X" it's OK.  */
+	token = cp_lexer_peek_token (parser->lexer);
 	if (scope && TYPE_P (scope)
-	    && cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+	    && token->type == CPP_NAME
 	    && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
 		== CPP_OPEN_PAREN)
-	    && (cp_lexer_peek_token (parser->lexer)->value
-		== TYPE_IDENTIFIER (scope)))
+	    && constructor_name_p (token->value, scope))
 	  {
 	    cp_lexer_consume_token (parser->lexer);
 	    return build_nt (BIT_NOT_EXPR, scope);
@@ -3550,20 +3550,6 @@ cp_parser_nested_name_specifier_opt (cp_
   cp_token_position start = 0;
   cp_token *token;
 
-  /* If the next token corresponds to a nested name specifier, there
-     is no need to reparse it.  However, if CHECK_DEPENDENCY_P is
-     false, it may have been true before, in which case something
-     like `A<X>::B<Y>::C' may have resulted in a nested-name-specifier
-     of `A<X>::', where it should now be `A<X>::B<Y>::'.  So, when
-     CHECK_DEPENDENCY_P is false, we have to fall through into the
-     main loop.  */
-  if (check_dependency_p
-      && cp_lexer_next_token_is (parser->lexer, CPP_NESTED_NAME_SPECIFIER))
-    {
-      cp_parser_pre_parsed_nested_name_specifier (parser);
-      return parser->scope;
-    }
-
   /* Remember where the nested-name-specifier starts.  */
   if (cp_parser_uncommitted_to_tentative_parse_p (parser))
     {
@@ -3663,6 +3649,8 @@ cp_parser_nested_name_specifier_opt (cp_
 	     class-or-namespace-name.  */
 	  parser->scope = old_scope;
 	  parser->qualifying_scope = saved_qualifying_scope;
+	  if (cp_parser_uncommitted_to_tentative_parse_p (parser))
+	    break;
 	  /* If the next token is an identifier, and the one after
 	     that is a `::', then any valid interpretation would have
 	     found a class-or-namespace-name.  */
@@ -8797,10 +8785,19 @@ cp_parser_template_id (cp_parser *parser
     template_id = build_min_nt (TEMPLATE_ID_EXPR, template, arguments);
   else if (DECL_CLASS_TEMPLATE_P (template)
 	   || DECL_TEMPLATE_TEMPLATE_PARM_P (template))
-    template_id
-      = finish_template_type (template, arguments,
-			      cp_lexer_next_token_is (parser->lexer,
-						      CPP_SCOPE));
+    {
+      bool entering_scope;
+      /* In "template <typename T> ... A<T>::", A<T> is the abstract A
+	 template (rather than some instantiation thereof) only if
+	 is not nested within some other construct.  For example, in
+	 "template <typename T> void f(T) { A<T>::", A<T> is just an
+	 instantiation of A.  */
+      entering_scope = (template_parm_scope_p ()
+			&& cp_lexer_next_token_is (parser->lexer,
+						   CPP_SCOPE));
+      template_id
+	= finish_template_type (template, arguments, entering_scope);
+    }
   else
     {
       /* If it's not a class-template or a template-template, it should be
Index: gcc/testsuite/g++.dg/template/crash52.C
===================================================================
--- gcc/testsuite/g++.dg/template/crash52.C	(revision 0)
+++ gcc/testsuite/g++.dg/template/crash52.C	(revision 0)
@@ -0,0 +1,19 @@
+// PR c++/27665
+
+template<int> struct A
+{
+    struct B
+    {
+      struct C {};
+    };
+};
+
+template<int N> void foo()
+{
+  class A<N>::B::C X;
+}
+
+void bar()
+{
+  foo<0>();
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]