r294613 - [c++1z] P0091R3: Basic support for deducing class template arguments via deduction-guides.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 9 11:17:44 PST 2017


Author: rsmith
Date: Thu Feb  9 13:17:44 2017
New Revision: 294613

URL: http://llvm.org/viewvc/llvm-project?rev=294613&view=rev
Log:
[c++1z] P0091R3: Basic support for deducing class template arguments via deduction-guides.

Added:
    cfe/trunk/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
    cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/
    cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp
    cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
Modified:
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/Sema/SemaCast.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp
    cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Thu Feb  9 13:17:44 2017
@@ -1470,7 +1470,8 @@ class CXXTemporaryObjectExpr : public CX
 public:
   CXXTemporaryObjectExpr(const ASTContext &C,
                          CXXConstructorDecl *Cons,
-                         TypeSourceInfo *Type,
+                         QualType Type,
+                         TypeSourceInfo *TSI,
                          ArrayRef<Expr *> Args,
                          SourceRange ParenOrBraceRange,
                          bool HadMultipleCandidates,

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Thu Feb  9 13:17:44 2017
@@ -4115,7 +4115,10 @@ class DeducedType : public Type {
 protected:
   DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent,
               bool IsInstantiationDependent, bool ContainsParameterPack)
-      : Type(TC, DeducedAsType.isNull() ? QualType(this, 0) : DeducedAsType,
+      : Type(TC,
+             // FIXME: Retain the sugared deduced type?
+             DeducedAsType.isNull() ? QualType(this, 0)
+                                    : DeducedAsType.getCanonicalType(),
              IsDependent, IsInstantiationDependent,
              /*VariablyModified=*/false, ContainsParameterPack) {
     if (!DeducedAsType.isNull()) {

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Feb  9 13:17:44 2017
@@ -1849,8 +1849,8 @@ def warn_cxx98_compat_temp_copy : Warnin
   InGroup<CXX98CompatBindToTemporaryCopy>, DefaultIgnore;
 def err_selected_explicit_constructor : Error<
   "chosen constructor is explicit in copy-initialization">;
-def note_constructor_declared_here : Note<
-  "constructor declared here">;
+def note_explicit_ctor_deduction_guide_here : Note<
+  "explicit %select{constructor|deduction guide}0 declared here">;
 
 // C++11 decltype
 def err_decltype_in_declarator : Error<
@@ -1961,8 +1961,23 @@ def err_deduced_class_template_compound_
   "cannot %select{form pointer to|form reference to|form array of|"
   "form function returning|use parentheses when declaring variable with}0 "
   "deduced class template specialization type">;
-def err_deduced_class_template_not_supported : Error<
-  "deduction of template arguments for class templates is not yet supported">;
+def err_deduced_non_class_template_specialization_type : Error<
+  "%select{<error>|function template|variable template|alias template|"
+  "template template parameter|template}0 %1 requires template arguments; "
+  "argument deduction only allowed for class templates">;
+def err_deduced_class_template_ctor_ambiguous : Error<
+  "ambiguous deduction for template arguments of %0">;
+def err_deduced_class_template_ctor_no_viable : Error<
+  "no viable constructor or deduction guide for deduction of "
+  "template arguments of %0">;
+def err_deduced_class_template_incomplete : Error<
+  "template %0 has no definition and no %select{|viable }1deduction guides "
+  "for deduction of template arguments">;
+def err_deduced_class_template_deleted : Error<
+  "class template argument deduction for %0 selected a deleted constructor">;
+def err_deduced_class_template_explicit : Error<
+  "class template argument deduction for %0 selected an explicit "
+  "%select{constructor|deduction guide}1 for copy-list-initialization">;
 def err_deduction_guide_no_trailing_return_type : Error<
   "deduction guide declaration without trailing return type">;
 def err_deduction_guide_with_complex_decl : Error<

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Thu Feb  9 13:17:44 2017
@@ -274,15 +274,18 @@ public:
   
   /// \brief Create the initialization entity for a temporary.
   static InitializedEntity InitializeTemporary(QualType Type) {
-    InitializedEntity Result(EK_Temporary, SourceLocation(), Type);
-    Result.TypeInfo = nullptr;
-    return Result;
+    return InitializeTemporary(nullptr, Type);
   }
 
   /// \brief Create the initialization entity for a temporary.
   static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo) {
-    InitializedEntity Result(EK_Temporary, SourceLocation(), 
-                             TypeInfo->getType());
+    return InitializeTemporary(TypeInfo, TypeInfo->getType());
+  }
+  
+  /// \brief Create the initialization entity for a temporary.
+  static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo,
+                                               QualType Type) {
+    InitializedEntity Result(EK_Temporary, SourceLocation(), Type);
     Result.TypeInfo = TypeInfo;
     return Result;
   }
@@ -579,6 +582,16 @@ public:
     return InitializationKind(IK_Value, isImplicit ? IC_Implicit : IC_Normal,
                               InitLoc, LParenLoc, RParenLoc);
   }
+
+  /// \brief Create an initialization from an initializer (which, for direct
+  /// initialization from a parenthesized list, will be a ParenListExpr).
+  static InitializationKind CreateForInit(SourceLocation Loc, bool DirectInit,
+                                          Expr *Init) {
+    if (!Init) return CreateDefault(Loc);
+    if (!DirectInit) return CreateCopy(Loc, Init->getLocStart());
+    if (isa<InitListExpr>(Init)) return CreateDirectList(Loc);
+    return CreateDirect(Loc, Init->getLocStart(), Init->getLocEnd());
+  }
   
   /// \brief Determine the initialization kind.
   InitKind getKind() const {

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Feb  9 13:17:44 2017
@@ -1760,6 +1760,8 @@ public:
   // Returns true if the variable declaration is a redeclaration
   bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
   void CheckVariableDeclarationType(VarDecl *NewVD);
+  bool DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
+                                     Expr *Init);
   void CheckCompleteVariableDeclaration(VarDecl *VD);
   void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD);
   void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
@@ -4340,7 +4342,7 @@ public:
 
   /// \brief Determine whether Ctor is an initializer-list constructor, as
   /// defined in [dcl.init.list]p2.
-  bool isInitListConstructor(const CXXConstructorDecl *Ctor);
+  bool isInitListConstructor(const FunctionDecl *Ctor);
 
   Decl *ActOnUsingDirective(Scope *CurScope,
                             SourceLocation UsingLoc,
@@ -6767,6 +6769,10 @@ public:
   bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
                         bool Diagnose = true);
 
+  QualType DeduceTemplateSpecializationFromInitializer(
+      TypeSourceInfo *TInfo, const InitializedEntity &Entity,
+      const InitializationKind &Kind, MultiExprArg Init);
+
   QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name,
                                         QualType Type, TypeSourceInfo *TSI,
                                         SourceRange Range, bool DirectInit,
@@ -9304,7 +9310,7 @@ public:
   ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr,
                                 CastKind &Kind);
 
