erichkeane updated this revision to Diff 279847.
erichkeane marked an inline comment as done.
erichkeane added a comment.

As CWG seems unmoved by my argument as to why CWG2303 should change, I've opted 
to implement it as worded.  As you can see, the implementation is somewhat more 
complicated, but I believe I made it at least reasonably understandable.

I've also now updated the cwg_dr_status.html file via the script, which I also 
updated to acknowledge the current released version.


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
  clang/www/make_cxx_dr_status

Index: clang/www/make_cxx_dr_status
===================================================================
--- clang/www/make_cxx_dr_status
+++ clang/www/make_cxx_dr_status
@@ -1,4 +1,5 @@
 #! /usr/bin/env python
+
 import sys, os, re
 
 index = 'cwg_index.html'
@@ -93,7 +94,7 @@
     <th>Available in Clang?</th>
   </tr>'''
 
-latest_release = 10
+latest_release = 11
 
 def availability(issue):
   status = status_map.get(issue, 'unknown')
Index: clang/www/cxx_dr_status.html
===================================================================
--- clang/www/cxx_dr_status.html
+++ clang/www/cxx_dr_status.html
@@ -1504,7 +1504,7 @@
     <td><a href="https://wg21.link/cwg244";>244</a></td>
     <td>CD1</td>
     <td>Destructor lookup</td>
-    <td class="unreleased" align="center">Clang 11</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr id="245">
     <td><a href="https://wg21.link/cwg245";>245</a></td>
@@ -2789,7 +2789,7 @@
     <td><a href="https://wg21.link/cwg458";>458</a></td>
     <td>C++11</td>
     <td>Hiding of member template parameters by other members</td>
-    <td class="unreleased" align="center">Clang 11</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr class="open" id="459">
     <td><a href="https://wg21.link/cwg459";>459</a></td>
@@ -3967,7 +3967,7 @@
     <td><a href="https://wg21.link/cwg654";>654</a></td>
     <td>CD1</td>
     <td>Conversions to and from <TT>nullptr_t</TT></td>
-    <td class="unreleased" align="center">Superseded by <a href="#1423">1423</a></td>
+    <td class="full" align="center">Superseded by <a href="#1423">1423</a></td>
   </tr>
   <tr id="655">
     <td><a href="https://wg21.link/cwg655";>655</a></td>
@@ -8353,7 +8353,7 @@
     <td><a href="https://wg21.link/cwg1423";>1423</a></td>
     <td>CD3</td>
     <td>Convertibility of <TT>nullptr</TT> to <TT>bool</TT></td>
-    <td class="unreleased" align="center">Clang 11</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr id="1424">
     <td><a href="https://wg21.link/cwg1424";>1424</a></td>
@@ -8899,7 +8899,7 @@
     <td><a href="https://wg21.link/cwg1514";>1514</a></td>
     <td>C++14</td>
     <td>Ambiguity between enumeration definition and zero-length bit-field</td>
-    <td class="unreleased" align="center">Clang 11</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr id="1515">
     <td><a href="https://wg21.link/cwg1515";>1515</a></td>
@@ -10333,7 +10333,7 @@
     <td><a href="https://wg21.link/cwg1753";>1753</a></td>
     <td>CD4</td>
     <td><I>decltype-specifier</I> in <I>nested-name-specifier</I> of destructor</td>
-    <td class="unreleased" align="center">Clang 11</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr id="1754">
     <td><a href="https://wg21.link/cwg1754";>1754</a></td>
@@ -11611,7 +11611,7 @@
     <td><a href="https://wg21.link/cwg1966";>1966</a></td>
     <td>CD4</td>
     <td>Colon following enumeration <I>elaborated-type-specifier</I></td>
-    <td class="unreleased" align="center">Clang 11</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr id="1967">
     <td><a href="https://wg21.link/cwg1967";>1967</a></td>
@@ -11971,7 +11971,7 @@
     <td><a href="https://wg21.link/cwg2026";>2026</a></td>
     <td>CD4</td>
     <td>Zero-initialization and <TT>constexpr</TT></td>
-    <td class="unreleased" align="center">Clang 11</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr id="2027">
     <td><a href="https://wg21.link/cwg2027";>2027</a></td>
@@ -12307,7 +12307,7 @@
     <td><a href="https://wg21.link/cwg2082";>2082</a></td>
     <td>CD4</td>
     <td>Referring to parameters in unevaluated operands of default arguments</td>
-    <td class="unreleased" align="center">Clang 11</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr id="2083">
     <td><a href="https://wg21.link/cwg2083";>2083</a></td>
@@ -12757,7 +12757,7 @@
     <td><a href="https://wg21.link/cwg2157";>2157</a></td>
     <td>CD4</td>
     <td>Further disambiguation of enumeration <I>elaborated-type-specifier</I></td>
-    <td class="unreleased" align="center">Clang 11</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr class="open" id="2158">
     <td><a href="https://wg21.link/cwg2158";>2158</a></td>
@@ -13213,7 +13213,7 @@
     <td><a href="https://wg21.link/cwg2233";>2233</a></td>
     <td>DRWP</td>
     <td>Function parameter packs following default arguments</td>
-    <td class="unreleased" align="center">Clang 11</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr id="2234">
     <td><a href="https://wg21.link/cwg2234";>2234</a></td>
@@ -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="unreleased" align="center">Clang 12</td>
   </tr>
   <tr id="2304">
     <td><a href="https://wg21.link/cwg2304";>2304</a></td>
@@ -13891,7 +13891,7 @@
     <td><a href="https://wg21.link/cwg2346";>2346</a></td>
     <td>DRWP</td>
     <td>Local variables in default arguments</td>
-    <td class="unreleased" align="center">Clang 11</td>
+    <td class="full" align="center">Clang 11</td>
   </tr>
   <tr id="2347">
     <td><a href="https://wg21.link/cwg2347";>2347</a></td>
@@ -14499,6 +14499,24 @@
     <td>Unintended description of abbreviated function templates</td>
     <td class="none" align="center">Unknown</td>
   </tr>
+  <tr class="open" id="2448">
+    <td><a href="https://wg21.link/cwg2448";>2448</a></td>
+    <td>open</td>
+    <td>Cv-qualification of arithmetic types and deprecation of volatile</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="2449">
+    <td><a href="https://wg21.link/cwg2449";>2449</a></td>
+    <td>open</td>
+    <td>Thunks as an implementation technique for pointers to virtual functions</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="2450">
+    <td><a href="https://wg21.link/cwg2450";>2450</a></td>
+    <td>open</td>
+    <td><I>braced-init-list</I> as a <I>template-argument</I></td>
+    <td align="center">Not resolved</td>
+  </tr>
 </table>
 
 </div>
Index: clang/test/CXX/drs/dr23xx.cpp
===================================================================
--- clang/test/CXX/drs/dr23xx.cpp
+++ clang/test/CXX/drs/dr23xx.cpp
@@ -113,3 +113,35 @@
   extern template const int d<const int>;
 #endif
 }
+
+#if __cplusplus >= 201103L
+namespace dr2303 { // dr2303: 12
+template <typename... T>
+struct A;
+template <>
+struct A<> {};
+template <typename T, typename... Ts>
+struct A<T, Ts...> : A<Ts...> {};
+struct B : A<int, int> {};
+struct C : A<int, int>, A<int> {}; // expected-warning {{direct base 'A<int>' is inaccessible}}
+struct D : A<int>, A<int, int> {}; // expected-warning {{direct base 'A<int>' is inaccessible}}
+struct E : A<int, int> {};
+struct F : B, E {};
+
+template <typename... T>
+void f(const A<T...> &) {
+  static_assert(sizeof...(T) == 2, "Should only match A<int,int>");
+}
+template <typename... T>
+void f2(const A<T...> *);
+
+void g() {
+  f(B{}); // This is no longer ambiguous.
+  B b;
+  f2(&b);
+  f(C{});
+  f(D{});
+  f(F{}); // expected-error {{ambiguous conversion from derived class}}
+}
+} //namespace dr2303
+#endif
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -1201,6 +1201,159 @@
   return false;
 }
 
+// Attempt to deduce the template arguments by checking the base types according
+// to (C++ [temp.deduct.call] p4b3.
+///
+/// \param S the semantic analysis object within which we are deducing
+///
+/// \param RecordT the top level record object we are deducing against.
+///
+/// \param TemplateParams the template parameters that we are deducing
+///
+/// \param SpecParam the template specialization parameter type.
+///
+/// \param Info information about the template argument deduction itself
+///
+/// \param Deduced the deduced template arguments
+///
+/// \returns the result of template argument deduction with the bases. "invalid"
+/// means no matches, "success" found a single item, and the
+/// "MiscellaneousDeductionFailure" result happens when the match is ambiguous.
+static Sema::TemplateDeductionResult DeduceTemplateBases(
+    Sema &S, const RecordType *RecordT, TemplateParameterList *TemplateParams,
+    const TemplateSpecializationType *SpecParam, TemplateDeductionInfo &Info,
+    SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+  // C++14 [temp.deduct.call] p4b3:
+  //   If P is a class and P has the form simple-template-id, then the
+  //   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. 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
+  //   type deduction fails.
+
+  // A structure to represent the successful matches.
+  struct BaseMatch {
+    const RecordType *RT;
+    TemplateDeductionInfo BaseInfo;
+    SmallVector<DeducedTemplateArgument, 8> Deduction;
+
+    BaseMatch(const RecordType *RT, const TemplateDeductionInfo &Info,
+              const llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced)
+        : RT(RT), BaseInfo(TemplateDeductionInfo::ForBase, Info),
+          Deduction(Deduced.begin(), Deduced.end()) {}
+    BaseMatch(BaseMatch &&LHS)
+        : RT(LHS.RT), BaseInfo(TemplateDeductionInfo::ForBase, LHS.BaseInfo),
+          Deduction(std::move(LHS.Deduction)) {
+      BaseInfo.Param = std::move(LHS.BaseInfo.Param);
+      BaseInfo.FirstArg = std::move(LHS.BaseInfo.FirstArg);
+      BaseInfo.SecondArg = std::move(LHS.BaseInfo.SecondArg);
+    }
+
+    BaseMatch &operator=(BaseMatch &&LHS) {
+      RT = LHS.RT;
+      BaseInfo.Param = std::move(LHS.BaseInfo.Param);
+      BaseInfo.FirstArg = std::move(LHS.BaseInfo.FirstArg);
+      BaseInfo.SecondArg = std::move(LHS.BaseInfo.SecondArg);
+      Deduction = std::move(LHS.Deduction);
+      return *this;
+    }
+  };
+  // Use a breadth-first search through the bases to collect the set of
+  // successful matches. Visited contains the set of nodes we have already
+  // visited, while ToVisit is our stack of records that we still need to
+  // visit.  Matches contains a list of matches that have yet to be
+  // disqualified.
+  llvm::SmallPtrSet<const RecordType *, 8> Visited;
+  SmallVector<const RecordType *, 8> ToVisit;
+  SmallVector<BaseMatch, 4> Matches;
+
+  auto AddBases = [&ToVisit](const RecordType *RT) {
+    CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+    for (const auto &Base : RD->bases()) {
+      assert(Base.getType()->isRecordType() &&
+             "Base class that isn't a record?");
+      ToVisit.push_back(Base.getType()->getAs<RecordType>());
+    }
+  };
+
+  // Set up the loop by adding all the bases.
+  AddBases(RecordT);
+
+  // Search each path of bases until we either run into a successful match
+  // (where all bases of IT are invalid), or we run out of bases.
+  while (!ToVisit.empty()) {
+    const RecordType *NextT = ToVisit.pop_back_val();
+    // If we have already seen this type, skip it.
+    if (!Visited.insert(NextT).second)
+      continue;
+
+    BaseMatch &CurMatch = Matches.emplace_back(NextT, Info, Deduced);
+    Sema::TemplateDeductionResult BaseResult = DeduceTemplateArguments(
+        S, TemplateParams, SpecParam, QualType(NextT, 0), CurMatch.BaseInfo,
+        CurMatch.Deduction);
+
+    // If the match was not a successful deduction, we have to search its bases.
+    if (BaseResult != Sema::TDK_Success) {
+      AddBases(NextT);
+      Matches.pop_back();
+    }
+  }
+
+  // At this point, 'Matches' contains a list of seemingly valid bases, however
+  // in the event that we have more than 1 match, it is possible that the base
+  // of one of the matches might be disqualified for being a base of another
+  // valid match. We can count on cyclical instantiations being invalid to
+  // simplify the disqualifications.  That is, if A & B are both matches, and B
+  // inherits from A (disqualifying A), we know that A cannot inherit from B.
+  if (Matches.size() > 1) {
+    for (const BaseMatch &Match : Matches)
+      AddBases(Match.RT);
+
+    Visited.clear();
+
+    // We can give up once we have a single item (or have run out of things to
+    // search) since cyclical inheritence isn't valid.
+    while (Matches.size() > 1 && !ToVisit.empty()) {
+      const RecordType *NextT = ToVisit.pop_back_val();
+      // If we have already seen this type, skip it.
+      if (!Visited.insert(NextT).second)
+        continue;
+
+      BaseMatch CurMatch(NextT, Info, Deduced);
+      Sema::TemplateDeductionResult BaseResult = DeduceTemplateArguments(
+          S, TemplateParams, SpecParam, QualType(NextT, 0), CurMatch.BaseInfo,
+          CurMatch.Deduction);
+
+      // If this iS a match, it isn't valid due to CWG2303. So, remove it
+      // from the possible matches.
+      if (BaseResult == Sema::TDK_Success)
+        llvm::erase_if(Matches,
+                       [NextT](const BaseMatch &M) { return M.RT == NextT; });
+
+      // Always add all bases, since the inheritence tree can contain
+      // disqualifications for multiple matches.
+      AddBases(NextT);
+    }
+  }
+
+  if (Matches.empty())
+    return Sema::TDK_Invalid;
+  if (Matches.size() > 1)
+    return Sema::TDK_MiscellaneousDeductionFailure;
+
+  std::swap(Matches[0].Deduction, Deduced);
+  Info.Param = Matches[0].BaseInfo.Param;
+  Info.FirstArg = Matches[0].BaseInfo.FirstArg;
+  Info.SecondArg = Matches[0].BaseInfo.SecondArg;
+  return Sema::TDK_Success;
+}
+
 /// Deduce the template arguments by comparing the parameter type and
 /// the argument type (C++ [temp.deduct.type]).
 ///
@@ -1787,78 +1940,15 @@
       if (!S.isCompleteType(Info.getLocation(), Arg))
         return Result;
 
-      // C++14 [temp.deduct.call] p4b3:
-      //   If P is a class and P has the form simple-template-id, then the
-      //   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.
-      //
-      //   These alternatives are considered only if type deduction would
-      //   otherwise fail. If they yield more than one possible deduced A, the
-      //   type deduction fails.
-
       // Reset the incorrectly deduced argument from above.
       Deduced = DeducedOrig;
 
-      // Use data recursion to crawl through the list of base classes.
-      // Visited contains the set of nodes we have already visited, while
-      // ToVisit is our stack of records that we still need to visit.
-      llvm::SmallPtrSet<const RecordType *, 8> Visited;
-      SmallVector<const RecordType *, 8> ToVisit;
-      ToVisit.push_back(RecordT);
-      bool Successful = false;
-      SmallVector<DeducedTemplateArgument, 8> SuccessfulDeduced;
-      while (!ToVisit.empty()) {
-        // Retrieve the next class in the inheritance hierarchy.
-        const RecordType *NextT = ToVisit.pop_back_val();
-
-        // If we have already seen this type, skip it.
-        if (!Visited.insert(NextT).second)
-          continue;
-
-        // If this is a base class, try to perform template argument
-        // deduction from it.
-        if (NextT != RecordT) {
-          TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info);
-          Sema::TemplateDeductionResult BaseResult =
-              DeduceTemplateArguments(S, TemplateParams, SpecParam,
-                                      QualType(NextT, 0), BaseInfo, Deduced);
-
-          // If template argument deduction for this base was successful,
-          // note that we had some success. Otherwise, ignore any deductions
-          // from this base class.
-          if (BaseResult == Sema::TDK_Success) {
-            // If we've already seen some success, then deduction fails due to
-            // an ambiguity (temp.deduct.call p5).
-            if (Successful)
-              return Sema::TDK_MiscellaneousDeductionFailure;
-
-            Successful = true;
-            std::swap(SuccessfulDeduced, Deduced);
-
-            Info.Param = BaseInfo.Param;
-            Info.FirstArg = BaseInfo.FirstArg;
-            Info.SecondArg = BaseInfo.SecondArg;
-          }
-
-          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 (Successful) {
-        std::swap(SuccessfulDeduced, Deduced);
-        return Sema::TDK_Success;
-      }
+      // Check bases according to C++14 [temp.deduct.call] p4b3:
+      Sema::TemplateDeductionResult BaseResult = DeduceTemplateBases(
+          S, RecordT, TemplateParams, SpecParam, Info, Deduced);
 
+      if (BaseResult != Sema::TDK_Invalid)
+        return BaseResult;
       return Result;
     }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to