C++ PATCH: PR 9849

Mark Mitchell mark@codesourcery.com
Mon Dec 1 06:02:00 GMT 2003


PR 9849 is a case where the error messages generated by the new parser
for an invalid template construct were not very good.  For this code:

  template<class T> struct C1
  {
    template<class U> struct C2
    { class Type { }; };
  };

  template<class T, class U>
  void foo(typename C1<T>::C2<U>::Type *) { }

we now say:

  test.C:8: error: non-template `C2' used as template
  test.C:8: error: (use `C1<T>::template C2' to indicate that it is a template)

which is just about ideal.

There is not going to be a good way to solve each and every one of
these problems.  The new parser has a fundamental capability
(backtracking) that the old parser did not have.  It has that
capability because that is required to implement C++; the new parser
has a functionality (correctness) that the old parser did not have.

If you don't know what construct must come at a given location
(becuase there is more than one choice), it's hard to give good error
messages.  One solution may be that if the new parser's "expected ..."
error messages are considered unhelpful that they simply be replaced
with "parse error".

Anyhow, this particular case is fixed with the attached patch.  Tested
on i686-pc-linux-gnu, applied on the mainline.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2003-11-30  Mark Mitchell  <mark@codesourcery.com>

	PR c++/9849
	* g++.dg/template/error4.C: New test.
	* g++.dg/template/nested3.C: Adjust error markers.

2003-11-30  Mark Mitchell  <mark@codesourcery.com>

	PR c++/9849
	* parser.c (cp_lexer_prev_token): New function.
	(cp_parser_skip_to_closing_parenthesis): Add consume_paren
	parameter.
	(cp_parser_nested_name_specifier_opt): Add is_declaration
	parameter.
	(cp_parser_nested_name_specifier): Likewise.
	(cp_parser_class_or_namespace_name): Likewise.
	(cp_parser_class_name): Likewise.
	(cp_parser_template_id): Likewise.
	(cp_parser_template_name): Likewise.
	(cp_parser_id_expression): Adjust calls to
	cp_parser_nested_name_specifier_op, cp_parser_template_id,
	cp_parser_class_name.
	(cp_parser_unqualified_id): Likewise.
	(cp_parser_postfix_expression): Likewise.
	(cp_parser_pseudo_destructor_name): Likewise.
	(cp_parser_cast_expression): Likewise.
	(cp_parser_mem_initializer_id): Likewise.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_type_name): Likewise.
	(cp_parser_elaborated_type_specifier): Likewise.
	(cp_parser_qualified_namespace_specifier): Likewise.
	(cp_parser_using_declaration): Likewise.
	(cp_parser_using_directive): Likewise.
	(cp_parser_ptr_operator): Likewise.
	(cp_parser_declarator_id): Likewise.
	(cp_parser_class_head): Likewise.
	(cp_parser_base_specifier): Likewise.
	(cp_parser_constructor_declarator_p): Likewise.
	(cp_parser_direct_declarator): Fix typo in comment.
	(cp_parser_parenthesized_expression_list): Adjust call to
	cp_parser_skip_to_closing_parenthesis.
	(cp_parser_selection_statement): Likewise.

Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.122
diff -c -5 -p -r1.122 parser.c
*** cp/parser.c	21 Nov 2003 11:36:58 -0000	1.122
--- cp/parser.c	1 Dec 2003 03:21:47 -0000
*************** static cp_lexer *cp_lexer_new_from_token
*** 217,226 ****
--- 217,228 ----
    (struct cp_token_cache *);
  static int cp_lexer_saving_tokens
    (const cp_lexer *);
  static cp_token *cp_lexer_next_token
    (cp_lexer *, cp_token *);
+ static cp_token *cp_lexer_prev_token
+   (cp_lexer *, cp_token *);
  static ptrdiff_t cp_lexer_token_difference 
    (cp_lexer *, cp_token *, cp_token *);
  static cp_token *cp_lexer_read_token
    (cp_lexer *);
  static void cp_lexer_maybe_grow_buffer
*************** cp_lexer_next_token (cp_lexer* lexer, cp
*** 417,426 ****
--- 419,439 ----
    if (token == lexer->buffer_end)
      token = lexer->buffer;
    return token;
  }
  