-  ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo,
+  ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, QualType Type,
                                         SourceLocation LParenLoc,
                                         Expr *CastExpr,
                                         SourceLocation RParenLoc);

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Thu Feb  9 13:17:44 2017
@@ -734,23 +734,23 @@ CXXBindTemporaryExpr *CXXBindTemporaryEx
 
 CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C,
                                                CXXConstructorDecl *Cons,
-                                               TypeSourceInfo *Type,
+                                               QualType Type,
+                                               TypeSourceInfo *TSI,
                                                ArrayRef<Expr*> Args,
                                                SourceRange ParenOrBraceRange,
                                                bool HadMultipleCandidates,
                                                bool ListInitialization,
                                                bool StdInitListInitialization,
                                                bool ZeroInitialization)
-  : CXXConstructExpr(C, CXXTemporaryObjectExprClass, 
-                     Type->getType().getNonReferenceType(), 
-                     Type->getTypeLoc().getBeginLoc(),
+  : CXXConstructExpr(C, CXXTemporaryObjectExprClass, Type,
+                     TSI->getTypeLoc().getBeginLoc(),
                      Cons, false, Args,
                      HadMultipleCandidates,
                      ListInitialization,
                      StdInitListInitialization,
                      ZeroInitialization,
                      CXXConstructExpr::CK_Complete, ParenOrBraceRange),
-    Type(Type) {
+    Type(TSI) {
 }
 
 SourceLocation CXXTemporaryObjectExpr::getLocStart() const {

Modified: cfe/trunk/lib/Sema/SemaCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCast.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCast.cpp Thu Feb  9 13:17:44 2017
@@ -2627,11 +2627,12 @@ ExprResult Sema::BuildCStyleCastExpr(Sou
 }
 
 ExprResult Sema::BuildCXXFunctionalCastExpr(TypeSourceInfo *CastTypeInfo,
+                                            QualType Type,
                                             SourceLocation LPLoc,
                                             Expr *CastExpr,
                                             SourceLocation RPLoc) {
   assert(LPLoc.isValid() && "List-initialization shouldn't get here.");
-  CastOperation Op(*this, CastTypeInfo->getType(), CastExpr);
+  CastOperation Op(*this, Type, CastExpr);
   Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange();
   Op.OpRange = SourceRange(Op.DestRange.getBegin(), CastExpr->getLocEnd());
 

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Feb  9 13:17:44 2017
@@ -9807,16 +9807,33 @@ QualType Sema::deduceVarTypeFromInitiali
   DeducedType *Deduced = Type->getContainedDeducedType();
   assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type");
 
+  ArrayRef<Expr*> DeduceInits = Init ? ArrayRef<Expr*>(Init) : None;
+  if (DirectInit) {
+    if (auto *PL = dyn_cast_or_null<ParenListExpr>(Init))
+      DeduceInits = PL->exprs();
+  }
+
   if (isa<DeducedTemplateSpecializationType>(Deduced)) {
-    Diag(Init->getLocStart(), diag::err_deduced_class_template_not_supported);
+    assert(VDecl && "non-auto type for init capture deduction?");
+    InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
+    InitializationKind Kind = InitializationKind::CreateForInit(
+        VDecl->getLocation(), DirectInit, Init);
+    // FIXME: Initialization should not be taking a mutable list of inits. 
+    SmallVector<Expr*, 8> InitsCopy(DeduceInits.begin(), DeduceInits.end());
+    return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind,
+                                                       InitsCopy);
+  }
+
+  // C++11 [dcl.spec.auto]p3
+  if (!Init) {
+    assert(VDecl && "no init for init capture deduction?");
+    Diag(VDecl->getLocation(), diag::err_auto_var_requires_init)
+      << VDecl->getDeclName() << Type;
     return QualType();
   }
 
-  ArrayRef<Expr *> DeduceInits = Init;
   if (DirectInit) {
-    if (auto *PL = dyn_cast<ParenListExpr>(Init))
-      DeduceInits = PL->exprs();
-    else if (auto *IL = dyn_cast<InitListExpr>(Init))
+    if (auto *IL = dyn_cast<InitListExpr>(Init))
       DeduceInits = IL->inits();
   }
 
@@ -9902,6 +9919,36 @@ QualType Sema::deduceVarTypeFromInitiali
   return DeducedType;
 }
 
+bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
+                                         Expr *Init) {
+  QualType DeducedType = deduceVarTypeFromInitializer(
+      VDecl, VDecl->getDeclName(), VDecl->getType(), VDecl->getTypeSourceInfo(),
+      VDecl->getSourceRange(), DirectInit, Init);
+  if (DeducedType.isNull()) {
+    VDecl->setInvalidDecl();
+    return true;
+  }
+
+  VDecl->setType(DeducedType);
+  assert(VDecl->isLinkageValid());
+
+  // In ARC, infer lifetime.
+  if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
+    VDecl->setInvalidDecl();
+
+  // If this is a redeclaration, check that the type we just deduced matches
+  // the previously declared type.
+  if (VarDecl *Old = VDecl->getPreviousDecl()) {
+    // We never need to merge the type, because we cannot form an incomplete
+    // array of auto, nor deduce such a type.
+    MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/ false);
+  }
+
+  // Check the deduced type is valid for a variable declaration.
+  CheckVariableDeclarationType(VDecl);
+  return VDecl->isInvalidDecl();
+}
+
 /// AddInitializerToDecl - Adds the initializer Init to the
 /// declaration dcl. If DirectInit is true, this is C++ direct
 /// initialization rather than copy initialization.
@@ -9941,32 +9988,7 @@ void Sema::AddInitializerToDecl(Decl *Re
     }
     Init = Res.get();
 
-    QualType DeducedType = deduceVarTypeFromInitializer(
-        VDecl, VDecl->getDeclName(), VDecl->getType(),
-        VDecl->getTypeSourceInfo(), VDecl->getSourceRange(), DirectInit, Init);
-    if (DeducedType.isNull()) {
-      RealDecl->setInvalidDecl();
-      return;
-    }
-
-    VDecl->setType(DeducedType);
-    assert(VDecl->isLinkageValid());
-
-    // In ARC, infer lifetime.
-    if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
-      VDecl->setInvalidDecl();
-
-    // If this is a redeclaration, check that the type we just deduced matches
-    // the previously declared type.
-    if (VarDecl *Old = VDecl->getPreviousDecl()) {
-      // We never need to merge the type, because we cannot form an incomplete
-      // array of auto, nor deduce such a type.
-      MergeVarDeclTypes(VDecl, Old, /*MergeTypeWithPrevious*/ false);
-    }
-
-    // Check the deduced type is valid for a variable declaration.
-    CheckVariableDeclarationType(VDecl);
-    if (VDecl->isInvalidDecl())
+    if (DeduceVariableDeclarationType(VDecl, DirectInit, Init))
       return;
   }
 
