This patch addresses the regression caused by the first fix. For reasons that used to make more sense, an overload set of template members would present as just a dependent using-decl, if it contained any such using decls. Then we'd defer repeat lookup to instantiation time. Except in a couple of places where we'd really want the non-dependent function set.

However, we're now better at doing lookups correctly in more places, and this deferring gets in the way. In this particular case, we need to know if
   name < whatever >
is a template-id-expr, or a less-than operator[*], and we determine this by seeing if any members of whatever 'name' found are templates. This breaks if we just present a dependent using decl.

So, this patch removes the frobbing in name lookup and returns the whole binding. We'll have arranged that if there is at least one dependent using decl, it'll be first in the overload set.

Then we need to deal with that as an overload member in a couple of places. The finish_id_expr change is so we properly insert an implicit 'this->' before hand. That showed I'd neglected to set the using-decl's DECL_CONTEXT, hence the change in finish_struct.

get_class_binding_direct's fn_or_type arg can now return to be a bool 'want_type', as we no longer call it with the 'want_fns's' value. That's a cleanup for stage 1. (The only other place we asked for fns is getting the dtor, which cannot be a dependent using decl anyway, so the request is moot.)

Booted & tested in x86_64-linux, applying to trunk and gcc-8.

nathan

[*] there's a core or evolution paper about interpreting '<' as a template-id-expr in more places regardless of the binding of the single identifer on its left.

--
Nathan Sidwell
2018-12-13  Nathan Sidwell  <nat...@acm.org>

	PR c++/87531
	* class.c (finish_struct): Set DECL_CONTEXT of template assign op.
	* name-lookup.c (get_class_binding_direct): Don't strip using-decl
	of overload here.
	* parser.c (cp_parser_postfix_expression): Cope with using decl in
	overload set.
	* semantics.c (finish_id_expr): Likewise.

	* g++.dg/lookup/pr87531-2.C: New.

Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(revision 267093)
+++ gcc/cp/class.c	(working copy)
@@ -7158,6 +7158,7 @@ finish_struct (tree t, tree attributes)
 	 time.  */
       tree ass_op = build_lang_decl (USING_DECL, assign_op_identifier,
 				     NULL_TREE);
+      DECL_CONTEXT (ass_op) = t;
       USING_DECL_SCOPE (ass_op) = t;
       DECL_DEPENDENT_P (ass_op) = true;
       DECL_ARTIFICIAL (ass_op) = true;
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	(revision 267093)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -1242,17 +1242,6 @@ get_class_binding_direct (tree klass, tr
 	}
       else if (STAT_HACK_P (val))
 	val = STAT_DECL (val);
-
-      if (val && TREE_CODE (val) == OVERLOAD
-	  && TREE_CODE (OVL_FUNCTION (val)) == USING_DECL)
-	{
-	  /* An overload with a dependent USING_DECL.  Does the caller
-	     want the USING_DECL or the functions?  */
-	  if (type_or_fns < 0)
-	    val = OVL_CHAIN (val);
-	  else
-	    val = OVL_FUNCTION (val);  
-	}
     }
   else
     {
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 267093)
+++ gcc/cp/parser.c	(working copy)
@@ -7240,14 +7240,19 @@ cp_parser_postfix_expression (cp_parser
 		else if (!args->is_empty ()
 			 && is_overloaded_fn (postfix_expression))
 		  {
+		    /* We only need to look at the first function,
+		       because all the fns share the attribute we're
+		       concerned with (all member fns or all local
+		       fns).  */
 		    tree fn = get_first_fn (postfix_expression);
 		    fn = STRIP_TEMPLATE (fn);
 
 		    /* Do not do argument dependent lookup if regular
 		       lookup finds a member function or a block-scope
 		       function declaration.  [basic.lookup.argdep]/3  */
-		    if (!DECL_FUNCTION_MEMBER_P (fn)
-			&& !DECL_LOCAL_FUNCTION_P (fn))
+		    if (!((TREE_CODE (fn) == USING_DECL && DECL_DEPENDENT_P (fn))
+			  || DECL_FUNCTION_MEMBER_P (fn)
+			  || DECL_LOCAL_FUNCTION_P (fn)))
 		      {
 			koenig_p = true;
 			if (!any_type_dependent_arguments_p (args))
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 267093)
+++ gcc/cp/semantics.c	(working copy)
@@ -3805,9 +3805,10 @@ finish_id_expression (tree id_expression
 	    return error_mark_node;
 
 	  if (!template_arg_p
-	      && TREE_CODE (first_fn) == FUNCTION_DECL
-	      && DECL_FUNCTION_MEMBER_P (first_fn)
-	      && !shared_member_p (decl))
+	      && (TREE_CODE (first_fn) == USING_DECL
+		  || (TREE_CODE (first_fn) == FUNCTION_DECL
+		      && DECL_FUNCTION_MEMBER_P (first_fn)
+		      && !shared_member_p (decl))))
 	    {
 	      /* A set of member functions.  */
 	      decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
Index: gcc/testsuite/g++.dg/lookup/pr87531-2.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/pr87531-2.C	(revision 0)
+++ gcc/testsuite/g++.dg/lookup/pr87531-2.C	(working copy)
@@ -0,0 +1,63 @@
+// PR 87531 part 2.  dependent using decls + template decls.
+
+template<typename T>
+struct One
+{
+  One& operator=(T* p_)
+  {
+    return operator=<T>(p_); // Parse failed here
+  }
+
+  template<typename U>
+  One& operator=(U* p_);
+  
+};
+
+
+template<typename T>
+struct Two : T
+{
+  using T::f;
+  template<typename U> void f ();
+
+  using T::operator T*;
+  operator T * () const;
+  
+  int frob ()
+  {
+    return f<int> (1);
+  }
+
+  T *quux ()
+  {
+    return operator T * ();
+  }
+
+  T *quux () const
+  {
+    return operator T * ();
+  }
+};
+
+struct Base 
+{
+  template <typename T> int f (T i) 
+  {
+    return i;
+  }
+
+  operator Base *() const;
+};
+
+void foo ()
+{
+  One<int> one;
+  Two<Base> two;
+
+  one = One<int> ();
+
+  two.frob ();
+  two.quux ();
+  const_cast <const Two<Base> &> (two).quux ();
+}
+

Reply via email to