+ /* TOKEN points into the circular token buffer.  Return a pointer to
+    the previous token in the buffer.  */
+ 
+ static inline cp_token *
+ cp_lexer_prev_token (cp_lexer* lexer, cp_token* token)
+ {
+   if (token == lexer->buffer)
+     token = lexer->buffer_end;
+   return token - 1;
+ }
+ 
  /* nonzero if we are presently saving tokens.  */
  
  static int
  cp_lexer_saving_tokens (const cp_lexer* lexer)
  {
*************** static tree cp_parser_primary_expression
*** 1307,1321 ****
  static tree cp_parser_id_expression
    (cp_parser *, bool, bool, bool *, bool);
  static tree cp_parser_unqualified_id
    (cp_parser *, bool, bool, bool);
  static tree cp_parser_nested_name_specifier_opt
!   (cp_parser *, bool, bool, bool);
  static tree cp_parser_nested_name_specifier
-   (cp_parser *, bool, bool, bool);
- static tree cp_parser_class_or_namespace_name
    (cp_parser *, bool, bool, bool, bool);
  static tree cp_parser_postfix_expression
    (cp_parser *, bool);
  static tree cp_parser_parenthesized_expression_list
    (cp_parser *, bool, bool *);
  static void cp_parser_pseudo_destructor_name
--- 1320,1334 ----
  static tree cp_parser_id_expression
    (cp_parser *, bool, bool, bool *, bool);
  static tree cp_parser_unqualified_id
    (cp_parser *, bool, bool, bool);
  static tree cp_parser_nested_name_specifier_opt
!   (cp_parser *, bool, bool, bool, bool);
  static tree cp_parser_nested_name_specifier
    (cp_parser *, bool, bool, bool, bool);
+ static tree cp_parser_class_or_namespace_name
+   (cp_parser *, bool, bool, bool, bool, bool);
  static tree cp_parser_postfix_expression
    (cp_parser *, bool);
  static tree cp_parser_parenthesized_expression_list
    (cp_parser *, bool, bool *);
  static void cp_parser_pseudo_destructor_name
*************** static bool cp_parser_ctor_initializer_o
*** 1493,1503 ****
    (cp_parser *);
  
  /* Classes [gram.class] */
  
  static tree cp_parser_class_name
!   (cp_parser *, bool, bool, bool, bool, bool);
  static tree cp_parser_class_specifier
    (cp_parser *);
  static tree cp_parser_class_head
    (cp_parser *, bool *);
  static enum tag_types cp_parser_class_key
--- 1506,1516 ----
    (cp_parser *);
  
  /* Classes [gram.class] */
  
  static tree cp_parser_class_name
!   (cp_parser *, bool, bool, bool, bool, bool, bool);
  static tree cp_parser_class_specifier
    (cp_parser *);
  static tree cp_parser_class_head
    (cp_parser *, bool *);
  static enum tag_types cp_parser_class_key
*************** static tree cp_parser_template_parameter
*** 1551,1563 ****
  static tree cp_parser_template_parameter
    (cp_parser *);
  static tree cp_parser_type_parameter
    (cp_parser *);
  static tree cp_parser_template_id
!   (cp_parser *, bool, bool);
  static tree cp_parser_template_name
!   (cp_parser *, bool, bool);
  static tree cp_parser_template_argument_list
    (cp_parser *);
  static tree cp_parser_template_argument
    (cp_parser *);
  static void cp_parser_explicit_instantiation
--- 1564,1576 ----
  static tree cp_parser_template_parameter
    (cp_parser *);
  static tree cp_parser_type_parameter
    (cp_parser *);
  static tree cp_parser_template_id
!   (cp_parser *, bool, bool, bool);
  static tree cp_parser_template_name
!   (cp_parser *, bool, bool, bool, bool *);
  static tree cp_parser_template_argument_list
    (cp_parser *);
  static tree cp_parser_template_argument
    (cp_parser *);
  static void cp_parser_explicit_instantiation
*************** static void cp_parser_check_for_definiti
*** 1692,1702 ****
  static tree cp_parser_non_constant_expression
    (const char *);
  static bool cp_parser_diagnose_invalid_type_name
    (cp_parser *);
  static int cp_parser_skip_to_closing_parenthesis
!   (cp_parser *, bool, bool);
  static void cp_parser_skip_to_end_of_statement
    (cp_parser *);
  static void cp_parser_consume_semicolon_at_end_of_statement
    (cp_parser *);
  static void cp_parser_skip_to_end_of_block_or_statement
--- 1705,1715 ----
  static tree cp_parser_non_constant_expression
    (const char *);
  static bool cp_parser_diagnose_invalid_type_name
    (cp_parser *);
  static int cp_parser_skip_to_closing_parenthesis
!   (cp_parser *, bool, bool, bool);
  static void cp_parser_skip_to_end_of_statement
    (cp_parser *);
  static void cp_parser_consume_semicolon_at_end_of_statement
    (cp_parser *);
  static void cp_parser_skip_to_end_of_block_or_statement
*************** cp_parser_diagnose_invalid_type_name (cp
*** 1888,1898 ****
     are doing error recovery. Returns -1 if OR_COMMA is true and we
     found an unnested comma.  */
  
  static int
  cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
! 				       bool recovering, bool or_comma)
  {
    unsigned paren_depth = 0;
    unsigned brace_depth = 0;
  
    if (recovering && !or_comma && cp_parser_parsing_tentatively (parser)
--- 1901,1913 ----
     are doing error recovery. Returns -1 if OR_COMMA is true and we
     found an unnested comma.  */
  
  static int
  cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
! 				       bool recovering, 
! 				       bool or_comma,
! 				       bool consume_paren)
  {
    unsigned paren_depth = 0;
    unsigned brace_depth = 0;
  
    if (recovering && !or_comma && cp_parser_parsing_tentatively (parser)
*************** cp_parser_skip_to_closing_parenthesis (c
*** 1905,1945 ****
        
        /* If we've run out of tokens, then there is no closing `)'.  */
        if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
  	return 0;
  
!       if (recovering)
  	{
! 	  token = cp_lexer_peek_token (parser->lexer);
! 
! 	  /* This matches the processing in skip_to_end_of_statement */
! 	  if (token->type == CPP_SEMICOLON && !brace_depth)
  	    return 0;
- 	  if (token->type == CPP_OPEN_BRACE)
- 	    ++brace_depth;
- 	  if (token->type == CPP_CLOSE_BRACE)
- 	    {
- 	      if (!brace_depth--)
- 		return 0;
- 	    }
- 	  if (or_comma && token->type == CPP_COMMA
- 	      && !brace_depth && !paren_depth)
- 	    return -1;
  	}
        
-       /* Consume the token.  */
-       token = cp_lexer_consume_token (parser->lexer);
- 
        if (!brace_depth)
  	{
  	  /* If it is an `(', we have entered another level of nesting.  */
  	  if (token->type == CPP_OPEN_PAREN)
  	    ++paren_depth;
  	  /* If it is a `)', then we might be done.  */
  	  else if (token->type == CPP_CLOSE_PAREN && !paren_depth--)
! 	    return 1;
  	}
      }
  }
  
  /* Consume tokens until we reach the end of the current statement.
     Normally, that will be just before consuming a `;'.  However, if a
--- 1920,1961 ----
        
        /* If we've run out of tokens, then there is no closing `)'.  */
        if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
  	return 0;
  
!       token = cp_lexer_peek_token (parser->lexer);
!       
!       /* This matches the processing in skip_to_end_of_statement */
!       if (token->type == CPP_SEMICOLON && !brace_depth)
! 	return 0;
!       if (token->type == CPP_OPEN_BRACE)
! 	++brace_depth;
!       if (token->type == CPP_CLOSE_BRACE)
  	{
! 	  if (!brace_depth--)
  	    return 0;
  	}
+       if (recovering && or_comma && token->type == CPP_COMMA
+ 	  && !brace_depth && !paren_depth)
+ 	return -1;
        
        if (!brace_depth)
  	{
  	  /* If it is an `(', we have entered another level of nesting.  */
  	  if (token->type == CPP_OPEN_PAREN)
  	    ++paren_depth;
  	  /* If it is a `)', then we might be done.  */
  	  else if (token->type == CPP_CLOSE_PAREN && !paren_depth--)
! 	    {
! 	      if (consume_paren)
! 		cp_lexer_consume_token (parser->lexer);
! 	      return 1;
! 	    }
  	}
+       
+       /* Consume the token.  */
+       cp_lexer_consume_token (parser->lexer);
      }
  }
  
  /* Consume tokens until we reach the end of the current statement.
     Normally, that will be just before consuming a `;'.  However, if a
*************** cp_parser_id_expression (cp_parser *pars
*** 2541,2551 ****
    /* Look for the optional nested-name-specifier.  */
    nested_name_specifier_p 
      = (cp_parser_nested_name_specifier_opt (parser,
  					    /*typename_keyword_p=*/false,
  					    check_dependency_p,
! 					    /*type_p=*/false)
         != NULL_TREE);
    /* If there is a nested-name-specifier, then we are looking at
       the first qualified-id production.  */
    if (nested_name_specifier_p)
      {
--- 2557,2568 ----
    /* Look for the optional nested-name-specifier.  */
    nested_name_specifier_p 
      = (cp_parser_nested_name_specifier_opt (parser,
  					    /*typename_keyword_p=*/false,
  					    check_dependency_p,
! 					    /*type_p=*/false,
! 					    /*is_declarator=*/false)
         != NULL_TREE);
    /* If there is a nested-name-specifier, then we are looking at
       the first qualified-id production.  */
    if (nested_name_specifier_p)
      {
*************** cp_parser_id_expression (cp_parser *pars
*** 2594,2604 ****
  
        cp_parser_parse_tentatively (parser);
        /* Try a template-id.  */
        id = cp_parser_template_id (parser, 
  				  /*template_keyword_p=*/false,
! 				  /*check_dependency_p=*/true);
        /* If that worked, we're done.  */
        if (cp_parser_parse_definitely (parser))
  	return id;
  
        /* Peek at the next token.  (Changes in the token buffer may
--- 2611,2622 ----
  
        cp_parser_parse_tentatively (parser);
        /* Try a template-id.  */
        id = cp_parser_template_id (parser, 
  				  /*template_keyword_p=*/false,
! 				  /*check_dependency_p=*/true,
! 				  declarator_p);
        /* If that worked, we're done.  */
        if (cp_parser_parse_definitely (parser))
  	return id;
  
        /* Peek at the next token.  (Changes in the token buffer may
*************** cp_parser_unqualified_id (cp_parser* par
*** 2668,2688 ****
  	/* We don't know yet whether or not this will be a
  	   template-id.  */
  	cp_parser_parse_tentatively (parser);
  	/* Try a template-id.  */
  	id = cp_parser_template_id (parser, template_keyword_p,
! 				    check_dependency_p);
  	/* If it worked, we're done.  */
  	if (cp_parser_parse_definitely (parser))
  	  return id;
  	/* Otherwise, it's an ordinary identifier.  */
  	return cp_parser_identifier (parser);
        }
  
      case CPP_TEMPLATE_ID:
        return cp_parser_template_id (parser, template_keyword_p,
! 				    check_dependency_p);
  
      case CPP_COMPL:
        {
  	tree type_decl;
  	tree qualifying_scope;
--- 2686,2708 ----
  	/* We don't know yet whether or not this will be a
  	   template-id.  */
  	cp_parser_parse_tentatively (parser);
  	/* Try a template-id.  */
  	id = cp_parser_template_id (parser, template_keyword_p,
! 				    check_dependency_p,
! 				    declarator_p);
  	/* If it worked, we're done.  */
  	if (cp_parser_parse_definitely (parser))
  	  return id;
  	/* Otherwise, it's an ordinary identifier.  */
  	return cp_parser_identifier (parser);
        }
  
      case CPP_TEMPLATE_ID:
        return cp_parser_template_id (parser, template_keyword_p,
! 				    check_dependency_p,
! 				    declarator_p);
  
      case CPP_COMPL:
        {
  	tree type_decl;
  	tree qualifying_scope;
*************** cp_parser_unqualified_id (cp_parser* par
*** 2750,2760 ****
  	    type_decl = cp_parser_class_name (parser, 
  					      /*typename_keyword_p=*/false,
  					      /*template_keyword_p=*/false,
  					      /*type_p=*/false,
  					      /*check_dependency=*/false,
! 					      /*class_head_p=*/false);
  	    if (cp_parser_parse_definitely (parser))
  	      return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
  	  }
  	/* In "N::S::~S", look in "N" as well.  */
  	if (scope && qualifying_scope)
--- 2770,2781 ----
  	    type_decl = cp_parser_class_name (parser, 
  					      /*typename_keyword_p=*/false,
  					      /*template_keyword_p=*/false,
  					      /*type_p=*/false,
  					      /*check_dependency=*/false,
! 					      /*class_head_p=*/false,
! 					      declarator_p);
  	    if (cp_parser_parse_definitely (parser))
  	      return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
  	  }
  	/* In "N::S::~S", look in "N" as well.  */
  	if (scope && qualifying_scope)
*************** cp_parser_unqualified_id (cp_parser* par
*** 2767,2777 ****
  	      = cp_parser_class_name (parser, 
  				      /*typename_keyword_p=*/false,
  				      /*template_keyword_p=*/false,
  				      /*type_p=*/false,
  				      /*check_dependency=*/false,
! 				      /*class_head_p=*/false);
  	    if (cp_parser_parse_definitely (parser))
  	      return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
  	  }
  	/* In "p->S::~T", look in the scope given by "*p" as well.  */
  	else if (object_scope)
--- 2788,2799 ----
  	      = cp_parser_class_name (parser, 
  				      /*typename_keyword_p=*/false,
  				      /*template_keyword_p=*/false,
  				      /*type_p=*/false,
  				      /*check_dependency=*/false,
! 				      /*class_head_p=*/false,
! 				      declarator_p);
  	    if (cp_parser_parse_definitely (parser))
  	      return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
  	  }
  	/* In "p->S::~T", look in the scope given by "*p" as well.  */
  	else if (object_scope)
*************** cp_parser_unqualified_id (cp_parser* par
*** 2784,2794 ****
  	      = cp_parser_class_name (parser, 
  				      /*typename_keyword_p=*/false,
  				      /*template_keyword_p=*/false,
  				      /*type_p=*/false,
  				      /*check_dependency=*/false,
! 				      /*class_head_p=*/false);
  	    if (cp_parser_parse_definitely (parser))
  	      return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
  	  }
  	/* Look in the surrounding context.  */
  	parser->scope = NULL_TREE;
--- 2806,2817 ----
  	      = cp_parser_class_name (parser, 
  				      /*typename_keyword_p=*/false,
  				      /*template_keyword_p=*/false,
  				      /*type_p=*/false,
  				      /*check_dependency=*/false,
! 				      /*class_head_p=*/false,
! 				      declarator_p);
  	    if (cp_parser_parse_definitely (parser))
  	      return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
  	  }
  	/* Look in the surrounding context.  */
  	parser->scope = NULL_TREE;
*************** cp_parser_unqualified_id (cp_parser* par
*** 2798,2808 ****
  	  = cp_parser_class_name (parser, 
  				  /*typename_keyword_p=*/false,
  				  /*template_keyword_p=*/false,
  				  /*type_p=*/false,
  				  /*check_dependency=*/false,
! 				  /*class_head_p=*/false);
  	/* If an error occurred, assume that the name of the
  	   destructor is the same as the name of the qualifying
  	   class.  That allows us to keep parsing after running
  	   into ill-formed destructor names.  */
  	if (type_decl == error_mark_node && scope && TYPE_P (scope))
--- 2821,2832 ----
  	  = cp_parser_class_name (parser, 
  				  /*typename_keyword_p=*/false,
  				  /*template_keyword_p=*/false,
  				  /*type_p=*/false,
  				  /*check_dependency=*/false,
! 				  /*class_head_p=*/false,
! 				  declarator_p);
  	/* If an error occurred, assume that the name of the
  	   destructor is the same as the name of the qualifying
  	   class.  That allows us to keep parsing after running
  	   into ill-formed destructor names.  */
  	if (type_decl == error_mark_node && scope && TYPE_P (scope))
*************** cp_parser_unqualified_id (cp_parser* par
*** 2830,2840 ****
  
  	  /* This could be a template-id, so we try that first.  */
  	  cp_parser_parse_tentatively (parser);
  	  /* Try a template-id.  */
  	  id = cp_parser_template_id (parser, template_keyword_p,
! 				      /*check_dependency_p=*/true);
  	  /* If that worked, we're done.  */
  	  if (cp_parser_parse_definitely (parser))
  	    return id;
  	  /* We still don't know whether we're looking at an
  	     operator-function-id or a conversion-function-id.  */
--- 2854,2865 ----
  
  	  /* This could be a template-id, so we try that first.  */
  	  cp_parser_parse_tentatively (parser);
  	  /* Try a template-id.  */
  	  id = cp_parser_template_id (parser, template_keyword_p,
! 				      /*check_dependency_p=*/true,
! 				      declarator_p);
  	  /* If that worked, we're done.  */
  	  if (cp_parser_parse_definitely (parser))
  	    return id;
  	  /* We still don't know whether we're looking at an
  	     operator-function-id or a conversion-function-id.  */
*************** cp_parser_unqualified_id (cp_parser* par
*** 2867,2883 ****
     in name lookups.
  
     Sets PARSER->SCOPE to the class (TYPE) or namespace
     (NAMESPACE_DECL) specified by the nested-name-specifier, or leaves
     it unchanged if there is no nested-name-specifier.  Returns the new
!    scope iff there is a nested-name-specifier, or NULL_TREE otherwise.  */
  
  static tree
  cp_parser_nested_name_specifier_opt (cp_parser *parser, 
  				     bool typename_keyword_p, 
  				     bool check_dependency_p,
! 				     bool type_p)
  {
    bool success = false;
    tree access_check = NULL_TREE;
    ptrdiff_t start;
    cp_token* token;
--- 2892,2912 ----
     in name lookups.
  
     Sets PARSER->SCOPE to the class (TYPE) or namespace
     (NAMESPACE_DECL) specified by the nested-name-specifier, or leaves
     it unchanged if there is no nested-name-specifier.  Returns the new
!    scope iff there is a nested-name-specifier, or NULL_TREE otherwise.  
! 
!    If IS_DECLARATION is TRUE, the nested-name-specifier is known to be
!    part of a declaration and/or decl-specifier.  */
  
  static tree
  cp_parser_nested_name_specifier_opt (cp_parser *parser, 
  				     bool typename_keyword_p, 
  				     bool check_dependency_p,
! 				     bool type_p,
! 				     bool is_declaration)
  {
    bool success = false;
    tree access_check = NULL_TREE;
    ptrdiff_t start;
    cp_token* token;
*************** cp_parser_nested_name_specifier_opt (cp_
*** 2972,2982 ****
        new_scope 
  	= cp_parser_class_or_namespace_name (parser,
  					     typename_keyword_p,
  					     template_keyword_p,
  					     check_dependency_p,
! 					     type_p);
        /* Look for the `::' token.  */
        cp_parser_require (parser, CPP_SCOPE, "`::'");
  
        /* If we found what we wanted, we keep going; otherwise, we're
  	 done.  */
--- 3001,3012 ----
        new_scope 
  	= cp_parser_class_or_namespace_name (parser,
  					     typename_keyword_p,
  					     template_keyword_p,
  					     check_dependency_p,
! 					     type_p,
! 					     is_declaration);
        /* Look for the `::' token.  */
        cp_parser_require (parser, CPP_SCOPE, "`::'");
  
        /* If we found what we wanted, we keep going; otherwise, we're
  	 done.  */
*************** cp_parser_nested_name_specifier_opt (cp_
*** 3099,3117 ****
  
  static tree
  cp_parser_nested_name_specifier (cp_parser *parser, 
  				 bool typename_keyword_p, 
  				 bool check_dependency_p,
! 				 bool type_p)
  {
    tree scope;
  
    /* Look for the nested-name-specifier.  */
    scope = cp_parser_nested_name_specifier_opt (parser,
  					       typename_keyword_p,
  					       check_dependency_p,
! 					       type_p);
    /* If it was not present, issue an error message.  */
    if (!scope)
      {
        cp_parser_error (parser, "expected nested-name-specifier");
        parser->scope = NULL_TREE;
--- 3129,3149 ----
  
  static tree
  cp_parser_nested_name_specifier (cp_parser *parser, 
  				 bool typename_keyword_p, 
  				 bool check_dependency_p,
! 				 bool type_p,
! 				 bool is_declaration)
  {
    tree scope;
  
    /* Look for the nested-name-specifier.  */
    scope = cp_parser_nested_name_specifier_opt (parser,
  					       typename_keyword_p,
  					       check_dependency_p,
! 					       type_p,
! 					       is_declaration);
    /* If it was not present, issue an error message.  */
    if (!scope)
      {
        cp_parser_error (parser, "expected nested-name-specifier");
        parser->scope = NULL_TREE;
*************** cp_parser_nested_name_specifier (cp_pars
*** 3141,3151 ****
  static tree
  cp_parser_class_or_namespace_name (cp_parser *parser, 
  				   bool typename_keyword_p,
  				   bool template_keyword_p,
  				   bool check_dependency_p,
! 				   bool type_p)
  {
    tree saved_scope;
    tree saved_qualifying_scope;
    tree saved_object_scope;
    tree scope;
--- 3173,3184 ----
  static tree
  cp_parser_class_or_namespace_name (cp_parser *parser, 
  				   bool typename_keyword_p,
  				   bool template_keyword_p,
  				   bool check_dependency_p,
! 				   bool type_p,
! 				   bool is_declaration)
  {
    tree saved_scope;
    tree saved_qualifying_scope;
    tree saved_object_scope;
    tree scope;
*************** cp_parser_class_or_namespace_name (cp_pa
*** 3165,3175 ****
    scope = cp_parser_class_name (parser, 
  				typename_keyword_p,
  				template_keyword_p,
  				type_p,
  				check_dependency_p,
! 				/*class_head_p=*/false);
    /* If that didn't work, try for a namespace-name.  */
    if (!only_class_p && !cp_parser_parse_definitely (parser))
      {
        /* Restore the saved scope.  */
        parser->scope = saved_scope;
--- 3198,3209 ----
    scope = cp_parser_class_name (parser, 
  				typename_keyword_p,
  				template_keyword_p,
  				type_p,
  				check_dependency_p,
! 				/*class_head_p=*/false,
! 				is_declaration);
    /* If that didn't work, try for a namespace-name.  */
    if (!only_class_p && !cp_parser_parse_definitely (parser))
      {
        /* Restore the saved scope.  */
        parser->scope = saved_scope;
*************** cp_parser_postfix_expression (cp_parser 
*** 3370,3388 ****
  				    /*current_scope_valid_p=*/false);
  	/* Look for the nested-name-specifier.  */
  	cp_parser_nested_name_specifier (parser,
  					 /*typename_keyword_p=*/true,
  					 /*check_dependency_p=*/true,
! 					 /*type_p=*/true);
  	/* Look for the optional `template' keyword.  */
  	template_p = cp_parser_optional_template_keyword (parser);
  	/* We don't know whether we're looking at a template-id or an
  	   identifier.  */
  	cp_parser_parse_tentatively (parser);
  	/* Try a template-id.  */
  	id = cp_parser_template_id (parser, template_p,
! 				    /*check_dependency_p=*/true);
  	/* If that didn't work, try an identifier.  */
  	if (!cp_parser_parse_definitely (parser))
  	  id = cp_parser_identifier (parser);
  	/* Create a TYPENAME_TYPE to represent the type to which the
  	   functional cast is being performed.  */
--- 3404,3424 ----
  				    /*current_scope_valid_p=*/false);
  	/* Look for the nested-name-specifier.  */
  	cp_parser_nested_name_specifier (parser,
  					 /*typename_keyword_p=*/true,
  					 /*check_dependency_p=*/true,
! 					 /*type_p=*/true,
! 					 /*is_declaration=*/true);
  	/* Look for the optional `template' keyword.  */
  	template_p = cp_parser_optional_template_keyword (parser);
  	/* We don't know whether we're looking at a template-id or an
  	   identifier.  */
  	cp_parser_parse_tentatively (parser);
  	/* Try a template-id.  */
  	id = cp_parser_template_id (parser, template_p,
! 				    /*check_dependency_p=*/true,
! 				    /*is_declaration=*/true);
  	/* If that didn't work, try an identifier.  */
  	if (!cp_parser_parse_definitely (parser))
  	  id = cp_parser_identifier (parser);
  	/* Create a TYPENAME_TYPE to represent the type to which the
  	   functional cast is being performed.  */
*************** cp_parser_parenthesized_expression_list 
*** 3870,3880 ****
        int ending;
        
      skip_comma:;
        /* We try and resync to an unnested comma, as that will give the
  	 user better diagnostics.  */
!       ending = cp_parser_skip_to_closing_parenthesis (parser, true, true);
        if (ending < 0)
  	goto get_comma;
        if (!ending)
  	return error_mark_node;
      }
--- 3906,3917 ----
        int ending;
        
      skip_comma:;
        /* We try and resync to an unnested comma, as that will give the
  	 user better diagnostics.  */
!       ending = cp_parser_skip_to_closing_parenthesis (parser, true, true,
! 						      /*consume_paren=*/true);
        if (ending < 0)
  	goto get_comma;
        if (!ending)
  	return error_mark_node;
      }
*************** cp_parser_pseudo_destructor_name (cp_par
*** 3911,3921 ****
    /* Look for the optional nested-name-specifier.  */
    nested_name_specifier_p 
      = (cp_parser_nested_name_specifier_opt (parser,
  					    /*typename_keyword_p=*/false,
  					    /*check_dependency_p=*/true,
! 					    /*type_p=*/false) 
         != NULL_TREE);
    /* Now, if we saw a nested-name-specifier, we might be doing the
       second production.  */
    if (nested_name_specifier_p 
        && cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
--- 3948,3959 ----
    /* Look for the optional nested-name-specifier.  */
    nested_name_specifier_p 
      = (cp_parser_nested_name_specifier_opt (parser,
  					    /*typename_keyword_p=*/false,
  					    /*check_dependency_p=*/true,
! 					    /*type_p=*/false,
! 					    /*is_declaration=*/true) 
         != NULL_TREE);
    /* Now, if we saw a nested-name-specifier, we might be doing the
       second production.  */
    if (nested_name_specifier_p 
        && cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
*************** cp_parser_pseudo_destructor_name (cp_par
*** 3923,3933 ****
        /* Consume the `template' keyword.  */
        cp_lexer_consume_token (parser->lexer);
        /* Parse the template-id.  */
        cp_parser_template_id (parser, 
  			     /*template_keyword_p=*/true,
! 			     /*check_dependency_p=*/false);
        /* Look for the `::' token.  */
        cp_parser_require (parser, CPP_SCOPE, "`::'");
      }
    /* If the next token is not a `~', then there might be some
       additional qualification.  */
--- 3961,3972 ----
        /* Consume the `template' keyword.  */
        cp_lexer_consume_token (parser->lexer);
        /* Parse the template-id.  */
        cp_parser_template_id (parser, 
  			     /*template_keyword_p=*/true,
! 			     /*check_dependency_p=*/false,
! 			     /*is_declaration=*/true);
        /* Look for the `::' token.  */
        cp_parser_require (parser, CPP_SCOPE, "`::'");
      }
    /* If the next token is not a `~', then there might be some
       additional qualification.  */
*************** cp_parser_cast_expression (cp_parser *pa
*** 4501,4511 ****
        cp_lexer_save_tokens (parser->lexer);
        /* Skip tokens until the next token is a closing parenthesis.
  	 If we find the closing `)', and the next token is a `{', then
  	 we are looking at a compound-literal.  */
        compound_literal_p 
! 	= (cp_parser_skip_to_closing_parenthesis (parser, false, false)
  	   && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE));
        /* Roll back the tokens we skipped.  */
        cp_lexer_rollback_tokens (parser->lexer);
        /* If we were looking at a compound-literal, simulate an error
  	 so that the call to cp_parser_parse_definitely below will
--- 4540,4551 ----
        cp_lexer_save_tokens (parser->lexer);
        /* Skip tokens until the next token is a closing parenthesis.
  	 If we find the closing `)', and the next token is a `{', then
  	 we are looking at a compound-literal.  */
        compound_literal_p 
! 	= (cp_parser_skip_to_closing_parenthesis (parser, false, false,
! 						  /*consume_paren=*/true)
  	   && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE));
        /* Roll back the tokens we skipped.  */
        cp_lexer_rollback_tokens (parser->lexer);
        /* If we were looking at a compound-literal, simulate an error
  	 so that the call to cp_parser_parse_definitely below will
*************** cp_parser_selection_statement (cp_parser
*** 5428,5438 ****
  
  	/* Parse the condition.  */
  	condition = cp_parser_condition (parser);
  	/* Look for the `)'.  */
  	if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
! 	  cp_parser_skip_to_closing_parenthesis (parser, true, false);
  
  	if (keyword == RID_IF)
  	  {
  	    tree then_stmt;
  
--- 5468,5479 ----
  
  	/* Parse the condition.  */
  	condition = cp_parser_condition (parser);
  	/* Look for the `)'.  */
  	if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
! 	  cp_parser_skip_to_closing_parenthesis (parser, true, false,
! 						 /*consume_paren=*/true);
  
  	if (keyword == RID_IF)
  	  {
  	    tree then_stmt;
  
*************** cp_parser_mem_initializer_id (cp_parser*
*** 6922,6951 ****
       point.  */
    nested_name_specifier_p 
      = (cp_parser_nested_name_specifier_opt (parser,
  					    /*typename_keyword_p=*/true,
  					    /*check_dependency_p=*/true,
! 					    /*type_p=*/true)
         != NULL_TREE);
    /* If there is a `::' operator or a nested-name-specifier, then we
       are definitely looking for a class-name.  */
    if (global_scope_p || nested_name_specifier_p)
      return cp_parser_class_name (parser,
  				 /*typename_keyword_p=*/true,
  				 /*template_keyword_p=*/false,
  				 /*type_p=*/false,
  				 /*check_dependency_p=*/true,
! 				 /*class_head_p=*/false);
    /* Otherwise, we could also be looking for an ordinary identifier.  */
    cp_parser_parse_tentatively (parser);
    /* Try a class-name.  */
    id = cp_parser_class_name (parser, 
  			     /*typename_keyword_p=*/true,
  			     /*template_keyword_p=*/false,
  			     /*type_p=*/false,
  			     /*check_dependency_p=*/true,
! 			     /*class_head_p=*/false);
    /* If we found one, we're done.  */
    if (cp_parser_parse_definitely (parser))
      return id;
    /* Otherwise, look for an ordinary identifier.  */
    return cp_parser_identifier (parser);
--- 6963,6995 ----
       point.  */
    nested_name_specifier_p 
      = (cp_parser_nested_name_specifier_opt (parser,
  					    /*typename_keyword_p=*/true,
  					    /*check_dependency_p=*/true,
! 					    /*type_p=*/true,
! 					    /*is_declaration=*/true)
         != NULL_TREE);
    /* If there is a `::' operator or a nested-name-specifier, then we
       are definitely looking for a class-name.  */
    if (global_scope_p || nested_name_specifier_p)
      return cp_parser_class_name (parser,
  				 /*typename_keyword_p=*/true,
  				 /*template_keyword_p=*/false,
  				 /*type_p=*/false,
  				 /*check_dependency_p=*/true,
! 				 /*class_head_p=*/false,
! 				 /*is_declaration=*/true);
    /* Otherwise, we could also be looking for an ordinary identifier.  */
    cp_parser_parse_tentatively (parser);
    /* Try a class-name.  */
    id = cp_parser_class_name (parser, 
  			     /*typename_keyword_p=*/true,
  			     /*template_keyword_p=*/false,
  			     /*type_p=*/false,
  			     /*check_dependency_p=*/true,
! 			     /*class_head_p=*/false,
! 			     /*is_declaration=*/true);
    /* If we found one, we're done.  */
    if (cp_parser_parse_definitely (parser))
      return id;
    /* Otherwise, look for an ordinary identifier.  */
    return cp_parser_identifier (parser);
*************** cp_parser_type_parameter (cp_parser* par
*** 7505,7522 ****
     uninstantiated templates.  */
  
  static tree
  cp_parser_template_id (cp_parser *parser, 
  		       bool template_keyword_p, 
! 		       bool check_dependency_p)
  {
    tree template;
    tree arguments;
    tree template_id;
    ptrdiff_t start_of_id;
    tree access_check = NULL_TREE;
    cp_token *next_token;
  
    /* If the next token corresponds to a template-id, there is no need
       to reparse it.  */
    next_token = cp_lexer_peek_token (parser->lexer);
    if (next_token->type == CPP_TEMPLATE_ID)
--- 7549,7568 ----
     uninstantiated templates.  */
  
  static tree
  cp_parser_template_id (cp_parser *parser, 
  		       bool template_keyword_p, 
! 		       bool check_dependency_p,
! 		       bool is_declaration)
  {
    tree template;
    tree arguments;
    tree template_id;
    ptrdiff_t start_of_id;
    tree access_check = NULL_TREE;
    cp_token *next_token;
+   bool is_identifier;
  
    /* If the next token corresponds to a template-id, there is no need
       to reparse it.  */
    next_token = cp_lexer_peek_token (parser->lexer);
    if (next_token->type == CPP_TEMPLATE_ID)
*************** cp_parser_template_id (cp_parser *parser
*** 7557,7572 ****
      start_of_id = -1;
  
    push_deferring_access_checks (dk_deferred);
  
    /* Parse the template-name.  */
    template = cp_parser_template_name (parser, template_keyword_p,
! 				      check_dependency_p);
!   if (template == error_mark_node)
      {
        pop_deferring_access_checks ();
!       return error_mark_node;
      }
  
    /* Look for the `<' that starts the template-argument-list.  */
    if (!cp_parser_require (parser, CPP_LESS, "`<'"))
      {
--- 7603,7621 ----
      start_of_id = -1;
  
    push_deferring_access_checks (dk_deferred);
  
    /* Parse the template-name.  */
+   is_identifier = false;
    template = cp_parser_template_name (parser, template_keyword_p,
! 				      check_dependency_p,
! 				      is_declaration,
! 				      &is_identifier);
!   if (template == error_mark_node || is_identifier)
      {
        pop_deferring_access_checks ();
!       return template;
      }
  
    /* Look for the `<' that starts the template-argument-list.  */
    if (!cp_parser_require (parser, CPP_LESS, "`<'"))
      {
*************** cp_parser_template_id (cp_parser *parser
*** 7659,7669 ****
     names are looked up inside uninstantiated templates.  */
  
  static tree
  cp_parser_template_name (cp_parser* parser, 
                           bool template_keyword_p, 
!                          bool check_dependency_p)
  {
    tree identifier;
    tree decl;
    tree fns;
  
--- 7708,7720 ----
     names are looked up inside uninstantiated templates.  */
  
  static tree
  cp_parser_template_name (cp_parser* parser, 
                           bool template_keyword_p, 
!                          bool check_dependency_p,
! 			 bool is_declaration,
! 			 bool *is_identifier)
  {
    tree identifier;
    tree decl;
    tree fns;
  
*************** cp_parser_template_name (cp_parser* pars
*** 7697,7709 ****
         template <typename T> struct S { S(); };
         template <typename T> S<T>::S();
  
       correctly.  We would treat `S' as a template -- if it were `S<T>'
       -- but we do not if there is no `<'.  */
!   if (template_keyword_p && processing_template_decl
        && cp_lexer_next_token_is (parser->lexer, CPP_LESS))
!     return identifier;
  
    /* Look up the name.  */
    decl = cp_parser_lookup_name (parser, identifier,
  				/*is_type=*/false,
  				/*is_namespace=*/false,
--- 7748,7821 ----
         template <typename T> struct S { S(); };
         template <typename T> S<T>::S();
  
       correctly.  We would treat `S' as a template -- if it were `S<T>'
       -- but we do not if there is no `<'.  */
! 
!   if (processing_template_decl
        && cp_lexer_next_token_is (parser->lexer, CPP_LESS))
!     {
!       /* In a declaration, in a dependent context, we pretend that the
! 	 "template" keyword was present in order to improve error
! 	 recovery.  For example, given:
! 	 
! 	   template <typename T> void f(T::X<int>);
! 	 
! 	 we want to treat "X<int>" as a template-id.  */
!       if (is_declaration 
! 	  && !template_keyword_p 
! 	  && parser->scope && TYPE_P (parser->scope)
! 	  && dependent_type_p (parser->scope))
! 	{
! 	  ptrdiff_t start;
! 	  cp_token* token;
! 	  /* Explain what went wrong.  */
! 	  error ("non-template `%D' used as template", identifier);
! 	  error ("(use `%T::template %D' to indicate that it is a template)",
! 		 parser->scope, identifier);
! 	  /* If parsing tentatively, find the location of the "<"
! 	     token.  */
! 	  if (cp_parser_parsing_tentatively (parser)
! 	      && !cp_parser_committed_to_tentative_parse (parser))
! 	    {
! 	      cp_parser_simulate_error (parser);
! 	      token = cp_lexer_peek_token (parser->lexer);
! 	      token = cp_lexer_prev_token (parser->lexer, token);
! 	      start = cp_lexer_token_difference (parser->lexer,
! 						 parser->lexer->first_token,
! 						 token);
! 	    }
! 	  else
! 	    start = -1;
! 	  /* Parse the template arguments so that we can issue error
! 	     messages about them.  */
! 	  cp_lexer_consume_token (parser->lexer);
! 	  cp_parser_enclosed_template_argument_list (parser);
! 	  /* Skip tokens until we find a good place from which to
! 	     continue parsing.  */
! 	  cp_parser_skip_to_closing_parenthesis (parser,
! 						 /*recovering=*/true,
! 						 /*or_comma=*/true,
! 						 /*consume_paren=*/false);
! 	  /* If parsing tentatively, permanently remove the
! 	     template argument list.  That will prevent duplicate
! 	     error messages from being issued about the missing
! 	     "template" keyword.  */
! 	  if (start >= 0)
! 	    {
! 	      token = cp_lexer_advance_token (parser->lexer,
! 					      parser->lexer->first_token,
! 					      start);
! 	      cp_lexer_purge_tokens_after (parser->lexer, token);
! 	    }
! 	  if (is_identifier)
! 	    *is_identifier = true;
! 	  return identifier;
! 	}
!       if (template_keyword_p)
! 	return identifier;
!     }
  
    /* Look up the name.  */
    decl = cp_parser_lookup_name (parser, identifier,
  				/*is_type=*/false,
  				/*is_namespace=*/false,
*************** cp_parser_simple_type_specifier (cp_pars
*** 8362,8381 ****
  				  /*current_scope_valid_p=*/false);
        /* Look for the nested-name specifier.  */
        cp_parser_nested_name_specifier_opt (parser,
  					   /*typename_keyword_p=*/false,
  					   /*check_dependency_p=*/true,
! 					   /*type_p=*/false);
        /* If we have seen a nested-name-specifier, and the next token
  	 is `template', then we are using the template-id production.  */
        if (parser->scope 
  	  && cp_parser_optional_template_keyword (parser))
  	{
  	  /* Look for the template-id.  */
  	  type = cp_parser_template_id (parser, 
  					/*template_keyword_p=*/true,
! 					/*check_dependency_p=*/true);
  	  /* If the template-id did not name a type, we are out of
  	     luck.  */
  	  if (TREE_CODE (type) != TYPE_DECL)
  	    {
  	      cp_parser_error (parser, "expected template-id for type");
--- 8474,8495 ----
  				  /*current_scope_valid_p=*/false);
        /* Look for the nested-name specifier.  */
        cp_parser_nested_name_specifier_opt (parser,
  					   /*typename_keyword_p=*/false,
  					   /*check_dependency_p=*/true,
! 					   /*type_p=*/false,
! 					   /*is_declaration=*/false);
        /* If we have seen a nested-name-specifier, and the next token
  	 is `template', then we are using the template-id production.  */
        if (parser->scope 
  	  && cp_parser_optional_template_keyword (parser))
  	{
  	  /* Look for the template-id.  */
  	  type = cp_parser_template_id (parser, 
  					/*template_keyword_p=*/true,
! 					/*check_dependency_p=*/true,
! 					/*is_declaration=*/false);
  	  /* If the template-id did not name a type, we are out of
  	     luck.  */
  	  if (TREE_CODE (type) != TYPE_DECL)
  	    {
  	      cp_parser_error (parser, "expected template-id for type");
*************** cp_parser_simple_type_specifier (cp_pars
*** 8401,8413 ****
      {
        cp_parser_error (parser, "expected type-name");
        return error_mark_node;
      }
  
!   /* There is no valid C++ program where a non-template type can never
!      be followed by a "<".  That usually indicates that the user
!      thought that the type was a template.  */
    if (type && cp_lexer_next_token_is (parser->lexer, CPP_LESS))
      {
        error ("`%T' is not a template", TREE_TYPE (type));
        /* Consume the "<".  */
        cp_lexer_consume_token (parser->lexer);
--- 8515,8527 ----
      {
        cp_parser_error (parser, "expected type-name");
        return error_mark_node;
      }
  
!   /* There is no valid C++ program where a non-template type is
!      followed by a "<".  That usually indicates that the user thought
!      that the type was a template.  */
    if (type && cp_lexer_next_token_is (parser->lexer, CPP_LESS))
      {
        error ("`%T' is not a template", TREE_TYPE (type));
        /* Consume the "<".  */
        cp_lexer_consume_token (parser->lexer);
*************** cp_parser_type_name (cp_parser* parser)
*** 8448,8458 ****
    type_decl = cp_parser_class_name (parser, 
  				    /*typename_keyword_p=*/false,
  				    /*template_keyword_p=*/false,
  				    /*type_p=*/false,
  				    /*check_dependency_p=*/true,
! 				    /*class_head_p=*/false);
    /* If it's not a class-name, keep looking.  */
    if (!cp_parser_parse_definitely (parser))
      {
        /* It must be a typedef-name or an enum-name.  */
        identifier = cp_parser_identifier (parser);
--- 8562,8573 ----
    type_decl = cp_parser_class_name (parser, 
  				    /*typename_keyword_p=*/false,
  				    /*template_keyword_p=*/false,
  				    /*type_p=*/false,
  				    /*check_dependency_p=*/true,
! 				    /*class_head_p=*/false,
! 				    /*is_declaration=*/false);
    /* If it's not a class-name, keep looking.  */
    if (!cp_parser_parse_definitely (parser))
      {
        /* It must be a typedef-name or an enum-name.  */
        identifier = cp_parser_identifier (parser);
*************** cp_parser_elaborated_type_specifier (cp_
*** 8542,8563 ****
    if (tag_type == typename_type)
      {
        if (cp_parser_nested_name_specifier (parser,
  					   /*typename_keyword_p=*/true,
  					   /*check_dependency_p=*/true,
! 					   /*type_p=*/true) 
  	  == error_mark_node)
  	return error_mark_node;
      }
    else
      /* Even though `typename' is not present, the proposed resolution
         to Core Issue 180 says that in `class A<T>::B', `B' should be
         considered a type-name, even if `A<T>' is dependent.  */
      cp_parser_nested_name_specifier_opt (parser,
  					 /*typename_keyword_p=*/true,
  					 /*check_dependency_p=*/true,
! 					 /*type_p=*/true);
    /* For everything but enumeration types, consider a template-id.  */
    if (tag_type != enum_type)
      {
        bool template_p = false;
        tree decl;
--- 8657,8680 ----
    if (tag_type == typename_type)
      {
        if (cp_parser_nested_name_specifier (parser,
  					   /*typename_keyword_p=*/true,
  					   /*check_dependency_p=*/true,
! 					   /*type_p=*/true,
! 					   is_declaration) 
  	  == error_mark_node)
  	return error_mark_node;
      }
    else
      /* Even though `typename' is not present, the proposed resolution
         to Core Issue 180 says that in `class A<T>::B', `B' should be
         considered a type-name, even if `A<T>' is dependent.  */
      cp_parser_nested_name_specifier_opt (parser,
  					 /*typename_keyword_p=*/true,
  					 /*check_dependency_p=*/true,
! 					 /*type_p=*/true,
! 					 is_declaration);
    /* For everything but enumeration types, consider a template-id.  */
    if (tag_type != enum_type)
      {
        bool template_p = false;
        tree decl;
*************** cp_parser_elaborated_type_specifier (cp_
*** 8568,8578 ****
           template-id or not.  */
        if (!template_p)
  	cp_parser_parse_tentatively (parser);
        /* Parse the template-id.  */
        decl = cp_parser_template_id (parser, template_p,
! 				    /*check_dependency_p=*/true);
        /* If we didn't find a template-id, look for an ordinary
           identifier.  */
        if (!template_p && !cp_parser_parse_definitely (parser))
  	;
        /* If DECL is a TEMPLATE_ID_EXPR, and the `typename' keyword is
--- 8685,8696 ----
           template-id or not.  */
        if (!template_p)
  	cp_parser_parse_tentatively (parser);
        /* Parse the template-id.  */
        decl = cp_parser_template_id (parser, template_p,
! 				    /*check_dependency_p=*/true,
! 				    is_declaration);
        /* If we didn't find a template-id, look for an ordinary
           identifier.  */
        if (!template_p && !cp_parser_parse_definitely (parser))
  	;
        /* If DECL is a TEMPLATE_ID_EXPR, and the `typename' keyword is
*************** cp_parser_qualified_namespace_specifier 
*** 8996,9006 ****
  
    /* Look for the optional nested-name-specifier.  */
    cp_parser_nested_name_specifier_opt (parser,
  				       /*typename_keyword_p=*/false,
  				       /*check_dependency_p=*/true,
! 				       /*type_p=*/false);
  
    return cp_parser_namespace_name (parser);
  }
  
  /* Parse a using-declaration.
--- 9114,9125 ----
  
    /* Look for the optional nested-name-specifier.  */
    cp_parser_nested_name_specifier_opt (parser,
  				       /*typename_keyword_p=*/false,
  				       /*check_dependency_p=*/true,
! 				       /*type_p=*/false,
! 				       /*is_declaration=*/true);
  
    return cp_parser_namespace_name (parser);
  }
  
  /* Parse a using-declaration.
*************** cp_parser_using_declaration (cp_parser* 
*** 9042,9059 ****
    /* If we saw `typename', or didn't see `::', then there must be a
       nested-name-specifier present.  */
    if (typename_p || !global_scope_p)
      cp_parser_nested_name_specifier (parser, typename_p, 
  				     /*check_dependency_p=*/true,
! 				     /*type_p=*/false);
    /* Otherwise, we could be in either of the two productions.  In that
       case, treat the nested-name-specifier as optional.  */
    else
      cp_parser_nested_name_specifier_opt (parser,
  					 /*typename_keyword_p=*/false,
  					 /*check_dependency_p=*/true,
! 					 /*type_p=*/false);
  
    /* Parse the unqualified-id.  */
    identifier = cp_parser_unqualified_id (parser, 
  					 /*template_keyword_p=*/false,
  					 /*check_dependency_p=*/true,
--- 9161,9180 ----
    /* If we saw `typename', or didn't see `::', then there must be a
       nested-name-specifier present.  */
    if (typename_p || !global_scope_p)
      cp_parser_nested_name_specifier (parser, typename_p, 
  				     /*check_dependency_p=*/true,
! 				     /*type_p=*/false,
! 				     /*is_declaration=*/true);
    /* Otherwise, we could be in either of the two productions.  In that
       case, treat the nested-name-specifier as optional.  */
    else
      cp_parser_nested_name_specifier_opt (parser,
  					 /*typename_keyword_p=*/false,
  					 /*check_dependency_p=*/true,
! 					 /*type_p=*/false,
! 					 /*is_declaration=*/true);
  
    /* Parse the unqualified-id.  */
    identifier = cp_parser_unqualified_id (parser, 
  					 /*template_keyword_p=*/false,
  					 /*check_dependency_p=*/true,
*************** cp_parser_using_directive (cp_parser* pa
*** 9123,9133 ****
    cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false);
    /* And the optional nested-name-specifier.  */
    cp_parser_nested_name_specifier_opt (parser,
  				       /*typename_keyword_p=*/false,
  				       /*check_dependency_p=*/true,
! 				       /*type_p=*/false);
    /* Get the namespace being used.  */
    namespace_decl = cp_parser_namespace_name (parser);
    /* And any specified attributes.  */
    attribs = cp_parser_attributes_opt (parser);
    /* Update the symbol table.  */
--- 9244,9255 ----
    cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false);
    /* And the optional nested-name-specifier.  */
    cp_parser_nested_name_specifier_opt (parser,
  				       /*typename_keyword_p=*/false,
  				       /*check_dependency_p=*/true,
! 				       /*type_p=*/false,
! 				       /*is_declaration=*/true);
    /* Get the namespace being used.  */
    namespace_decl = cp_parser_namespace_name (parser);
    /* And any specified attributes.  */
    attribs = cp_parser_attributes_opt (parser);
    /* Update the symbol table.  */
*************** cp_parser_asm_definition (cp_parser* par
*** 9255,9265 ****
  	    clobbers = cp_parser_asm_clobber_list (parser);
  	}
      }
    /* Look for the closing `)'.  */
    if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
!     cp_parser_skip_to_closing_parenthesis (parser, true, false);
    cp_parser_require (parser, CPP_SEMICOLON, "`;'");
  
    /* Create the ASM_STMT.  */
    if (at_function_scope_p ())
      {
--- 9377,9388 ----
  	    clobbers = cp_parser_asm_clobber_list (parser);
  	}
      }
    /* Look for the closing `)'.  */
    if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
!     cp_parser_skip_to_closing_parenthesis (parser, true, false,
! 					   /*consume_paren=*/true);
    cp_parser_require (parser, CPP_SEMICOLON, "`;'");
  
    /* Create the ASM_STMT.  */
    if (at_function_scope_p ())
      {
*************** cp_parser_direct_declarator (cp_parser* 
*** 9889,9899 ****
  
  	  declarator = build_nt (ARRAY_REF, declarator, bounds);
  	}
        else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
  	{
! 	  /* Parse a declarator_id */
  	  if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
  	    cp_parser_parse_tentatively (parser);
  	  declarator = cp_parser_declarator_id (parser);
  	  if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
  	    {
--- 10012,10022 ----
  
  	  declarator = build_nt (ARRAY_REF, declarator, bounds);
  	}
        else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
  	{
! 	  /* Parse a declarator-id */
  	  if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
  	    cp_parser_parse_tentatively (parser);
  	  declarator = cp_parser_declarator_id (parser);
  	  if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
  	    {
*************** cp_parser_ptr_operator (cp_parser* parse
*** 10076,10086 ****
  				  /*current_scope_valid_p=*/false);
        /* Look for the nested-name specifier.  */
        cp_parser_nested_name_specifier (parser,
  				       /*typename_keyword_p=*/false,
  				       /*check_dependency_p=*/true,
! 				       /*type_p=*/false);
        /* If we found it, and the next token is a `*', then we are
  	 indeed looking at a pointer-to-member operator.  */
        if (!cp_parser_error_occurred (parser)
  	  && cp_parser_require (parser, CPP_MULT, "`*'"))
  	{
--- 10199,10210 ----
  				  /*current_scope_valid_p=*/false);
        /* Look for the nested-name specifier.  */
        cp_parser_nested_name_specifier (parser,
  				       /*typename_keyword_p=*/false,
  				       /*check_dependency_p=*/true,
! 				       /*type_p=*/false,
! 				       /*is_declaration=*/false);
        /* If we found it, and the next token is a `*', then we are
  	 indeed looking at a pointer-to-member operator.  */
        if (!cp_parser_error_occurred (parser)
  	  && cp_parser_require (parser, CPP_MULT, "`*'"))
  	{
*************** static tree
*** 11121,11131 ****
  cp_parser_class_name (cp_parser *parser, 
  		      bool typename_keyword_p, 
  		      bool template_keyword_p, 
  		      bool type_p,
  		      bool check_dependency_p,
! 		      bool class_head_p)
  {
    tree decl;
    tree scope;
    bool typename_p;
    cp_token *token;
--- 11245,11256 ----
  cp_parser_class_name (cp_parser *parser, 
  		      bool typename_keyword_p, 
  		      bool template_keyword_p, 
  		      bool type_p,
  		      bool check_dependency_p,
! 		      bool class_head_p,
! 		      bool is_declaration)
  {
    tree decl;
    tree scope;
    bool typename_p;
    cp_token *token;
*************** cp_parser_class_name (cp_parser *parser,
*** 11186,11196 ****
      }
    else
      {
        /* Try a template-id.  */
        decl = cp_parser_template_id (parser, template_keyword_p,
! 				    check_dependency_p);
        if (decl == error_mark_node)
  	return error_mark_node;
      }
  
    decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p);
--- 11311,11322 ----
      }
    else
      {
        /* Try a template-id.  */
        decl = cp_parser_template_id (parser, template_keyword_p,
! 				    check_dependency_p,
! 				    is_declaration);
        if (decl == error_mark_node)
  	return error_mark_node;
      }
  
    decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p);
*************** cp_parser_class_head (cp_parser* parser,
*** 11446,11456 ****
       optional nested-name-specifier.  */
    nested_name_specifier 
      = cp_parser_nested_name_specifier_opt (parser,
  					   /*typename_keyword_p=*/false,
  					   /*check_dependency_p=*/false,
! 					   /*type_p=*/false);
    /* If there was a nested-name-specifier, then there *must* be an
       identifier.  */
    if (nested_name_specifier)
      {
        /* Although the grammar says `identifier', it really means
--- 11572,11583 ----
       optional nested-name-specifier.  */
    nested_name_specifier 
      = cp_parser_nested_name_specifier_opt (parser,
  					   /*typename_keyword_p=*/false,
  					   /*check_dependency_p=*/false,
! 					   /*type_p=*/false,
! 					   /*is_declaration=*/false);
    /* If there was a nested-name-specifier, then there *must* be an
       identifier.  */
    if (nested_name_specifier)
      {
        /* Although the grammar says `identifier', it really means
*************** cp_parser_class_head (cp_parser* parser,
*** 11474,11484 ****
        type = cp_parser_class_name (parser,
  				   /*typename_keyword_p=*/false,
  				   /*template_keyword_p=*/false,
  				   /*type_p=*/true,
  				   /*check_dependency_p=*/false,
! 				   /*class_head_p=*/true);
        /* If that didn't work, ignore the nested-name-specifier.  */
        if (!cp_parser_parse_definitely (parser))
  	{
  	  invalid_nested_name_p = true;
  	  id = cp_parser_identifier (parser);
--- 11601,11612 ----
        type = cp_parser_class_name (parser,
  				   /*typename_keyword_p=*/false,
  				   /*template_keyword_p=*/false,
  				   /*type_p=*/true,
  				   /*check_dependency_p=*/false,
! 				   /*class_head_p=*/true,
! 				   /*is_declaration=*/false);
        /* If that didn't work, ignore the nested-name-specifier.  */
        if (!cp_parser_parse_definitely (parser))
  	{
  	  invalid_nested_name_p = true;
  	  id = cp_parser_identifier (parser);
*************** cp_parser_class_head (cp_parser* parser,
*** 11515,11525 ****
  	 an identifier, or nothing at all.  */
        cp_parser_parse_tentatively (parser);
        /* Check for a template-id.  */
        id = cp_parser_template_id (parser, 
  				  /*template_keyword_p=*/false,
! 				  /*check_dependency_p=*/true);
        /* If that didn't work, it could still be an identifier.  */
        if (!cp_parser_parse_definitely (parser))
  	{
  	  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
  	    id = cp_parser_identifier (parser);
--- 11643,11654 ----
  	 an identifier, or nothing at all.  */
        cp_parser_parse_tentatively (parser);
        /* Check for a template-id.  */
        id = cp_parser_template_id (parser, 
  				  /*template_keyword_p=*/false,
! 				  /*check_dependency_p=*/true,
! 				  /*is_declaration=*/true);
        /* If that didn't work, it could still be an identifier.  */
        if (!cp_parser_parse_definitely (parser))
  	{
  	  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
  	    id = cp_parser_identifier (parser);
*************** cp_parser_base_specifier (cp_parser* par
*** 12336,12346 ****
       is to pretend that we have seen the `typename' keyword at this
       point.  */ 
    cp_parser_nested_name_specifier_opt (parser,
  				       /*typename_keyword_p=*/true,
  				       /*check_dependency_p=*/true,
! 				       /*type_p=*/true);
    /* If the base class is given by a qualified name, assume that names
       we see are type names or templates, as appropriate.  */
    class_scope_p = (parser->scope && TYPE_P (parser->scope));
    template_p = class_scope_p && cp_parser_optional_template_keyword (parser);
    
--- 12465,12476 ----
       is to pretend that we have seen the `typename' keyword at this
       point.  */ 
    cp_parser_nested_name_specifier_opt (parser,
  				       /*typename_keyword_p=*/true,
  				       /*check_dependency_p=*/true,
! 				       /*type_p=*/true,
! 				       /*is_declaration=*/true);
    /* If the base class is given by a qualified name, assume that names
       we see are type names or templates, as appropriate.  */
    class_scope_p = (parser->scope && TYPE_P (parser->scope));
    template_p = class_scope_p && cp_parser_optional_template_keyword (parser);
    
*************** cp_parser_base_specifier (cp_parser* par
*** 12348,12358 ****
    type = cp_parser_class_name (parser, 
  			       class_scope_p,
  			       template_p,
  			       /*type_p=*/true,
  			       /*check_dependency_p=*/true,
! 			       /*class_head_p=*/false);
  
    if (type == error_mark_node)
      return error_mark_node;
  
    return finish_base_specifier (TREE_TYPE (type), access, virtual_p);
--- 12478,12489 ----
    type = cp_parser_class_name (parser, 
  			       class_scope_p,
  			       template_p,
  			       /*type_p=*/true,
  			       /*check_dependency_p=*/true,
! 			       /*class_head_p=*/false,
! 			       /*is_declaration=*/true);
  
    if (type == error_mark_node)
      return error_mark_node;
  
    return finish_base_specifier (TREE_TYPE (type), access, virtual_p);
*************** cp_parser_constructor_declarator_p (cp_p
*** 13439,13449 ****
    /* Look for the nested-name-specifier.  */
    nested_name_p 
      = (cp_parser_nested_name_specifier_opt (parser,
  					    /*typename_keyword_p=*/false,
  					    /*check_dependency_p=*/false,
! 					    /*type_p=*/false)
         != NULL_TREE);
    /* Outside of a class-specifier, there must be a
       nested-name-specifier.  */
    if (!nested_name_p && 
        (!at_class_scope_p () || !TYPE_BEING_DEFINED (current_class_type)
--- 13570,13581 ----
    /* Look for the nested-name-specifier.  */
    nested_name_p 
      = (cp_parser_nested_name_specifier_opt (parser,
  					    /*typename_keyword_p=*/false,
  					    /*check_dependency_p=*/false,
! 					    /*type_p=*/false,
! 					    /*is_declaration=*/false)
         != NULL_TREE);
    /* Outside of a class-specifier, there must be a
       nested-name-specifier.  */
    if (!nested_name_p && 
        (!at_class_scope_p () || !TYPE_BEING_DEFINED (current_class_type)
*************** cp_parser_constructor_declarator_p (cp_p
*** 13467,13477 ****
        type_decl = cp_parser_class_name (parser,
  					/*typename_keyword_p=*/false,
  					/*template_keyword_p=*/false,
  					/*type_p=*/false,
  					/*check_dependency_p=*/false,
! 					/*class_head_p=*/false);
        /* If there was no class-name, then this is not a constructor.  */
        constructor_p = !cp_parser_error_occurred (parser);
      }
  
    /* If we're still considering a constructor, we have to see a `(',
--- 13599,13610 ----
        type_decl = cp_parser_class_name (parser,
  					/*typename_keyword_p=*/false,
  					/*template_keyword_p=*/false,
  					/*type_p=*/false,
  					/*check_dependency_p=*/false,
! 					/*class_head_p=*/false,
! 					/*is_declaration=*/false);
        /* If there was no class-name, then this is not a constructor.  */
        constructor_p = !cp_parser_error_occurred (parser);
      }
  
    /* If we're still considering a constructor, we have to see a `(',
Index: testsuite/g++.dg/template/error4.C
===================================================================
RCS file: testsuite/g++.dg/template/error4.C
diff -N testsuite/g++.dg/template/error4.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/error4.C	1 Dec 2003 03:21:48 -0000
***************
*** 0 ****
--- 1,8 ----
+ template<class T> struct C1
+ {
+   template<class U> struct C2
+   { class Type { }; };
+ };
+ 
+ template<class T, class U>
+ void foo(typename C1<T>::C2<U>::Type *) { } // { dg-error "template" }
Index: testsuite/g++.dg/template/nested3.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/template/nested3.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 nested3.C
*** testsuite/g++.dg/template/nested3.C	24 Feb 2003 07:43:23 -0000	1.1
--- testsuite/g++.dg/template/nested3.C	1 Dec 2003 03:21:49 -0000
*************** class A {
*** 3,28 ****
    template <class S>
    class SubA {
      int _k;
    };
    T1 _t1;
!   T2 _t2;
  };
  
  template <class U>
! class B {
    class SubB1 {
!     B _i;
    };
  
    class SubB2 {
      int _j;
    };
    A<U,SubB1>::SubA<SubB2> _a; // { dg-error "" }
  };
  
  
  int main() {
!   B<char> objB;
  
    return 0;
  }
--- 3,28 ----
    template <class S>
    class SubA {
      int _k;
    };
    T1 _t1;
!   T2 _t2; // { dg-error "instantiated" }
  };
  
  template <class U>
! class B { // { dg-error "" }
    class SubB1 {
!     B _i; // { dg-error "" }
    };
  
    class SubB2 {
      int _j;
    };
    A<U,SubB1>::SubA<SubB2> _a; // { dg-error "" }
  };
  
  
  int main() {
!   B<char> objB; // { dg-error "instantiated" }
  
    return 0;
  }



More information about the Gcc-patches mailing list