@@ -10085,15 +10107,8 @@ void Sema::AddInitializerToDecl(Decl *Re
       }
 
     InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
-    InitializationKind Kind =
-        DirectInit
-            ? CXXDirectInit
-                  ? InitializationKind::CreateDirect(VDecl->getLocation(),
-                                                     Init->getLocStart(),
-                                                     Init->getLocEnd())
-                  : InitializationKind::CreateDirectList(VDecl->getLocation())
-            : InitializationKind::CreateCopy(VDecl->getLocation(),
-                                             Init->getLocStart());
+    InitializationKind Kind = InitializationKind::CreateForInit(
+        VDecl->getLocation(), DirectInit, Init);
 
     MultiExprArg Args = Init;
     if (CXXDirectInit)
@@ -10417,13 +10432,9 @@ void Sema::ActOnUninitializedDecl(Decl *
       return;
     }
 
-    // C++11 [dcl.spec.auto]p3
-    if (Type->isUndeducedType()) {
-      Diag(Var->getLocation(), diag::err_auto_var_requires_init)
-        << Var->getDeclName() << Type;
-      Var->setInvalidDecl();
+    if (Type->isUndeducedType() &&
+        DeduceVariableDeclarationType(Var, false, nullptr))
       return;
-    }
 
     // C++11 [class.static.data]p3: A static data member can be declared with
     // the constexpr specifier; if so, its declaration shall specify

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Feb  9 13:17:44 2017
@@ -8556,7 +8556,7 @@ QualType Sema::BuildStdInitializerList(Q
       CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
 }
 
-bool Sema::isInitListConstructor(const CXXConstructorDecl* Ctor) {
+bool Sema::isInitListConstructor(const FunctionDecl *Ctor) {
   // C++ [dcl.init.list]p2:
   //   A constructor is an initializer-list constructor if its first parameter
   //   is of type std::initializer_list<E> or reference to possibly cv-qualified

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Feb  9 13:17:44 2017
@@ -1266,15 +1266,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSour
                                               RParenLoc);
   }
 
-  // C++1z [expr.type.conv]p1:
-  //   If the type is a placeholder for a deduced class type, [...perform class
-  //   template argument deduction...]
-  DeducedType *Deduced = Ty->getContainedDeducedType();
-  if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
-    Diag(TyBeginLoc, diag::err_deduced_class_template_not_supported);
-    return ExprError();
-  }
-
   bool ListInitialization = LParenLoc.isInvalid();
   assert((!ListInitialization ||
           (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) &&
@@ -1282,13 +1273,34 @@ Sema::BuildCXXTypeConstructExpr(TypeSour
   SourceRange FullRange = SourceRange(TyBeginLoc,
       ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc);
 
+  InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo);
+  InitializationKind Kind =
+      Exprs.size()
+          ? ListInitialization
+                ? InitializationKind::CreateDirectList(TyBeginLoc)
+                : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc,
+                                                   RParenLoc)
+          : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc);
+
+  // C++1z [expr.type.conv]p1:
+  //   If the type is a placeholder for a deduced class type, [...perform class
+  //   template argument deduction...]
+  DeducedType *Deduced = Ty->getContainedDeducedType();
+  if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
+    Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity,
+                                                     Kind, Exprs);
+    if (Ty.isNull())
+      return ExprError();
+    Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
+  }
+
   // C++ [expr.type.conv]p1:
   // If the expression list is a single expression, the type conversion
   // expression is equivalent (in definedness, and if defined in meaning) to the
   // corresponding cast expression.
   if (Exprs.size() == 1 && !ListInitialization) {
     Expr *Arg = Exprs[0];
-    return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc);
+    return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenLoc, Arg, RParenLoc);
   }
 
   // C++14 [expr.type.conv]p2: The expression T(), where T is a
@@ -1313,12 +1325,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSour
                           diag::err_invalid_incomplete_type_use, FullRange))
     return ExprError();
 
-  InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo);
-  InitializationKind Kind =
-      Exprs.size() ? ListInitialization
-      ? InitializationKind::CreateDirectList(TyBeginLoc)
-      : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, RParenLoc)
-      : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc);
   InitializationSequence InitSeq(*this, Entity, Kind, Exprs);
   ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs);
 
@@ -1339,7 +1345,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSour
     // is sometimes handled by initialization and sometimes not.
     QualType ResultType = Result.get()->getType();
     Result = CXXFunctionalCastExpr::Create(
-        Context, ResultType, Expr::getValueKindForType(TInfo->getType()), TInfo,
+        Context, ResultType, Expr::getValueKindForType(Ty), TInfo,
         CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc);
   }
 
@@ -1665,13 +1671,38 @@ Sema::BuildCXXNew(SourceRange Range, boo
     NumInits = List->getNumExprs();
   }
 
+  // C++11 [expr.new]p15:
+  //   A new-expression that creates an object of type T initializes that
+  //   object as follows:
+  InitializationKind Kind
+  //     - If the new-initializer is omitted, the object is default-
+  //       initialized (8.5); if no initialization is performed,
+  //       the object has indeterminate value
+    = initStyle == CXXNewExpr::NoInit
+        ? InitializationKind::CreateDefault(TypeRange.getBegin())
+  //     - Otherwise, the new-initializer is interpreted according to the
+  //       initialization rules of 8.5 for direct-initialization.
+        : initStyle == CXXNewExpr::ListInit
+            ? InitializationKind::CreateDirectList(TypeRange.getBegin())
+            : InitializationKind::CreateDirect(TypeRange.getBegin(),
+                                               DirectInitRange.getBegin(),
+                                               DirectInitRange.getEnd());
+
   // C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for.
-  if (AllocType->isUndeducedType()) {
-    if (isa<DeducedTemplateSpecializationType>(
-            AllocType->getContainedDeducedType()))
-      return ExprError(Diag(TypeRange.getBegin(),
-                            diag::err_deduced_class_template_not_supported));
+  auto *Deduced = AllocType->getContainedDeducedType();
+  if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
+    if (ArraySize)
+      return ExprError(Diag(ArraySize->getExprLoc(),
+                            diag::err_deduced_class_template_compound_type)
+                       << /*array*/ 2 << ArraySize->getSourceRange());
 
+    InitializedEntity Entity
+      = InitializedEntity::InitializeNew(StartLoc, AllocType);
+    AllocType = DeduceTemplateSpecializationFromInitializer(
+        AllocTypeInfo, Entity, Kind, MultiExprArg(Inits, NumInits));
+    if (AllocType.isNull())
+      return ExprError();
+  } else if (Deduced) {
     if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
       return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
                        << AllocType << TypeRange);
