This patch fixes the first testcase in 80891. That was a case af a using declaration and a using directive bringing in the same function during lookup. the template specialization machinery wasn't prepared for that, and reasonably thought neither instance was more specialized.

This patch teaches most_specialized_template to ignore duplicates.

However, I think my decision to permit lookup to return duplicates was wrong. It should try harder not to -- as (a) it appears to be more common than I'd guessed and (b) the cost of returning duplicates is high, as both go through the instantiation machinery when there are templates involved.

Now that using declarations are ordered wrt regular functions, we can do better than before -- and even if we couldn't we can do no worse.

I've committed this patch, to unbreak things, but I'm going to leave the defect open and fixup lookup shortly, along with turning this patch into an appropriate assert.

nathan
--
Nathan Sidwell
2017-05-29  Nathan Sidwell  <nat...@acm.org>

	PR c++/80891 (#1)
	* pt.c (most_specialized_instantiation): Cope with duplicate
	instantiations.

	PR c++/80891 (#1)
	* g++.dg/lookup/pr80891-1.C: New.

Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 248571)
+++ cp/pt.c	(working copy)
@@ -21728,31 +21728,32 @@ most_specialized_instantiation (tree tem
 
   champ = templates;
   for (fn = TREE_CHAIN (templates); fn; fn = TREE_CHAIN (fn))
-    {
-      int fate = more_specialized_inst (TREE_VALUE (champ), TREE_VALUE (fn));
-      if (fate == -1)
-	champ = fn;
-      else if (!fate)
-	{
-	  /* Equally specialized, move to next function.  If there
-	     is no next function, nothing's most specialized.  */
-	  fn = TREE_CHAIN (fn);
+    if (TREE_VALUE (champ) != TREE_VALUE (fn))
+      {
+	int fate = more_specialized_inst (TREE_VALUE (champ), TREE_VALUE (fn));
+	if (fate == -1)
 	  champ = fn;
-	  if (!fn)
-	    break;
-	}
-    }
+	else if (!fate)
+	  {
+	    /* Equally specialized, move to next function.  If there
+	       is no next function, nothing's most specialized.  */
+	    fn = TREE_CHAIN (fn);
+	    champ = fn;
+	    if (!fn)
+	      break;
+	  }
+      }
 
   if (champ)
     /* Now verify that champ is better than everything earlier in the
        instantiation list.  */
-    for (fn = templates; fn != champ; fn = TREE_CHAIN (fn)) {
-      if (more_specialized_inst (TREE_VALUE (champ), TREE_VALUE (fn)) != 1)
-      {
-        champ = NULL_TREE;
-        break;
-      }
-    }
+    for (fn = templates; fn != champ; fn = TREE_CHAIN (fn))
+      if (TREE_VALUE (champ) != TREE_VALUE (fn)
+	  && more_specialized_inst (TREE_VALUE (champ), TREE_VALUE (fn)) != 1)
+	{
+	  champ = NULL_TREE;
+	  break;
+	}
 
   processing_template_decl--;
 
Index: testsuite/g++.dg/lookup/pr80891-1.C
===================================================================
--- testsuite/g++.dg/lookup/pr80891-1.C	(revision 0)
+++ testsuite/g++.dg/lookup/pr80891-1.C	(working copy)
@@ -0,0 +1,19 @@
+// PR c++/80891 part 1
+// std::endl is found via two paths and most_specialized_instantiation
+// gets confused.
+
+namespace std {
+  struct A {
+    void operator<<(A(A));
+  };
+  template <typename _CharT, typename _Traits> _CharT endl(_Traits);
+  A a;
+}
+
+using std::endl;
+
+void chi_squared_sample_sized()
+{
+  using namespace std;
+  a << endl;
+}

Reply via email to