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 for c++/9634, 29469, 29607 [DR 224]


This patch implements the intent of DR 224: if we're looking up a qualified name in the context of a currently open class ("the current instantiation"), we do the lookup, and the name is only dependent if that lookup fails. I understand the problems that Gaby had with the wording of the DR, but the intent is clear.

Tested x86_64-pc-linux-gnu, applied to trunk.

2009-03-04  Jason Merrill  <jason@redhat.com>

	PR c++/9634
	PR c++/29469
	PR c++/29607
	* decl.c (make_typename_type): Do look inside currently open classes.
	* parser.c (cp_parser_lookup_name): Likewise.
	(cp_parser_template_name): Likewise.
	* pt.c (dependent_scope_p): New function.
	* cp-tree.h: Declare it.
	* class.c (currently_open_class): Return fast if T isn't a class.

Index: cp/class.c
===================================================================
*** cp/class.c	(revision 144538)
--- cp/class.c	(working copy)
*************** currently_open_class (tree t)
*** 5787,5792 ****
--- 5787,5795 ----
  {
    int i;
  
+   if (!CLASS_TYPE_P (t))
+     return false;
+ 
    /* We start looking from 1 because entry 0 is from global scope,
       and has no type.  */
    for (i = current_class_depth; i > 0; --i)
Index: cp/decl.c
===================================================================
*** cp/decl.c	(revision 144538)
--- cp/decl.c	(working copy)
*************** make_typename_type (tree context, tree n
*** 2977,2988 ****
    gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
    gcc_assert (TYPE_P (context));
  
-   /* When the CONTEXT is a dependent type,  NAME could refer to a
-      dependent base class of CONTEXT.  So we cannot peek inside it,
-      even if CONTEXT is a currently open scope.  */
-   if (dependent_type_p (context))
-     return build_typename_type (context, name, fullname, tag_type);
- 
    if (!MAYBE_CLASS_TYPE_P (context))
      {
        if (complain & tf_error)
--- 2977,2982 ----
*************** make_typename_type (tree context, tree n
*** 2990,3000 ****
        return error_mark_node;
      }
    
    want_template = TREE_CODE (fullname) == TEMPLATE_ID_EXPR;
    
-   /* We should only set WANT_TYPE when we're a nested typename type.
-      Then we can give better diagnostics if we find a non-type.  */
-   t = lookup_field (context, name, 0, /*want_type=*/true);
    if (!t)
      {
        if (complain & tf_error)
--- 2984,3006 ----
        return error_mark_node;
      }
    
+   /* When the CONTEXT is a dependent type,  NAME could refer to a
+      dependent base class of CONTEXT.  But look inside it anyway
+      if CONTEXT is a currently open scope, in case it refers to a
+      member of the current instantiation or a non-dependent base;
+      lookup will stop when we hit a dependent base.  */
+   if (!dependent_scope_p (context))
+     /* We should only set WANT_TYPE when we're a nested typename type.
+        Then we can give better diagnostics if we find a non-type.  */
+     t = lookup_field (context, name, 0, /*want_type=*/true);
+   else
+     t = NULL_TREE;
+ 
+   if (!t && dependent_type_p (context)) 
+     return build_typename_type (context, name, fullname, tag_type);
+ 
    want_template = TREE_CODE (fullname) == TEMPLATE_ID_EXPR;
    
    if (!t)
      {
        if (complain & tf_error)
Index: cp/pt.c
===================================================================
*** cp/pt.c	(revision 144538)
--- cp/pt.c	(working copy)
*************** dependent_type_p (tree type)
*** 16067,16072 ****
--- 16067,16082 ----
    return TYPE_DEPENDENT_P (type);
  }
  
+ /* Returns TRUE if SCOPE is a dependent scope, in which we can't do any
+    lookup.  In other words, a dependent type that is not the current
+    instantiation.  */
+ 
+ bool
+ dependent_scope_p (tree scope)
+ {
+   return dependent_type_p (scope) && !currently_open_class (scope);
+ }
+ 
  /* Returns TRUE if EXPRESSION is dependent, according to CRITERION.  */
  
  static bool
*************** dependent_scope_ref_p (tree expression, 
*** 16088,16094 ****
       An id-expression is type-dependent if it contains a
       nested-name-specifier that contains a class-name that names a
       dependent type.  */
!   /* The suggested resolution to Core Issue 2 implies that if the
       qualifying type is the current class, then we must peek
       inside it.  */
    if (DECL_P (name)
--- 16098,16104 ----
       An id-expression is type-dependent if it contains a
       nested-name-specifier that contains a class-name that names a
       dependent type.  */
!   /* The suggested resolution to Core Issue 224 implies that if the
       qualifying type is the current class, then we must peek
       inside it.  */
    if (DECL_P (name)
Index: cp/parser.c
===================================================================
*** cp/parser.c	(revision 144538)
--- cp/parser.c	(working copy)
*************** cp_parser_template_name (cp_parser* pars
*** 10323,10329 ****
  	  && !template_keyword_p
  	  && parser->scope && TYPE_P (parser->scope)
  	  && check_dependency_p
! 	  && dependent_type_p (parser->scope)
  	  /* Do not do this for dtors (or ctors), since they never
  	     need the template keyword before their name.  */
  	  && !constructor_name_p (identifier, parser->scope))
--- 10323,10329 ----
  	  && !template_keyword_p
  	  && parser->scope && TYPE_P (parser->scope)
  	  && check_dependency_p
! 	  && dependent_scope_p (parser->scope)
  	  /* Do not do this for dtors (or ctors), since they never
  	     need the template keyword before their name.  */
  	  && !constructor_name_p (identifier, parser->scope))
*************** cp_parser_lookup_name (cp_parser *parser
*** 17023,17057 ****
  	 cannot look up the name if the scope is not a class type; it
  	 might, for example, be a template type parameter.  */
        dependent_p = (TYPE_P (parser->scope)
! 		     && !(parser->in_declarator_p
! 			  && currently_open_class (parser->scope))
! 		     && dependent_type_p (parser->scope));
        if ((check_dependency || !CLASS_TYPE_P (parser->scope))
! 	   && dependent_p)
! 	{
! 	  if (tag_type)
! 	    {
! 	      tree type;
! 
! 	      /* The resolution to Core Issue 180 says that `struct
! 		 A::B' should be considered a type-name, even if `A'
! 		 is dependent.  */
! 	      type = make_typename_type (parser->scope, name, tag_type,
! 					 /*complain=*/tf_error);
! 	      decl = TYPE_NAME (type);
! 	    }
! 	  else if (is_template
! 		   && (cp_parser_next_token_ends_template_argument_p (parser)
! 		       || cp_lexer_next_token_is (parser->lexer,
! 						  CPP_CLOSE_PAREN)))
! 	    decl = make_unbound_class_template (parser->scope,
! 						name, NULL_TREE,
! 						/*complain=*/tf_error);
! 	  else
! 	    decl = build_qualified_name (/*type=*/NULL_TREE,
! 					 parser->scope, name,
! 					 is_template);
! 	}
        else
  	{
  	  tree pushed_scope = NULL_TREE;
--- 17023,17033 ----
  	 cannot look up the name if the scope is not a class type; it
  	 might, for example, be a template type parameter.  */
        dependent_p = (TYPE_P (parser->scope)
! 		     && dependent_scope_p (parser->scope));
        if ((check_dependency || !CLASS_TYPE_P (parser->scope))
! 	  && dependent_p)
! 	/* Defer lookup.  */
! 	decl = error_mark_node;
        else
  	{
  	  tree pushed_scope = NULL_TREE;
*************** cp_parser_lookup_name (cp_parser *parser
*** 17072,17085 ****
  					/*complain=*/true);
  
  	  /* If we have a single function from a using decl, pull it out.  */
! 	  if (decl
! 	      && TREE_CODE (decl) == OVERLOAD
  	      && !really_overloaded_fn (decl))
  	    decl = OVL_FUNCTION (decl);
  
  	  if (pushed_scope)
  	    pop_scope (pushed_scope);
  	}
        parser->qualifying_scope = parser->scope;
        parser->object_scope = NULL_TREE;
      }
--- 17048,17089 ----
  					/*complain=*/true);
  
  	  /* If we have a single function from a using decl, pull it out.  */
! 	  if (TREE_CODE (decl) == OVERLOAD
  	      && !really_overloaded_fn (decl))
  	    decl = OVL_FUNCTION (decl);
  
  	  if (pushed_scope)
  	    pop_scope (pushed_scope);
  	}
+ 
+       /* If the scope is a dependent type and either we deferred lookup or
+ 	 we did lookup but didn't find the name, rememeber the name.  */
+       if (decl == error_mark_node && TYPE_P (parser->scope)
+ 	  && dependent_type_p (parser->scope))
+ 	{
+ 	  if (tag_type)
+ 	    {
+ 	      tree type;
+ 
+ 	      /* The resolution to Core Issue 180 says that `struct
+ 		 A::B' should be considered a type-name, even if `A'
+ 		 is dependent.  */
+ 	      type = make_typename_type (parser->scope, name, tag_type,
+ 					 /*complain=*/tf_error);
+ 	      decl = TYPE_NAME (type);
+ 	    }
+ 	  else if (is_template
+ 		   && (cp_parser_next_token_ends_template_argument_p (parser)
+ 		       || cp_lexer_next_token_is (parser->lexer,
+ 						  CPP_CLOSE_PAREN)))
+ 	    decl = make_unbound_class_template (parser->scope,
+ 						name, NULL_TREE,
+ 						/*complain=*/tf_error);
+ 	  else
+ 	    decl = build_qualified_name (/*type=*/NULL_TREE,
+ 					 parser->scope, name,
+ 					 is_template);
+ 	}
        parser->qualifying_scope = parser->scope;
        parser->object_scope = NULL_TREE;
      }
Index: cp/cp-tree.h
===================================================================
*** cp/cp-tree.h	(revision 144538)
--- cp/cp-tree.h	(working copy)
*************** extern struct tinst_level *current_insta
*** 4594,4599 ****
--- 4594,4600 ----
  extern tree maybe_get_template_decl_from_type_decl (tree);
  extern int processing_template_parmlist;
  extern bool dependent_type_p			(tree);
+ extern bool dependent_scope_p			(tree);
  extern bool any_dependent_template_arguments_p  (const_tree);
  extern bool dependent_template_p		(tree);
  extern bool dependent_template_id_p		(tree, tree);
Index: testsuite/g++.dg/template/dependent-name5.C
===================================================================
*** testsuite/g++.dg/template/dependent-name5.C	(revision 0)
--- testsuite/g++.dg/template/dependent-name5.C	(revision 0)
***************
*** 0 ****
--- 1,45 ----
+ // PR c++/9634, c++/29469, c++/29607
+ // Contributed by: Giovanni Bajo <giovannibajo at gcc dot gnu dot org>
+ // DR224: Make sure that a name is *truly* semantically dependent.
+ 
+ struct D {
+   typedef int K;
+ };
+ 
+ template <typename T>
+ struct A
+ {
+   typedef int Bar;
+ 
+   template <typename>
+   struct N {};
+ 
+   typedef Bar          type1;
+   typedef A::Bar       type2;
+   typedef A<T>::Bar    type3;
+   typedef A<T*>::Bar    type4;  // { dg-error "" }
+   typedef typename A<T*>::Bar type5;
+ 
+   typedef N<int>       type6;
+   typedef A::N<int>    type7;
+   typedef A<T>::N<int> type8;
+   typedef A<T*>::template N<int> type9;  // { dg-error "" }
+   typedef typename A<T*>::template N<int> type10;
+ 
+   typedef D Bar2;
+   struct N2 { typedef int K; };
+ 
+   // Check that A::N2 is still considered dependent (because it
+   //  could be specialized), while A::Bar2 (being just ::D) is not.
+   typedef A::Bar2 type11;
+   typedef type11::K k3;
+ 
+   typedef A::N2 type12;
+   typedef typename type12::K k2;
+   typedef type12::K k1;  // { dg-error "" }
+ 
+   // Check that A::Bar2 is not considered dependent even if we use
+   // the typename keyword.
+   typedef typename A::Bar2 type13;
+   typedef type13::K k4;
+ };

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