@@ -1958,23 +1989,6 @@ Sema::BuildCXXNew(SourceRange Range, boo
     else
       InitType = AllocType;
 
-    // C++11 [expr.new]p15:
-    //   A new-expression that creates an object of type T initializes that
-    //   object as follows:
-    InitializationKind Kind
-    //     - If the new-initializer is omitted, the object is default-
-    //       initialized (8.5); if no initialization is performed,
-    //       the object has indeterminate value
-      = initStyle == CXXNewExpr::NoInit
-          ? InitializationKind::CreateDefault(TypeRange.getBegin())
-    //     - Otherwise, the new-initializer is interpreted according to the
-    //       initialization rules of 8.5 for direct-initialization.
-          : initStyle == CXXNewExpr::ListInit
-              ? InitializationKind::CreateDirectList(TypeRange.getBegin())
-              : InitializationKind::CreateDirect(TypeRange.getBegin(),
-                                                 DirectInitRange.getBegin(),
-                                                 DirectInitRange.getEnd());
-
     InitializedEntity Entity
       = InitializedEntity::InitializeNew(StartLoc, InitType);
     InitializationSequence InitSeq(*this, Entity, Kind,

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Feb  9 13:17:44 2017
@@ -5914,7 +5914,8 @@ PerformConstructorInitialization(Sema &S
     S.MarkFunctionReferenced(Loc, Constructor);
 
     CurInit = new (S.Context) CXXTemporaryObjectExpr(
-        S.Context, Constructor, TSInfo,
+        S.Context, Constructor,
+        Entity.getType().getNonLValueExprType(S.Context), TSInfo,
         ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
         IsListInitialization, IsStdInitListInitialization,
         ConstructorInitRequiresZeroInit);
@@ -6982,7 +6983,7 @@ InitializationSequence::Perform(Sema &S,
                                                     Kind.getRange().getBegin());
 
         CurInit = new (S.Context) CXXScalarValueInitExpr(
-            TSInfo->getType().getNonLValueExprType(S.Context), TSInfo,
+            Entity.getType().getNonLValueExprType(S.Context), TSInfo,
             Kind.getRange().getEnd());
       } else {
         CurInit = new (S.Context) ImplicitValueInitExpr(Step->Type);
@@ -7755,7 +7756,8 @@ bool InitializationSequence::Diagnose(Se
     (void)Ovl;
     assert(Ovl == OR_Success && "Inconsistent overload resolution");
     CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
-    S.Diag(CtorDecl->getLocation(), diag::note_constructor_declared_here);
+    S.Diag(CtorDecl->getLocation(),
+           diag::note_explicit_ctor_deduction_guide_here) << false;
     break;
   }
   }
@@ -8219,3 +8221,215 @@ Sema::PerformCopyInitialization(const In
 
   return Result;
 }
+
+QualType Sema::DeduceTemplateSpecializationFromInitializer(
+    TypeSourceInfo *TSInfo, const InitializedEntity &Entity,
+    const InitializationKind &Kind, MultiExprArg Inits) {
+  auto *DeducedTST = dyn_cast<DeducedTemplateSpecializationType>(
+      TSInfo->getType()->getContainedDeducedType());
+  assert(DeducedTST && "not a deduced template specialization type");
+
+  // We can only perform deduction for class templates.
+  auto TemplateName = DeducedTST->getTemplateName();
+  auto *Template =
+      dyn_cast_or_null<ClassTemplateDecl>(TemplateName.getAsTemplateDecl());
+  if (!Template) {
+    Diag(Kind.getLocation(),
+         diag::err_deduced_non_class_template_specialization_type)
+      << (int)getTemplateNameKindForDiagnostics(TemplateName) << TemplateName;
+    if (auto *TD = TemplateName.getAsTemplateDecl())
+      Diag(TD->getLocation(), diag::note_template_decl_here);
+    return QualType();
+  }
+
+  // FIXME: Perform "exact type" matching first, per CWG discussion?
+  //        Or implement this via an implied 'T(T) -> T' deduction guide?
+
+  // FIXME: Do we need/want a std::initializer_list<T> special case?
+
+  // C++1z [over.match.class.deduct]p1:
+  //   A set of functions and function templates is formed comprising:
+  bool HasDefaultConstructor = false;
+  SmallVector<DeclAccessPair, 16> CtorsAndGuides;
+  CXXRecordDecl *Primary = Template->getTemplatedDecl();
+  bool Complete = isCompleteType(TSInfo->getTypeLoc().getEndLoc(),
+                                 Context.getTypeDeclType(Primary));
+  if (Complete) {
+    for (NamedDecl *D : LookupConstructors(Template->getTemplatedDecl())) {
+      //   - For each constructor of the class template designated by the
+      //     template-name, a function template [...]
+      auto Info = getConstructorInfo(D);
+      if (!Info.Constructor || Info.Constructor->isInvalidDecl())
+        continue;
+
+      // FIXME: Synthesize a deduction guide.
+
+      if (Info.Constructor->isDefaultConstructor())
+        HasDefaultConstructor = true;
+    }
+  }
+
+  //  - For each deduction-guide, a function or function template [...]
+  DeclarationNameInfo NameInfo(
+      Context.DeclarationNames.getCXXDeductionGuideName(Template),
+      TSInfo->getTypeLoc().getEndLoc());
+  LookupResult Guides(*this, NameInfo, LookupOrdinaryName);
+  LookupQualifiedName(Guides, Template->getDeclContext());
+  for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
+    auto *FD = dyn_cast<FunctionDecl>(*I);
+    if (FD && FD->getMinRequiredArguments() == 0)
+      HasDefaultConstructor = true;
+    CtorsAndGuides.push_back(I.getPair());
+  }
+
+  // FIXME: Do not diagnose inaccessible deduction guides. The standard isn't
+  // clear on this, but they're not found by name so access does not apply.
+  Guides.suppressDiagnostics();
+
+  // Figure out if this is list-initialization.
+  InitListExpr *ListInit =
+      (Inits.size() == 1 && Kind.getKind() != InitializationKind::IK_Direct)
+          ? dyn_cast<InitListExpr>(Inits[0])
+          : nullptr;
+
+  // C++1z [over.match.class.deduct]p1:
+  //   Initialization and overload resolution are performed as described in
+  //   [dcl.init] and [over.match.ctor], [over.match.copy], or [over.match.list]
+  //   (as appropriate for the type of initialization performed) for an object
+  //   of a hypothetical class type, where the selected functions and function
+  //   templates are considered to be the constructors of that class type
+  //
+  // Since we know we're initializing a class type of a type unrelated to that
+  // of the initializer, this reduces to something fairly reasonable.
+  OverloadCandidateSet Candidates(Kind.getLocation(),
+                                  OverloadCandidateSet::CSK_Normal);
+  OverloadCandidateSet::iterator Best;
+  auto tryToResolveOverload =
+      [&](bool OnlyListConstructors) -> OverloadingResult {
+    Candidates.clear();
+    for (DeclAccessPair Pair : CtorsAndGuides) {
+      NamedDecl *D = Pair.getDecl()->getUnderlyingDecl();
+      if (D->isInvalidDecl())
+        continue;
+
+      FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(D);
+      FunctionDecl *FD =
+          TD ? TD->getTemplatedDecl() : dyn_cast<FunctionDecl>(D);
+      if (!FD)
+        continue;
+
+      // C++ [over.match.ctor]p1: (non-list copy-initialization from non-class)
+      //   For copy-initialization, the candidate functions are all the
+      //   converting constructors (12.3.1) of that class.
+      // C++ [over.match.copy]p1: (non-list copy-initialization from class)
+      //   The converting constructors of T are candidate functions.
+      if (Kind.isCopyInit() && !ListInit) {
+        // FIXME: if (FD->isExplicit()) continue;
+
+        // When looking for a converting constructor, deduction guides that
+        // could never be called with one argument are not interesting.
+        if (FD->getMinRequiredArguments() > 1 ||
+            (FD->getNumParams() == 0 && !FD->isVariadic()))
+          continue;
+      }
+
+      // C++ [over.match.list]p1.1: (first phase list initialization)
+      //   Initially, the candidate functions are the initializer-list
+      //   constructors of the class T
+      if (OnlyListConstructors && !isInitListConstructor(FD))
+        continue;
+
+      // C++ [over.match.list]p1.2: (second phase list initialization)
+      //   the candidate functions are all the constructors of the class T
+      // C++ [over.match.ctor]p1: (all other cases)
+      //   the candidate functions are all the constructors of the class of
+      //   the object being initialized
+
+      // C++ [over.best.ics]p4:
+      //   When [...] the constructor [...] is a candidate by
+      //    - [over.match.copy] (in all cases)
+      // FIXME: The "second phase of [over.match.list] case can also
+      // theoretically happen here, but it's not clear whether we can
+      // ever have a parameter of the right type.
+      bool SuppressUserConversions = Kind.isCopyInit();
+
+      // FIXME: These are definitely wrong in the non-deduction-guide case.
+      if (TD)
+        AddTemplateOverloadCandidate(TD, Pair, /*ExplicitArgs*/ nullptr, Inits,
+                                     Candidates, SuppressUserConversions);
+      else
+        AddOverloadCandidate(FD, Pair, Inits, Candidates,
+                             SuppressUserConversions);
+    }
+    return Candidates.BestViableFunction(*this, Kind.getLocation(), Best);
+  };
+
+  OverloadingResult Result = OR_No_Viable_Function;
+
+  // C++11 [over.match.list]p1, per DR1467: for list-initialization, first
+  // try initializer-list constructors.
+  if (ListInit) {
+    if (ListInit->getNumInits() || !HasDefaultConstructor)
+      Result = tryToResolveOverload(/*OnlyListConstructor*/true);
+    // Then unwrap the initializer list and try again considering all
+    // constructors.
+    Inits = MultiExprArg(ListInit->getInits(), ListInit->getNumInits());
+  }
+
+  // If list-initialization fails, or if we're doing any other kind of
+  // initialization, we (eventually) consider constructors.
+  if (Result == OR_No_Viable_Function)
+    Result = tryToResolveOverload(/*OnlyListConstructor*/false);
+
+  switch (Result) {
+  case OR_Ambiguous:
+    Diag(Kind.getLocation(), diag::err_deduced_class_template_ctor_ambiguous)
+      << TemplateName;
+    // FIXME: For list-initialization candidates, it'd usually be better to
+    // list why they were not viable when given the initializer list itself as
+    // an argument.
+    Candidates.NoteCandidates(*this, OCD_ViableCandidates, Inits);
+    return QualType();
+
+  case OR_No_Viable_Function:
+    Diag(Kind.getLocation(),
+         Complete ? diag::err_deduced_class_template_ctor_no_viable
+                  : diag::err_deduced_class_template_incomplete)
+      << TemplateName << !CtorsAndGuides.empty();
+    Candidates.NoteCandidates(*this, OCD_AllCandidates, Inits);
+    return QualType();
+
+  case OR_Deleted: {
+    Diag(Kind.getLocation(), diag::err_deduced_class_template_deleted)
+      << TemplateName;
+    NoteDeletedFunction(Best->Function);
+    return QualType();
+  }
+
+  case OR_Success:
+    // C++ [over.match.list]p1:
+    //   In copy-list-initialization, if an explicit constructor is chosen, the
+    //   initialization is ill-formed.
+    if (Kind.isCopyInit() && ListInit &&
+        false /*FIXME: Best->Function->isExplicit()*/) {
+      bool IsDeductionGuide = !Best->Function->isImplicit();
+      Diag(Kind.getLocation(), diag::err_deduced_class_template_explicit)
+          << TemplateName << IsDeductionGuide;
+      Diag(Best->Function->getLocation(),
+           diag::note_explicit_ctor_deduction_guide_here)
+          << IsDeductionGuide;
+      return QualType();
+    }
+
+    // Make sure we didn't select an unusable deduction guide, and mark it
+    // as referenced.
+    DiagnoseUseOfDecl(Best->Function, Kind.getLocation());
+    MarkFunctionReferenced(Kind.getLocation(), Best->Function);
+    break;
+  }
+
+  // C++ [dcl.type.class.deduct]p1:
+  //  The placeholder is replaced by the return type of the function selected
+  //  by overload resolution for class template deduction.
+  return SubstAutoType(TSInfo->getType(), Best->Function->getReturnType());
+}

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Feb  9 13:17:44 2017
@@ -4019,17 +4019,26 @@ Sema::TemplateDeductionResult Sema::Dedu
 }
 
 namespace {
-  /// Substitute the 'auto' type specifier within a type for a given replacement
-  /// type.
-  class SubstituteAutoTransform :
-    public TreeTransform<SubstituteAutoTransform> {
+  /// Substitute the 'auto' specifier or deduced template specialization type
+  /// specifier within a type for a given replacement type.
+  class SubstituteDeducedTypeTransform :
+      public TreeTransform<SubstituteDeducedTypeTransform> {
     QualType Replacement;
-    bool UseAutoSugar;
+    bool UseTypeSugar;
   public:
-    SubstituteAutoTransform(Sema &SemaRef, QualType Replacement,
-                            bool UseAutoSugar = true)
-        : TreeTransform<SubstituteAutoTransform>(SemaRef),
-          Replacement(Replacement), UseAutoSugar(UseAutoSugar) {}
+    SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement,
+                            bool UseTypeSugar = true)
+        : TreeTransform<SubstituteDeducedTypeTransform>(SemaRef),
+          Replacement(Replacement), UseTypeSugar(UseTypeSugar) {}
+
+    QualType TransformDesugared(TypeLocBuilder &TLB, DeducedTypeLoc TL) {
+      assert(isa<TemplateTypeParmType>(Replacement) &&
+             "unexpected unsugared replacement kind");
+      QualType Result = Replacement;
+      TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
+      NewTL.setNameLoc(TL.getNameLoc());
+      return Result;
+    }
 
     QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) {
       // If we're building the type pattern to deduce against, don't wrap the
@@ -4039,21 +4048,29 @@ namespace {
       //   auto &&lref = lvalue;
       // must transform into "rvalue reference to T" not "rvalue reference to
       // auto type deduced as T" in order for [temp.deduct.call]p3 to apply.
-      if (!UseAutoSugar) {
-        assert(isa<TemplateTypeParmType>(Replacement) &&
-               "unexpected unsugared replacement kind");
-        QualType Result = Replacement;
-        TemplateTypeParmTypeLoc NewTL =
-          TLB.push<TemplateTypeParmTypeLoc>(Result);
-        NewTL.setNameLoc(TL.getNameLoc());
-        return Result;
-      } else {
-        QualType Result = SemaRef.Context.getAutoType(
-            Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull());
-        AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
-        NewTL.setNameLoc(TL.getNameLoc());
-        return Result;
-      }
+      //
+      // FIXME: Is this still necessary?
+      if (!UseTypeSugar)
+        return TransformDesugared(TLB, TL);
+
+      QualType Result = SemaRef.Context.getAutoType(
+          Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull());
+      auto NewTL = TLB.push<AutoTypeLoc>(Result);
+      NewTL.setNameLoc(TL.getNameLoc());
+      return Result;
+    }
+
+    QualType TransformDeducedTemplateSpecializationType(
+        TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) {
+      if (!UseTypeSugar)
+        return TransformDesugared(TLB, TL);
+
+      QualType Result = SemaRef.Context.getDeducedTemplateSpecializationType(
+          TL.getTypePtr()->getTemplateName(),
+          Replacement, Replacement.isNull());
+      auto NewTL = TLB.push<DeducedTemplateSpecializationTypeLoc>(Result);
+      NewTL.setNameLoc(TL.getNameLoc());
+      return Result;
     }
 
     ExprResult TransformLambdaExpr(LambdaExpr *E) {
@@ -4104,7 +4121,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr
 
   if (!DependentDeductionDepth &&
       (Type.getType()->isDependentType() || Init->isTypeDependent())) {
-    Result = SubstituteAutoTransform(*this, QualType()).Apply(Type);
+    Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
     assert(!Result.isNull() && "substituting DependentTy can't fail");
     return DAR_Succeeded;
   }
@@ -4127,7 +4144,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr
         return DAR_FailedAlreadyDiagnosed;
       // FIXME: Support a non-canonical deduced type for 'auto'.
       Deduced = Context.getCanonicalType(Deduced);
-      Result = SubstituteAutoTransform(*this, Deduced).Apply(Type);
+      Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
       if (Result.isNull())
         return DAR_FailedAlreadyDiagnosed;
       return DAR_Succeeded;
@@ -4152,7 +4169,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr
       Loc, Loc, TemplParamPtr, Loc, nullptr);
 
   QualType FuncParam =
-      SubstituteAutoTransform(*this, TemplArg, /*UseAutoSugar*/false)
+      SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false)
           .Apply(Type);
   assert(!FuncParam.isNull() &&
          "substituting template parameter for 'auto' failed");
@@ -4167,7 +4184,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr
   // might acquire a matching type in the instantiation.
   auto DeductionFailed = [&]() -> DeduceAutoResult {
     if (Init->isTypeDependent()) {
-      Result = SubstituteAutoTransform(*this, QualType()).Apply(Type);
+      Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type);
       assert(!Result.isNull() && "substituting DependentTy can't fail");
       return DAR_Succeeded;
     }
@@ -4215,7 +4232,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr
       return DAR_FailedAlreadyDiagnosed;
   }
 
