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]

PATCH RFA: Possible fix for PR c++/11987


Mark Mitchell <mark@codesourcery.com> writes:

> IIRC, it's specifically the situation where the typedef is nested in
> another class.  Now, it would sure be useful if I had the standardese to
> justify that, wouldn't it? :-)  I'll see if I can find it.

Thanks.  Here is an attempt to implement that.  It correctly gives an
error for the test case in PR c++/11987, and the patch adds that test
case as gcc/testsuite/g++.dg/typedef1.C.

This patch tweaks several places in the parser in a simple way.  It's
a brute force approach.  At the time we know that we have a function
definition, it's too late to tell whether things are OK.  So instead
we detect it along the way, which means that we have to pass the
information along through three data structures.

The basic data flow is:

1) In cp_parser_nested_name_specifier_opt, we detect the case where
   the scope uses a cross-class typedef.  We record it in a new field
   in the cp_parser struct.

2) When we create a new CPP_NESTED_NAME_SPECIFIER in
   cpp_parser_nested_name_specifier_opt, we copy the new cp_parser
   field into a new cp_token field.

3) When we pick apart the CPP_NESTED_NAME_SPECIFIER token in
   cp_parser_pre_parsed_nested_name_specifier, we copy the new
   cp_token field back into the new cp_parser field.

4) If we see the new parser field set when we are defining a function,
   we give an error.

This patch passes the g++ testsuite on i686-pc-linux-gnu.  I'm running
the libstdc++-v3 testsuite now, along with a bootstrap.  I'm sending
this patch in now because I am expecting comments suggesting changes.

Just in case there aren't any comments, OK for mainline if the testing
passes?

I don't see any reason to put this accepts-invalid patch into 3.4 or
4.0.

Ian


cp/ChangeLog:
2005-09-16  Ian Lance Taylor  <ian@airs.com>

	PR c++/11987
	* parser.c (struct cp_token): Add scope_external_typedef_p.
	(eof_token): Initialize new field.
	(make_id_declarator): Initialize scope_external_typedef_p.
	(struct cp_parser): Add scope_external_typedef_p.
	(cp_parser_nested_name_specifier_opt): Set parser's
	scope_external_typedef_p field if we find a typedef for a type
	defined in a different class.  When creating a
	CPP_NESTED_NAME_SPECIFIER, set scope_external_typedef_p.
	(cp_parser_pre_parsed_nested_name_specifier): Set parser's
	scope_external_typedef_p field from token.
	(cp_parser_init_declarator): Give an error on a function
	definition if scope_external_typedef_p is set in declarator.
	(cp_parser_direct_declarator): Set scope_external_typedef_p in new
	id declarator.
	(cp_parser_clear_scope): New static inline function.
	(cp_parser_diagnose_invalid_type_name): Save parser's
	scope_external_typedef_p field.
	(cp_parser_id_expression): Likewise.
	(cp_parser_nested_name_specifier_opt): Likewise.
	(cp_parser_class_or_namespace_name): Likewise
	(cp_parser_conversion_function_id): Likewise.
	(cp_parser_enclosed_template_argument_list): Likewise.
	(cp_parser_unqualified_id): Clear scope_external_typedef_p when we
	clear scope.
	(cp_parser_nested_name_specifier_opt): Call
	cp_parser_clear_scope.
	(cp_parser_nested_name_specifier): Likewise.
	(cp_parser_postfix_dot_deref_expression): Likewise.
	(cp_parser_elaborated_type_specifier): Likewise.
	(cp_parser_ptr_operator): Likewise.
	(cp_parser_member_declaration): Likewise.
	(cp_parser_base_clause): Likewise.
	(cp_parser_global_scope_opt): Likewise.
	(cp_parser_single_declaration): Likewise.
	(cp_parser_global_scope_opt): Clear scope_external_typedef_p.
	* cp-tree.h (struct cp_declarator): In u.id, change sfk to
	bitfield, and add scope_external_typedef_p bitfield.

