[PATCH] D84048: DR2303: Prefer 'nearer' base classes during template deduction.

Erich Keane via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 17 09:53:19 PDT 2020


erichkeane created this revision.
erichkeane added reviewers: rsmith, rjmccall, aaron.ballman.

DR2303 fixes the case where the derived-base match for template
deduction is ambiguous if a base-of-base ALSO matches. The canonical
example (as shown in the test) is just like the MSVC implementation of
std::tuple.

This fixes a fairly sizable issue, where if a user inherits from
std::tuple on Windows (with the MS STL), they cannot use that type to
call a function that takes std::tuple.


https://reviews.llvm.org/D84048

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


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,21 +1844,33 @@
             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>());
+          }
         }
       }
 
       if (Successful) {
+        // TODO
         std::swap(SuccessfulDeduced, Deduced);
         return Sema::TDK_Success;
       }


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D84048.278821.patch
Type: text/x-patch
Size: 3503 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200717/885b1d05/attachment-0001.bin>


More information about the cfe-commits mailing list