-  Result = SubstituteAutoTransform(*this, DeducedType).Apply(Type);
+  Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
   if (Result.isNull())
     return DAR_FailedAlreadyDiagnosed;
 
@@ -4238,22 +4255,22 @@ QualType Sema::SubstAutoType(QualType Ty
                              QualType TypeToReplaceAuto) {
   if (TypeToReplaceAuto->isDependentType())
     TypeToReplaceAuto = QualType();
-  return SubstituteAutoTransform(*this, TypeToReplaceAuto)
+  return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
       .TransformType(TypeWithAuto);
 }
 
-TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
-                             QualType TypeToReplaceAuto) {
+TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
+                                              QualType TypeToReplaceAuto) {
   if (TypeToReplaceAuto->isDependentType())
     TypeToReplaceAuto = QualType();
-  return SubstituteAutoTransform(*this, TypeToReplaceAuto)
+  return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
       .TransformType(TypeWithAuto);
 }
 
 QualType Sema::ReplaceAutoType(QualType TypeWithAuto,
                                QualType TypeToReplaceAuto) {
-  return SubstituteAutoTransform(*this, TypeToReplaceAuto,
-                                 /*UseAutoSugar*/ false)
+  return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto,
+                                        /*UseTypeSugar*/ false)
       .TransformType(TypeWithAuto);
 }
 

