erichkeane updated this revision to Diff 279598.
erichkeane added a comment.

Also make sure to update the the cxx_dr_status.html document.

Additionally, I sent out a CWG message on the reflector about this: 
https://godbolt.org/z/bEr61T

My implementation has this as ambiguous, but the wording makes it well-formed I 
think.  I don't think that was the intent of CWG2303, so unless they confirm  
that this was their intent (or that I'm wrong), I'll leave this patch as is.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84048/new/

https://reviews.llvm.org/D84048

Files:
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/test/CXX/drs/dr23xx.cpp
  clang/www/cxx_dr_status.html

Index: clang/www/cxx_dr_status.html
===================================================================
--- clang/www/cxx_dr_status.html
+++ clang/www/cxx_dr_status.html
@@ -13633,7 +13633,7 @@
     <td><a href="https://wg21.link/cwg2303";>2303</a></td>
     <td>DRWP</td>
     <td>Partial ordering and recursive variadic inheritance</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="full" align="center">Yes</td>
   </tr>
   <tr id="2304">
     <td><a href="https://wg21.link/cwg2304";>2304</a></td>
Index: clang/test/CXX/drs/dr23xx.cpp
===================================================================
--- clang/test/CXX/drs/dr23xx.cpp
+++ clang/test/CXX/drs/dr23xx.cpp
@@ -113,3 +113,26 @@
   extern template const int d<const int>;
 #endif
 }
+
+#if __cplusplus >= 201103L
+namespace dr2303 {
+template <typename... T>
+struct A;
+template <>
+struct A<> {};
+template <typename T, typename... Ts>
+struct A<T, Ts...> : A<Ts...> {};
+struct B : A<int> {};
+
+template <typename... T>
+void f(const A<T...> &);
+template <typename... T>
+void f2(const A<T...> *);
+
+void g() {
+  f(B{}); // This is no longer ambiguous.
+  B b;
+  f2(&b);
+}
+} //namespace dr2303
+#endif
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -1792,7 +1792,10 @@
       //   transformed A can be a derived class of the deduced A. Likewise if
       //   P is a pointer to a class of the form simple-template-id, the
       //   transformed A can be a pointer to a derived class pointed to by the
-      //   deduced A.
+      //   deduced A. However, if there is a class C that is a (direct or
+      //   indirect) base class of D and derived (directly or indirectly) from a
+      //   class B and that would be a valid deduced A, the deduced A cannot be
+      //   B or pointer to B, respectively.
       //
       //   These alternatives are considered only if type deduction would
       //   otherwise fail. If they yield more than one possible deduced A, the
@@ -1812,6 +1815,7 @@
       while (!ToVisit.empty()) {
         // Retrieve the next class in the inheritance hierarchy.
         const RecordType *NextT = ToVisit.pop_back_val();
+        bool SkipBases = false;
 
         // If we have already seen this type, skip it.
         if (!Visited.insert(NextT).second)
@@ -1840,17 +1844,28 @@
             Info.Param = BaseInfo.Param;
             Info.FirstArg = BaseInfo.FirstArg;
             Info.SecondArg = BaseInfo.SecondArg;
+
+            // In order to implement CWG2303 (added the following to p4b3):
+            //   However, if there is a class C that is a (direct or indirect)
+            //   base class of D and derived (directly or indirectly) from a
+            //   class B and that would be a valid deduced A, the deduced A
+            //   cannot be B or pointer to B, respectively.
+            // We shouldn't visit the bases of a successful match ('C'), as they
+            // could only be 'B' here.
+            SkipBases = true;
           }
 
           Deduced = DeducedOrig;
         }
 
         // Visit base classes
-        CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl());
-        for (const auto &Base : Next->bases()) {
-          assert(Base.getType()->isRecordType() &&
-                 "Base class that isn't a record?");
-          ToVisit.push_back(Base.getType()->getAs<RecordType>());
+        if (!SkipBases) {
+          CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl());
+          for (const auto &Base : Next->bases()) {
+            assert(Base.getType()->isRecordType() &&
+                   "Base class that isn't a record?");
+            ToVisit.push_back(Base.getType()->getAs<RecordType>());
+          }
         }
       }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to