testsuite/ChangeLog:
2005-09-16  Ian Lance Taylor  <ian@airs.com>

	PR c++/11987
	* g++.dg/lookup/typedef1.C: New test.


Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1164
diff -p -u -r1.1164 cp-tree.h
--- cp/cp-tree.h	12 Sep 2005 19:53:57 -0000	1.1164
+++ cp/cp-tree.h	17 Sep 2005 06:09:52 -0000
@@ -3608,7 +3608,10 @@ struct cp_declarator {
       tree unqualified_name;
       /* If this is the name of a function, what kind of special
 	 function (if any).  */
-      special_function_kind sfk;
+      ENUM_BITFIELD(special_function_kind) sfk : 8;
+      /* Whether qualifying_scope was defined using a typedef for a
+	 type defined in a different class.  */
+      unsigned scope_external_typedef_p : 1;
     } id;
     /* For functions.  */
     struct {
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.358
diff -p -u -r1.358 parser.c
--- cp/parser.c	13 Sep 2005 02:41:04 -0000	1.358
+++ cp/parser.c	17 Sep 2005 06:09:54 -0000
@@ -59,6 +59,8 @@ typedef struct cp_token GTY (())
   BOOL_BITFIELD in_system_header : 1;
   /* True if this token is from a context where it is implicitly extern "C" */
   BOOL_BITFIELD implicit_extern_c : 1;
+  /* Copy of scope_external_typedef_p for CPP_NESTED_NAME_SPECIFIER.  */
+  BOOL_BITFIELD scope_external_typedef_p : 1;
   /* The value associated with this token, if any.  */
   tree value;
   /* The location at which this token was found.  */
@@ -72,7 +74,7 @@ DEF_VEC_ALLOC_P (cp_token_position,heap)
 
 static const cp_token eof_token =
 {
-  CPP_EOF, RID_MAX, 0, 0, 0, NULL_TREE,
+  CPP_EOF, RID_MAX, 0, 0, 0, 0, NULL_TREE,
 #if USE_MAPPED_LOCATION
   0
 #else
@@ -843,6 +845,7 @@ make_id_declarator (tree qualifying_scop
   declarator->u.id.qualifying_scope = qualifying_scope;
   declarator->u.id.unqualified_name = unqualified_name;
   declarator->u.id.sfk = sfk_none;
+  declarator->u.id.scope_external_typedef_p = false;
 
   return declarator;
 }
@@ -1253,6 +1256,10 @@ typedef struct cp_parser GTY(())
      GNU extensions are not recognized.  */
   bool allow_gnu_extensions_p;
 
+  /* TRUE if the scope field was resolved using a typedef for a type
+     defined in a different class.  */
+  bool scope_external_typedef_p;
+
   /* TRUE if the `>' token should be interpreted as the greater-than
      operator.  FALSE if it is the end of a template-id or
      template-parameter-list.  */
@@ -1933,6 +1940,17 @@ cp_parser_simulate_error (cp_parser* par
   return false;
 }
 
+/* Clear the current parser scope.  */
+
+static inline void
+cp_parser_clear_scope (cp_parser* parser)
+{
+  parser->scope = NULL;
+  parser->scope_external_typedef_p = false;
+  parser->qualifying_scope = NULL;
+  parser->object_scope = NULL;
+}
+
 /* This function is called when a type is defined.  If type
    definitions are forbidden at this point, an error message is
    issued.  */
@@ -2037,11 +2055,15 @@ static void
 cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree scope, tree id)
 {
   tree decl, old_scope;
+  bool old_scope_external_typedef_p;
+
   /* Try to lookup the identifier.  */
   old_scope = parser->scope;
+  old_scope_external_typedef_p = parser->scope_external_typedef_p;
   parser->scope = scope;
   decl = cp_parser_lookup_name_simple (parser, id);
   parser->scope = old_scope;
+  parser->scope_external_typedef_p = old_scope_external_typedef_p;
   /* If the lookup found a template-name, it means that the user forgot
   to specify an argument list. Emit a useful error message.  */
   if (TREE_CODE (decl) == TEMPLATE_DECL)
@@ -3126,6 +3148,7 @@ cp_parser_id_expression (cp_parser *pars
   if (nested_name_specifier_p)
     {
       tree saved_scope;
+      bool saved_scope_external_typedef_p;
       tree saved_object_scope;
       tree saved_qualifying_scope;
       tree unqualified_id;
@@ -3138,6 +3161,7 @@ cp_parser_id_expression (cp_parser *pars
       /* Name lookup we do during the processing of the
 	 unqualified-id might obliterate SCOPE.  */
       saved_scope = parser->scope;
+      saved_scope_external_typedef_p = parser->scope_external_typedef_p;
       saved_object_scope = parser->object_scope;
       saved_qualifying_scope = parser->qualifying_scope;
       /* Process the final unqualified-id.  */
@@ -3146,6 +3170,7 @@ cp_parser_id_expression (cp_parser *pars
 						 declarator_p);
       /* Restore the SAVED_SCOPE for our caller.  */
       parser->scope = saved_scope;
+      parser->scope_external_typedef_p = saved_scope_external_typedef_p;
       parser->object_scope = saved_object_scope;
       parser->qualifying_scope = saved_qualifying_scope;
 
@@ -3380,6 +3405,7 @@ cp_parser_unqualified_id (cp_parser* par
 	if (!done)
 	  {
 	    parser->scope = NULL_TREE;
+	    parser->scope_external_typedef_p = false;
 	    parser->object_scope = NULL_TREE;
 	    parser->qualifying_scope = NULL_TREE;
 	    type_decl
@@ -3502,6 +3528,7 @@ cp_parser_nested_name_specifier_opt (cp_
     {
       tree new_scope;
       tree old_scope;
+      bool old_scope_external_typedef_p;
       tree saved_qualifying_scope;
       bool template_keyword_p;
 
@@ -3557,6 +3584,7 @@ cp_parser_nested_name_specifier_opt (cp_
       /* Save the old scope since the name lookup we are about to do
 	 might destroy it.  */
       old_scope = parser->scope;
+      old_scope_external_typedef_p = parser->scope_external_typedef_p;
       saved_qualifying_scope = parser->qualifying_scope;
       /* In a declarator-id like "X<T>::I::Y<T>" we must be able to
 	 look up names in "X<T>::I" in order to determine that "Y" is
@@ -3589,6 +3617,7 @@ cp_parser_nested_name_specifier_opt (cp_
 	     failed attempt at finding the last
 	     class-or-namespace-name.  */
 	  parser->scope = old_scope;
+	  parser->scope_external_typedef_p = old_scope_external_typedef_p;
 	  parser->qualifying_scope = saved_qualifying_scope;
 	  /* If the next token is an identifier, and the one after
 	     that is a `::', then any valid interpretation would have
@@ -3611,7 +3640,7 @@ cp_parser_nested_name_specifier_opt (cp_
 		    cp_parser_name_lookup_error
 		      (parser, token->value, decl,
 		       "is not a class or namespace");
-		  parser->scope = NULL_TREE;
+		  cp_parser_clear_scope (parser);
 		  error_p = true;
 		  /* Treat this as a successful nested-name-specifier
 		     due to:
@@ -3630,11 +3659,32 @@ cp_parser_nested_name_specifier_opt (cp_
 
       /* We've found one valid nested-name-specifier.  */
       success = true;
+
       /* Make sure we look in the right scope the next time through
 	 the loop.  */
-      parser->scope = (TREE_CODE (new_scope) == TYPE_DECL
-		       ? TREE_TYPE (new_scope)
-		       : new_scope);
+      if (TREE_CODE (new_scope) != TYPE_DECL)
+	parser->scope = new_scope;
+      else
+	{
+	  parser->scope = TREE_TYPE (new_scope);
+
+	  /* We want to prohibit the use of some typedefs for a
+	     function definition, so look for them here.  The case we
+	     want to prohibit is a typedef found within a class which
+	     names a type defined in a different class.  At this point
+	     we don't know if we are going to see a function
+	     definition, so just record the fact that we saw a
+	     typedef.  */
+	  if (!DECL_IMPLICIT_TYPEDEF_P (new_scope)
+	      && !DECL_ARTIFICIAL (new_scope)
+	      && TYPE_CONTEXT (parser->scope)
+	      && CLASS_TYPE_P (TYPE_CONTEXT (parser->scope))
+	      && DECL_CONTEXT (new_scope)
+	      && CLASS_TYPE_P (DECL_CONTEXT (new_scope))
+	      && TYPE_CONTEXT (parser->scope) != DECL_CONTEXT (new_scope))
+	    parser->scope_external_typedef_p = true;
+	}
+
       /* If it is a class scope, try to complete it; we are about to
 	 be looking up names inside the class.  */
       if (TYPE_P (parser->scope)
@@ -3663,6 +3713,7 @@ cp_parser_nested_name_specifier_opt (cp_
       token->type = CPP_NESTED_NAME_SPECIFIER;
       token->value = build_tree_list (access_check, parser->scope);
       TREE_TYPE (token->value) = parser->qualifying_scope;
+      token->scope_external_typedef_p = parser->scope_external_typedef_p;
       token->keyword = RID_MAX;
 
       /* Purge all subsequent tokens.  */
@@ -3697,7 +3748,7 @@ cp_parser_nested_name_specifier (cp_pars
   if (!scope)
     {
       cp_parser_error (parser, "expected nested-name-specifier");
-      parser->scope = NULL_TREE;
+      cp_parser_clear_scope (parser);
     }
 
   return scope;
@@ -3729,6 +3780,7 @@ cp_parser_class_or_namespace_name (cp_pa
 				   bool is_declaration)
 {
   tree saved_scope;
+  bool saved_scope_external_typedef_p;
   tree saved_qualifying_scope;
   tree saved_object_scope;
   tree scope;
@@ -3738,6 +3790,7 @@ cp_parser_class_or_namespace_name (cp_pa
      current PARSER->SCOPE since cp_parser_class_name will destroy
      it.  */
   saved_scope = parser->scope;
+  saved_scope_external_typedef_p = parser->scope_external_typedef_p;
   saved_qualifying_scope = parser->qualifying_scope;
   saved_object_scope = parser->object_scope;
   /* Try for a class-name first.  If the SAVED_SCOPE is a type, then
@@ -3757,6 +3810,7 @@ cp_parser_class_or_namespace_name (cp_pa
     {
       /* Restore the saved scope.  */
       parser->scope = saved_scope;
+      parser->scope_external_typedef_p = saved_scope_external_typedef_p;
       parser->qualifying_scope = saved_qualifying_scope;
       parser->object_scope = saved_object_scope;
       /* If we are not looking at an identifier followed by the scope
@@ -4400,9 +4454,7 @@ cp_parser_postfix_dot_deref_expression (
   /* Check to see whether or not the expression is type-dependent.  */
   dependent_p = type_dependent_expression_p (postfix_expression);
   /* The identifier following the `->' or `.' is not qualified.  */
-  parser->scope = NULL_TREE;
-  parser->qualifying_scope = NULL_TREE;
-  parser->object_scope = NULL_TREE;
+  cp_parser_clear_scope (parser);
   *idk = CP_ID_KIND_NONE;
   /* Enter the scope corresponding to the type of the object
      given by the POSTFIX_EXPRESSION.  */
@@ -4494,9 +4546,7 @@ cp_parser_postfix_dot_deref_expression (
 	  if (name != error_mark_node && !BASELINK_P (name) && parser->scope)
 	    {
 	      name = build_nt (SCOPE_REF, parser->scope, name);
-	      parser->scope = NULL_TREE;
-	      parser->qualifying_scope = NULL_TREE;
-	      parser->object_scope = NULL_TREE;
+	      cp_parser_clear_scope (parser);
 	    }
 	  if (scope && name && BASELINK_P (name))
 	    adjust_result_of_qualified_name_lookup
@@ -7624,6 +7674,7 @@ cp_parser_conversion_function_id (cp_par
 {
   tree type;
   tree saved_scope;
+  bool saved_scope_external_typedef_p;
   tree saved_qualifying_scope;
   tree saved_object_scope;
   tree pushed_scope = NULL_TREE;
@@ -7635,6 +7686,7 @@ cp_parser_conversion_function_id (cp_par
      reset.  However, we need that information in able to look up the
      conversion function later, so we save it here.  */
   saved_scope = parser->scope;
+  saved_scope_external_typedef_p = parser->scope_external_typedef_p;
   saved_qualifying_scope = parser->qualifying_scope;
   saved_object_scope = parser->object_scope;
   /* We must enter the scope of the class so that the names of
@@ -7659,6 +7711,7 @@ cp_parser_conversion_function_id (cp_par
     pop_scope (pushed_scope);
   /* Restore the saved scope.  */
   parser->scope = saved_scope;
+  parser->scope_external_typedef_p = saved_scope_external_typedef_p;
   parser->qualifying_scope = saved_qualifying_scope;
   parser->object_scope = saved_object_scope;
   /* If the TYPE is invalid, indicate failure.  */
@@ -9937,7 +9990,7 @@ cp_parser_elaborated_type_specifier (cp_
 
       if (identifier == error_mark_node)
 	{
-	  parser->scope = NULL_TREE;
+	  cp_parser_clear_scope (parser);
 	  return error_mark_node;
 	}
 
@@ -10770,12 +10823,24 @@ cp_parser_init_declarator (cp_parser* pa
 	}
       else
 	{
+	  cp_declarator *pd;
+
 	  /* Neither attributes nor an asm-specification are allowed
 	     on a function-definition.  */
 	  if (asm_specification)
 	    error ("an asm-specification is not allowed on a function-definition");
 	  if (attributes)
 	    error ("attributes are not allowed on a function-definition");
+
+	  /* A function definition must be written using the real
+	     name, so if we used a typedef to get here something has
+	     gone wrong.  */
+	  pd = declarator;
+	  while (pd && pd->kind != cdk_id)
+	    pd = pd->declarator;
+	  if (pd && pd->u.id.scope_external_typedef_p)
+	    error ("invalid typedef used in function name");
+
 	  /* This is a function-definition.  */
 	  *function_definition_p = true;
 
@@ -11370,6 +11435,8 @@ cp_parser_direct_declarator (cp_parser* 
 
 	  declarator = make_id_declarator (qualifying_scope,
 					   unqualified_name);
+	  declarator->u.id.scope_external_typedef_p =
+	    parser->scope_external_typedef_p;
 	  declarator->id_loc = token->location;
 	  if (unqualified_name)
 	    {
@@ -11525,9 +11592,7 @@ cp_parser_ptr_operator (cp_parser* parse
 	     current SCOPE.  */
 	  *type = parser->scope;
 	  /* The next name will not be qualified.  */
-	  parser->scope = NULL_TREE;
-	  parser->qualifying_scope = NULL_TREE;
-	  parser->object_scope = NULL_TREE;
+	  cp_parser_clear_scope (parser);
 	  /* Indicate that the `*' operator was used.  */
 	  code = INDIRECT_REF;
 	  /* Look for the optional cv-qualifier-seq.  */
@@ -13525,9 +13590,7 @@ cp_parser_member_declaration (cp_parser*
 
 	  /* If there is any qualification still in effect, clear it
 	     now; we will be starting fresh with the next declarator.  */
-	  parser->scope = NULL_TREE;
-	  parser->qualifying_scope = NULL_TREE;
-	  parser->object_scope = NULL_TREE;
+	  cp_parser_clear_scope (parser);
 	  /* If it's a `,', then there are more declarators.  */
 	  if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
 	    cp_lexer_consume_token (parser->lexer);
@@ -13679,9 +13742,7 @@ cp_parser_base_clause (cp_parser* parser
   /* PARSER->SCOPE may still be non-NULL at this point, if the last
      base class had a qualified name.  However, the next name that
      appears is certainly not qualified.  */
-  parser->scope = NULL_TREE;
-  parser->qualifying_scope = NULL_TREE;
-  parser->object_scope = NULL_TREE;
+  cp_parser_clear_scope (parser);
 
   return nreverse (bases);
 }
@@ -14834,17 +14895,14 @@ cp_parser_global_scope_opt (cp_parser* p
       cp_lexer_consume_token (parser->lexer);
       /* Set the SCOPE so that we know where to start the lookup.  */
       parser->scope = global_namespace;
+      parser->scope_external_typedef_p = false;
       parser->qualifying_scope = global_namespace;
       parser->object_scope = NULL_TREE;
 
       return parser->scope;
     }
   else if (!current_scope_valid_p)
-    {
-      parser->scope = NULL_TREE;
-      parser->qualifying_scope = NULL_TREE;
-      parser->object_scope = NULL_TREE;
-    }
+    cp_parser_clear_scope (parser);
 
   return NULL_TREE;
 }
@@ -15291,9 +15349,7 @@ cp_parser_single_declaration (cp_parser*
 
   /* Clear any current qualification; whatever comes next is the start
      of something new.  */
-  parser->scope = NULL_TREE;
-  parser->qualifying_scope = NULL_TREE;
-  parser->object_scope = NULL_TREE;
+  cp_parser_clear_scope (parser);
   /* Look for a trailing `;' after the declaration.  */
   if (!function_definition_p
       && (decl == error_mark_node
@@ -15408,6 +15464,7 @@ cp_parser_enclosed_template_argument_lis
 {
   tree arguments;
   tree saved_scope;
+  bool saved_scope_external_typedef_p;
   tree saved_qualifying_scope;
   tree saved_object_scope;
   bool saved_greater_than_is_operator_p;
@@ -15423,6 +15480,7 @@ cp_parser_enclosed_template_argument_lis
   /* Parsing the argument list may modify SCOPE, so we save it
      here.  */
   saved_scope = parser->scope;
+  saved_scope_external_typedef_p = parser->scope_external_typedef_p;
   saved_qualifying_scope = parser->qualifying_scope;
   saved_object_scope = parser->object_scope;
   /* Parse the template-argument-list itself.  */
@@ -15472,6 +15530,7 @@ cp_parser_enclosed_template_argument_lis
     = saved_greater_than_is_operator_p;
   /* Restore the SAVED_SCOPE.  */
   parser->scope = saved_scope;
+  parser->scope_external_typedef_p = saved_scope_external_typedef_p;
   parser->qualifying_scope = saved_qualifying_scope;
   parser->object_scope = saved_object_scope;
 
@@ -16077,16 +16136,19 @@ cp_parser_optional_template_keyword (cp_
 static void
 cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser)
 {
+  cp_token *token;
   tree value;
   tree check;
 
   /* Get the stored value.  */
-  value = cp_lexer_consume_token (parser->lexer)->value;
+  token = cp_lexer_consume_token (parser->lexer);
+  value = token->value;
   /* Perform any access checks that were deferred.  */
   for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
     perform_or_defer_access_check (TREE_PURPOSE (check), TREE_VALUE (check));
   /* Set the scope from the stored value.  */
   parser->scope = TREE_VALUE (value);
+  parser->scope_external_typedef_p = token->scope_external_typedef_p;
   parser->qualifying_scope = TREE_TYPE (value);
   parser->object_scope = NULL_TREE;
 }
Index: testsuite/g++.dg/lookup/typedef1.C
===================================================================
RCS file: testsuite/g++.dg/lookup/typedef1.C
diff -N testsuite/g++.dg/lookup/typedef1.C
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/g++.dg/lookup/typedef1.C	17 Sep 2005 06:10:04 -0000
@@ -0,0 +1,15 @@
+// PR 11987
+// { dg-do compile }
+
+template <int dim> struct X { 
+    struct I { I(); }; 
+}; 
+ 
+template <int dim> struct Y : X<dim> { 
+    typedef typename X<dim>::I I; 
+}; 
+ 
+template <int dim> 
+Y<dim>::I::I () {}  // { dg-error "invalid typedef" }
+ 
+template struct Y<1>;


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