Added: cfe/trunk/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.post/expr.type.conv/p1.cpp?rev=294613&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.post/expr.type.conv/p1.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.post/expr.type.conv/p1.cpp Thu Feb  9 13:17:44 2017
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+template<typename T> struct A {
+  T t, u;
+};
+template<typename T> A(T, T) -> A<T>; // expected-note {{deduced conflicting types for parameter 'T'}}
+template<typename T> A(A<T>) -> A<T>; // expected-note {{requires 1 argument, but 2 were provided}}
+
+A a = A{1, 2};
+A b = A{3, 4.0}; // expected-error {{no viable constructor or deduction guide}}

Added: cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp?rev=294613&view=auto
==============================================================================
--- cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp (added)
+++ cfe/trunk/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp Thu Feb  9 13:17:44 2017
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+namespace std_example {
+  template <class T> struct A { // expected-note 2{{candidate}}
+    // FIXME: This is a bad way to diagnose redeclaration of a class member!
+    explicit A(const T &, ...) noexcept; // expected-note {{previous}} expected-note {{candidate}}
+    A(T &&, ...); // expected-error {{missing exception specification 'noexcept'}}
+  };
+
+  int i;
+  // FIXME: All but the first should be valid once we synthesize deduction guides from constructors.
+  A a1 = {i, i}; // expected-error {{no viable constructor or deduction guide}}
+  A a2{i, i}; // expected-error {{no viable constructor or deduction guide}}
+  A a3{0, i}; // expected-error {{no viable constructor or deduction guide}}
+  A a4 = {0, i}; // expected-error {{no viable constructor or deduction guide}}
+
+  template <class T> A(const T &, const T &) -> A<T &>;
+  template <class T> explicit A(T &&, T &&) -> A<T>;
+
+  A a5 = {0, 1}; // FIXME: Should be invalid, explicit deduction guide selected in copy-list-init
+  A a6{0, 1};
+  A a7 = {0, i}; // expected-note {{in instantiation of}}
+  A a8{0, i}; // expected-error {{no matching constructor}}
+
+  template <class T> struct B {
+    template <class U> using TA = T;
+    template <class U> B(U, TA<U>);
+  };
+  // FIXME: This is valid.
+  B b{(int *)0, (char *)0}; // expected-error {{no viable constructor or deduction guide}}
+}
+
+namespace check {
+  using namespace std_example;
+  template<typename T, typename U> constexpr bool same = false;
+  template<typename T> constexpr bool same<T, T> = true;
+
+  static_assert(same<decltype(a2), A<int>>);
+  static_assert(same<decltype(a3), A<int>>);
+  static_assert(same<decltype(a4), A<int>>);
+  static_assert(same<decltype(a6), A<int>>);
+  static_assert(same<decltype(b), A<char*>>);
+}

