diff mbox

C++ PATCH for c++/10200 (DR 141, template name lookup after ->)

Message ID 56BB57A8.3000407@redhat.com
State New
Headers show

Commit Message

Jason Merrill Feb. 10, 2016, 3:30 p.m. UTC
After . or ->, when we see a name followed by < we look for a template 
name, first in the scope of the object expression and then in the 
enclosing scope.  DR 141 clarified that when we look in the enclosing 
scope, we only consider class templates, since there's no way a 
non-member function template could be correct in that situation.

When I fixed that, I found that we were failing to do the lookup in the 
object scope in the case where that scope is the current instantiation, 
so I needed to fix that as well.

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

Comments

Markus Trippelsdorf Feb. 11, 2016, 6:20 a.m. UTC | #1
On 2016.02.10 at 10:30 -0500, Jason Merrill wrote:
> After . or ->, when we see a name followed by < we look for a template name,
> first in the scope of the object expression and then in the enclosing scope.
> DR 141 clarified that when we look in the enclosing scope, we only consider
> class templates, since there's no way a non-member function template could
> be correct in that situation.
> 
> When I fixed that, I found that we were failing to do the lookup in the
> object scope in the case where that scope is the current instantiation, so I
> needed to fix that as well.
> 
> Tested x86_64-pc-linux-gnu, applying to trunk.

This commit causes: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69753
diff mbox

Patch

commit b3a4e73d776023398007c3d41bf957cee1792683
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Feb 8 23:46:24 2016 -0500

    	PR c++/10200
    
    	* parser.c (cp_parser_lookup_name): When looking for a template
    	after . or ->, only consider class templates.
    	(cp_parser_postfix_dot_deref_expression): Handle the current
    	instantiation.  Remember a dependent object expression.
    	* typeck2.c (build_x_arrow): Handle the current instantiation.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 6f47edf..07d1821 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -7184,8 +7184,16 @@  cp_parser_postfix_dot_deref_expression (cp_parser *parser,
   if (token_type == CPP_DEREF)
     postfix_expression = build_x_arrow (location, postfix_expression,
 					tf_warning_or_error);
-  /* Check to see whether or not the expression is type-dependent.  */
-  dependent_p = type_dependent_expression_p (postfix_expression);
+  /* According to the standard, no expression should ever have
+     reference type.  Unfortunately, we do not currently match
+     the standard in this respect in that our internal representation
+     of an expression may have reference type even when the standard
+     says it does not.  Therefore, we have to manually obtain the
+     underlying type here.  */
+  scope = non_reference (TREE_TYPE (postfix_expression));
+  /* Check to see whether or not the expression is type-dependent and
+     not the current instantiation.  */
+  dependent_p = !scope || dependent_scope_p (scope);
   /* The identifier following the `->' or `.' is not qualified.  */
   parser->scope = NULL_TREE;
   parser->qualifying_scope = NULL_TREE;
@@ -7194,16 +7202,8 @@  cp_parser_postfix_dot_deref_expression (cp_parser *parser,
 
   /* Enter the scope corresponding to the type of the object
      given by the POSTFIX_EXPRESSION.  */
-  if (!dependent_p && TREE_TYPE (postfix_expression) != NULL_TREE)
+  if (!dependent_p)
     {
-      scope = TREE_TYPE (postfix_expression);
-      /* According to the standard, no expression should ever have
-	 reference type.  Unfortunately, we do not currently match
-	 the standard in this respect in that our internal representation
-	 of an expression may have reference type even when the standard
-	 says it does not.  Therefore, we have to manually obtain the
-	 underlying type here.  */
-      scope = non_reference (scope);
       /* The type of the POSTFIX_EXPRESSION must be complete.  */
       if (scope == unknown_type_node)
 	{
@@ -7215,7 +7215,10 @@  cp_parser_postfix_dot_deref_expression (cp_parser *parser,
 	 required to be of complete type for purposes of class member
 	 access (5.2.5) outside the member function body.  */
       else if (postfix_expression != current_class_ref
-	       && !(processing_template_decl && scope == current_class_type))
+	       && !(processing_template_decl
+		    && current_class_type
+		    && (same_type_ignoring_top_level_qualifiers_p
+			(scope, current_class_type))))
 	scope = complete_type_or_else (scope, NULL_TREE);
       /* Let the name lookup machinery know that we are processing a
 	 class member access expression.  */
@@ -7231,6 +7234,10 @@  cp_parser_postfix_dot_deref_expression (cp_parser *parser,
       if (scope == error_mark_node)
 	postfix_expression = error_mark_node;
     }
+  else
+    /* Tell cp_parser_lookup_name that there was an object, even though it's
+       type-dependent.  */
+    parser->context->object_type = unknown_type_node;
 
   /* Assume this expression is not a pseudo-destructor access.  */
   pseudo_destructor_p = false;
@@ -24720,10 +24727,15 @@  cp_parser_lookup_name (cp_parser *parser, tree name,
 	decl = NULL_TREE;
 
       if (!decl)
-	/* Look it up in the enclosing context.  */
-	decl = lookup_name_real (name, tag_type != none_type,
+	/* Look it up in the enclosing context.  DR 141: When looking for a
+	   template-name after -> or ., only consider class templates.  */
+	decl = lookup_name_real (name, tag_type != none_type || is_template,
 				 /*nonclass=*/0,
 				 /*block_p=*/true, is_namespace, 0);
+      if (object_type == unknown_type_node)
+	/* The object is type-dependent, so we can't look anything up; we used
+	   this to get the DR 141 behavior.  */
+	object_type = NULL_TREE;
       parser->object_scope = object_type;
       parser->qualifying_scope = NULL_TREE;
     }
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 2a76c96..54a432f 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1694,7 +1694,10 @@  build_x_arrow (location_t loc, tree expr, tsubst_flags_t complain)
 
   if (processing_template_decl)
     {
-      if (type_dependent_expression_p (expr))
+      if (type && TREE_CODE (type) == POINTER_TYPE
+	  && !dependent_scope_p (TREE_TYPE (type)))
+	/* Pointer to current instantiation, don't treat as dependent.  */;
+      else if (type_dependent_expression_p (expr))
 	return build_min_nt_loc (loc, ARROW_EXPR, expr);
       expr = build_non_dependent_expr (expr);
     }
diff --git a/gcc/testsuite/g++.dg/lookup/member2.C b/gcc/testsuite/g++.dg/lookup/member2.C
new file mode 100644
index 0000000..5478448
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/member2.C
@@ -0,0 +1,5 @@ 
+// PR c++/10200
+
+template<class Tp> inline void end(Tp) { }
+
+template <typename T> bool tnegative(const T& t) { return t.end < 0; }