diff mbox series

[PR,c++/87531] Fix second bug

Message ID c38ce57f-821d-a6d2-6f93-716cd5bac4cc@acm.org
State New
Headers show
Series [PR,c++/87531] Fix second bug | expand

Commit Message

Nathan Sidwell Dec. 13, 2018, 2:11 p.m. UTC
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.
diff mbox series

Patch

2018-12-13  Nathan Sidwell  <nathan@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 ();
+}
+