Modified: cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp Thu Feb  9 13:17:44 2017
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++1z -verify %s
+// expected-no-diagnostics
 
 namespace std_example {
   template<typename T, typename U = int> struct S {
@@ -10,5 +11,5 @@ namespace std_example {
     using type = short;
     operator type();
   };
-  S x{A()}; // expected-error {{not yet supported}}
+  S x{A()};
 }

Modified: cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp?rev=294613&r1=294612&r2=294613&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp (original)
+++ cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp Thu Feb  9 13:17:44 2017
@@ -1,6 +1,12 @@
 // RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s
 
-template<typename T> struct A {}; // expected-note 35{{declared here}}
+template <typename T> struct A { // expected-note 35{{declared here}}
+  constexpr A() {}
+  constexpr A(int) {}
+  constexpr operator int() { return 0; }
+};
+A() -> A<int>;
+A(int) -> A<int>;
 
 // Make sure we still correctly parse cases where a template can appear without arguments.
 namespace template_template_arg {
@@ -18,7 +24,7 @@ namespace template_template_arg {
   template<typename = ::A> struct YCCD {}; // expected-error {{requires template arguments}}
 
   // FIXME: replacing the invalid type with 'int' here is horrible
-  template <A a = A<int>()> class C { }; // expected-error {{requires template arguments}} expected-error {{not implicitly convertible to 'int'}}
+  template <A a = A<int>()> class C { }; // expected-error {{requires template arguments}}
   template<typename T = A> struct G { }; // expected-error {{requires template arguments}}
 }
 
@@ -27,7 +33,7 @@ namespace injected_class_name {
     A(T);
     void f(int) {
       A a = 1;
-      injected_class_name::A b = 1; // expected-error {{not yet supported}}
+      injected_class_name::A b = 1; // expected-error {{no viable constructor or deduction guide}}
     }
     void f(T);
   };
@@ -46,8 +52,8 @@ struct member {
 
   operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}}
 
-  static A x; // expected-error {{requires an initializer}}
-  static A y = 0; // expected-error {{not yet supported}}
+  static A x; // FIXME: We deduce A<int> from the initializer despite this not being a definition!
+  static constexpr A y = 0;
 };
 
 namespace in_typedef {
@@ -67,18 +73,18 @@ namespace stmt {
     // simple-declaration or cast. We also permit it in conditions,
     // for-range-declarations, member-declarations for static data members, and
     // new-expressions, because not doing so would be bizarre.
-    A local = 0; // expected-error {{not yet supported}}
-    static A local_static = 0; // expected-error {{not yet supported}}
-    static thread_local A thread_local_static = 0; // expected-error {{not yet supported}}
-    if (A a = 0) {} // expected-error {{not yet supported}}
-    if (A a = 0; a) {} // expected-error {{not yet supported}}
-    switch (A a = 0) {} // expected-error {{not yet supported}}
-    switch (A a = 0; a) {} // expected-error {{not yet supported}}
-    for (A a = 0; a; /**/) {} // expected-error {{not yet supported}}
-    for (/**/; A a = 0; /**/) {} // expected-error {{not yet supported}}
-    while (A a = 0) {} // expected-error {{not yet supported}}
+    A local = 0;
+    static A local_static = 0;
+    static thread_local A thread_local_static = 0;
+    if (A a = 0) {}
+    if (A a = 0; a) {}
+    switch (A a = 0) {} // expected-warning {{no case matching constant switch condition '0'}}
+    switch (A a = 0; a) {} // expected-warning {{no case matching constant switch condition '0'}}
+    for (A a = 0; a; /**/) {}
+    for (/**/; A a = 0; /**/) {}
+    while (A a = 0) {}
     int arr[3];
-    for (A a : arr) {} // expected-error {{not yet supported}}
+    for (A a : arr) {}
   }
 
   namespace std {
@@ -104,12 +110,12 @@ namespace expr {
     (void)(A)(n); // expected-error{{requires template arguments; argument deduction not allowed here}}
     (void)(A){n}; // expected-error{{requires template arguments; argument deduction not allowed here}}
 
-    (void)A(n); // expected-error {{not yet supported}}
-    (void)A{n}; // expected-error {{not yet supported}}
-    (void)new A(n); // expected-error {{not yet supported}}
-    (void)new A{n}; // expected-error {{not yet supported}}
+    (void)A(n);
+    (void)A{n};
+    (void)new A(n);
+    (void)new A{n};
     // FIXME: We should diagnose the lack of an initializer here.
-    (void)new A; // expected-error {{not yet supported}}
+    (void)new A;
   }
 }
 
@@ -121,55 +127,57 @@ namespace decl {
 
   auto k() -> A; // expected-error{{requires template arguments}}
 
-  A a; // expected-error {{requires an initializer}}
-  A b = 0; // expected-error {{not yet supported}}
-  const A c = 0; // expected-error {{not yet supported}}
+  A a; // FIXME: This is (technically) syntactically invalid.
+  A b = 0;
+  const A c = 0;
   A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
   A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
   A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}}
   A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}}
   A F::*pm = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
   A (*fp)() = 0; // expected-error {{cannot form function returning deduced class template specialization type}}
-  A [x, y] = 0; // expected-error {{cannot be declared with type 'A'}} expected-error {{not yet supported}}
+  A [x, y] = 0; // expected-error {{cannot be declared with type 'A'}} expected-error {{type 'A<int>' decomposes into 0 elements, but 2 names were provided}}
 }
 
 namespace typename_specifier {
   struct F {};
 
   void e() {
-    (void) typename ::A(0); // expected-error {{not yet supported}}
-    (void) typename ::A{0}; // expected-error {{not yet supported}}
-    new typename ::A(0); // expected-error {{not yet supported}}
-    new typename ::A{0}; // expected-error {{not yet supported}}
-    typename ::A a = 0; // expected-error {{not yet supported}}
-    const typename ::A b = 0; // expected-error {{not yet supported}}
-    if (typename ::A a = 0) {} // expected-error {{not yet supported}}
-    for (typename ::A a = 0; typename ::A b = 0; /**/) {} // expected-error 2{{not yet supported}}
+    (void) typename ::A(0);
+    (void) typename ::A{0};
+    new typename ::A(0);
+    new typename ::A{0};
+    typename ::A a = 0;
+    const typename ::A b = 0;
+    if (typename ::A a = 0) {}
+    for (typename ::A a = 0; typename ::A b = 0; /**/) {}
 
     (void)(typename ::A)(0); // expected-error{{requires template arguments; argument deduction not allowed here}}
     (void)(typename ::A){0}; // expected-error{{requires template arguments; argument deduction not allowed here}}
   }
-  typename ::A a = 0; // expected-error {{not yet supported}}
-  const typename ::A b = 0; // expected-error {{not yet supported}}
+  typename ::A a = 0;
+  const typename ::A b = 0;
   typename ::A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
   typename ::A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
   typename ::A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}}
   typename ::A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}}
   typename ::A F::*pm = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
   typename ::A (*fp)() = 0; // expected-error {{cannot form function returning deduced class template specialization type}}
