]> granicus.if.org Git - clang/commitdiff
P0702R1: in class template argument deduction from a list of one element, if
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 7 Sep 2017 07:22:36 +0000 (07:22 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 7 Sep 2017 07:22:36 +0000 (07:22 +0000)
that element's type is (or is derived from) a specialization of the deduced
template, skip the std::initializer_list special case.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@312703 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaInit.cpp
lib/Sema/SemaTemplateDeduction.cpp
test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
www/cxx_status.html

index 32024cb335dc30c97d37521c46bb018f7b603579..8aa60bcef07493e45f01c241d08a6f823cb301d6 100644 (file)
@@ -8339,6 +8339,16 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
   return Result;
 }
 
+/// Determine whether RD is, or is derived from, a specialization of CTD.
+static bool isOrIsDerivedFromSpecializationOf(CXXRecordDecl *RD,
+                                              ClassTemplateDecl *CTD) {
+  auto NotSpecialization = [&] (const CXXRecordDecl *Candidate) {
+    auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Candidate);
+    return !CTSD || !declaresSameEntity(CTSD->getSpecializedTemplate(), CTD);
+  };
+  return !(NotSpecialization(RD) && RD->forallBases(NotSpecialization));
+}
+
 QualType Sema::DeduceTemplateSpecializationFromInitializer(
     TypeSourceInfo *TSInfo, const InitializedEntity &Entity,
     const InitializationKind &Kind, MultiExprArg Inits) {
@@ -8483,6 +8493,17 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
           break;
         }
       }
+    } else if (ListInit->getNumInits() == 1) {
+      // C++ [over.match.class.deduct]:
+      //   As an exception, the first phase in [over.match.list] (considering
+      //   initializer-list constructors) is omitted if the initializer list
+      //   consists of a single expression of type cv U, where U is a
+      //   specialization of C or a class derived from a specialization of C.
+      Expr *E = ListInit->getInit(0);
+      auto *RD = E->getType()->getAsCXXRecordDecl();
+      if (!isa<InitListExpr>(E) && RD &&
+          isOrIsDerivedFromSpecializationOf(RD, Template))
+        TryListConstructors = false;
     }
 
     if (TryListConstructors)
index 5ed802d004f366c66b8f924e8401c611e3c40bb4..0dcf52aec5958ad67d92b482dee16fce17feb7dc 100644 (file)
@@ -2695,6 +2695,17 @@ static bool isSimpleTemplateIdType(QualType T) {
         = T->getAs<TemplateSpecializationType>())
     return Spec->getTemplateName().getAsTemplateDecl() != nullptr;
 
+  // C++17 [temp.local]p2:
+  //   the injected-class-name [...] is equivalent to the template-name followed
+  //   by the template-arguments of the class template specialization or partial
+  //   specialization enclosed in <>
+  // ... which means it's equivalent to a simple-template-id.
+  //
+  // This only arises during class template argument deduction for a copy
+  // deduction candidate, where it permits slicing.
+  if (T->getAs<InjectedClassNameType>())
+    return true;
+
   return false;
 }
 
index fe1b6a63d75b50093a6a90c8b023f9f8b96d7a07..cf925455acbc7480a535982f59b9f9526aec756e 100644 (file)
@@ -23,3 +23,34 @@ namespace Explicit {
   using Y = decltype(b);
   using X = decltype(c);
 }
+
+namespace std {
+  template<typename T> struct initializer_list {
+    const T *ptr;
+    __SIZE_TYPE__ size;
+    initializer_list();
+  };
+}
+
+namespace p0702r1 {
+  template<typename T> struct X { // expected-note {{candidate}}
+    X(std::initializer_list<T>); // expected-note {{candidate}}
+  };
+
+  X xi = {0};
+  X xxi = {xi};
+  extern X<int> xi;
+  // Prior to P0702R1, this is X<X<int>>.
+  extern X<int> xxi;
+
+  struct Y : X<int> {};
+  Y y {{0}};
+  X xy {y};
+  extern X<int> xy;
+
+  struct Z : X<int>, X<float> {};
+  Z z = {{0}, {0.0f}};
+  // This is not X<Z> even though that would work. Instead, it's ambiguous
+  // between X<int> and X<float>.
+  X xz = {z}; // expected-error {{no viable constructor or deduction guide}}
+}
index d90d08f0c27b9a5e7e1d0f6ec21642454ea1a81a..0a904765cf24129dc87452924e822174696b226c 100644 (file)
@@ -828,7 +828,7 @@ as the draft C++2a standard evolves.
     <tr>
       <td>Initializer list constructors in class template argument deduction</td>
       <td><a href="http://wg21.link/p0702r1">P0702R1</a></td>
-      <td class="none" align="center">No</td>
+      <td class="svn" align="center">SVN <a href="#p0702">(13)</a></td>
     </tr>
     <tr id="p0374">
       <td>Concepts</td>
@@ -838,6 +838,12 @@ as the draft C++2a standard evolves.
 </table>
 </details>
 
+<p>
+<span id="p0702">(13): This is the resolution to a Defect Report, so is applied
+to all language versions supporting class template argument deduction.
+</span>
+</p>
+
 <h2 id="ts">Technical specifications and standing documents</h2>
 
 <p>ISO C++ also publishes a number of documents describing additional language