-  typename ::A [x, y] = 0; // expected-error {{cannot be declared with type 'typename ::A'}} expected-error {{not yet supported}}
+  typename ::A [x, y] = 0; // expected-error {{cannot be declared with type 'typename ::A'}} expected-error {{type 'typename ::A<int>' (aka 'A<int>') decomposes into 0}}
 
   struct X { template<typename T> struct A {}; }; // expected-note 8{{template}}
 
+  // FIXME: We do not yet properly support class template argument deduction
+  // during template instantiation.
   template<typename T> void f() {
-    (void) typename T::A(0); // expected-error {{not yet supported}}
-    (void) typename T::A{0}; // expected-error {{not yet supported}}
-    new typename T::A(0); // expected-error {{not yet supported}}
-    new typename T::A{0}; // expected-error {{not yet supported}}
-    typename T::A a = 0; // expected-error {{not yet supported}}
-    const typename T::A b = 0; // expected-error {{not yet supported}}
-    if (typename T::A a = 0) {} // expected-error {{not yet supported}}
-    for (typename T::A a = 0; typename T::A b = 0; /**/) {} // expected-error 2{{not yet supported}}
+    (void) typename T::A(0); // expected-error {{no viable}}
+    (void) typename T::A{0}; // expected-error {{no viable}}
+    new typename T::A(0); // expected-error {{no viable}}
+    new typename T::A{0}; // expected-error {{no viable}}
+    typename T::A a = 0; // expected-error {{no viable}}
+    const typename T::A b = 0; // expected-error {{no viable}}
+    if (typename T::A a = 0) {} // expected-error {{no viable}}
+    for (typename T::A a = 0; typename T::A b = 0; /**/) {} // expected-error 2{{no viable}}
 
     {(void)(typename T::A)(0);} // expected-error{{refers to class template member}}
     {(void)(typename T::A){0};} // expected-error{{refers to class template member}}
@@ -179,7 +187,7 @@ namespace typename_specifier {
     {typename T::A arr[3] = 0;} // expected-error {{refers to class template member}}
     {typename T::A F::*pm = 0;} // expected-error {{refers to class template member}}
     {typename T::A (*fp)() = 0;} // expected-error {{refers to class template member}}
-    {typename T::A [x, y] = 0;} // expected-error {{cannot be declared with type 'typename T::A'}} expected-error {{not yet supported}}
+    {typename T::A [x, y] = 0;} // expected-error {{cannot be declared with type 'typename T::A'}} expected-error {{no viable}}
   }
   template void f<X>(); // expected-note {{instantiation of}}
 

Added: cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp?rev=294613&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp Thu Feb  9 13:17:44 2017
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+namespace std {
+  using size_t = decltype(sizeof(0));
+  template<typename T> struct initializer_list {
+    const T *p;
+    size_t n;
+    initializer_list();
+  };
+  // FIXME: This should probably not be necessary.
+  template<typename T> initializer_list(initializer_list<T>) -> initializer_list<T>;
+}
+
+template<typename T> constexpr bool has_type(...) { return false; }
+template<typename T> constexpr bool has_type(T) { return true; }
+
+std::initializer_list il = {1, 2, 3, 4, 5};
+
+template<typename T> struct vector {
+  template<typename Iter> vector(Iter, Iter);
+  vector(std::initializer_list<T>);
+};
+
+template<typename T> vector(std::initializer_list<T>) -> vector<T>;
+template<typename Iter> explicit vector(Iter, Iter) -> vector<typename Iter::value_type>;
+template<typename T> explicit vector(std::size_t, T) -> vector<T>;
+
+vector v1 = {1, 2, 3, 4};
+static_assert(has_type<vector<int>>(v1));
+
+struct iter { typedef char value_type; } it, end;
+vector v2(it, end);
+static_assert(has_type<vector<char>>(v2));
+
+vector v3(5, 5);
+static_assert(has_type<vector<int>>(v3));
+
+
+template<typename ...T> struct tuple { tuple(T...); };
+template<typename ...T> explicit tuple(T ...t) -> tuple<T...>;
+// FIXME: Remove
+template<typename ...T> tuple(tuple<T...>) -> tuple<T...>;
+
+const int n = 4;
+tuple ta = tuple{1, 'a', "foo", n};
+static_assert(has_type<tuple<int, char, const char*, int>>(ta));
+
+tuple tb{ta};
+static_assert(has_type<tuple<int, char, const char*, int>>(ta));
+
+// FIXME: This should be tuple<tuple<...>>;
+tuple tc = {ta};
+static_assert(has_type<tuple<int, char, const char*, int>>(ta));
+
+tuple td = {1, 2, 3};
+static_assert(has_type<tuple<int, char, const char*, int>>(ta));
+
+// FIXME: This is a GCC extension for now; if CWG don't allow this, at least
+// add a warning for it.
+namespace new_expr {
+  tuple<int> *p = new tuple{0};
+  tuple<float, float> *q = new tuple(1.0f, 2.0f);
+}
+
+namespace ambiguity {
+  template<typename T> struct A {};
+  A(unsigned short) -> A<int>; // expected-note {{candidate}}
+  A(short) -> A<int>; // expected-note {{candidate}}
+  A a = 0; // expected-error {{ambiguous deduction for template arguments of 'A'}}
+
+  template<typename T> struct B {};
+  template<typename T> B(T(&)(int)) -> B<int>; // expected-note {{candidate function [with T = int]}}
+  template<typename T> B(int(&)(T)) -> B<int>; // expected-note {{candidate function [with T = int]}}
+  int f(int);
+  B b = f; // expected-error {{ambiguous deduction for template arguments of 'B'}}
+}
+
+// FIXME: Revisit this once CWG decides if attributes, and [[deprecated]] in
+// particular, should be permitted here.
+namespace deprecated {
+  template<typename T> struct A { A(int); };
+  [[deprecated]] A(int) -> A<void>; // expected-note {{marked deprecated here}}
+  A a = 0; // expected-warning {{'<deduction guide for A>' is deprecated}}
+}




More information about the cfe-commits mailing list