]> granicus.if.org Git - clang/commitdiff
[c++1z] Synthesize implicit deduction guides from constructors on demand. Rank
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 14 Feb 2017 00:25:28 +0000 (00:25 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 14 Feb 2017 00:25:28 +0000 (00:25 +0000)
such guides below explicit ones, and ensure that references to the class's
template parameters are not treated as forwarding references.

We make a few tweaks to the wording in the current standard:
1) The constructor parameter list is copied faithfully to the deduction guide,
   without losing default arguments or a varargs ellipsis (which the standard
   wording loses by omission).
2) If the class template declares no constructors, we add a T() -> T<...> guide
   (which will only ever work if T has default arguments for all non-pack
   template parameters).
3) If the class template declares nothing that looks like a copy or move
   constructor, we add a T(T<...>) -> T<...> guide.
#2 and #3 follow from the "pretend we had a class type with these constructors"
philosophy for deduction guides.

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

14 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/DeclTemplate.h
include/clang/Sema/Sema.h
lib/AST/ASTContext.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/expr/expr.post/expr.type.conv/p1.cpp
test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p3.cpp
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
test/Parser/cxx1z-class-template-argument-deduction.cpp

index e6287dc0659c31ed1fc6c48cd14a85140293ae2c..6811281570888c30bffa3f3e60f7d97ec23a314b 100644 (file)
@@ -1357,6 +1357,8 @@ public:
       ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
       const IdentifierInfo *Name, ArrayRef<TemplateArgument> Args) const;
 
+  TemplateArgument getInjectedTemplateArg(NamedDecl *ParamDecl);
+
   /// Get a template argument list with one argument per template parameter
   /// in a template parameter list, such as for the injected class name of
   /// a class template.
index 1d9045aac341d197cbecd1d631dbef3b2fd8095a..6f81fcb4adf3cc9824f9fd0149176d9354aacacb 100644 (file)
@@ -1482,6 +1482,7 @@ public:
   
   using TemplateParmPosition::getDepth;
   using TemplateParmPosition::getPosition;
+  using TemplateParmPosition::setPosition;
   using TemplateParmPosition::getIndex;
 
   /// \brief Whether this template template parameter is a template
index 8ee53b209f15cd080fe99d16e8d1a2fa1b145aa4..dcb6c735239a5d0c5fa5407f85e5e64fac5292d8 100644 (file)
@@ -6759,6 +6759,11 @@ public:
   bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
                         bool Diagnose = true);
 
+  /// \brief Declare implicit deduction guides for a class template if we've
+  /// not already done so.
+  void DeclareImplicitDeductionGuides(TemplateDecl *Template,
+                                      SourceLocation Loc);
+
   QualType DeduceTemplateSpecializationFromInitializer(
       TypeSourceInfo *TInfo, const InitializedEntity &Entity,
       const InitializationKind &Kind, MultiExprArg Init);
index 1539a52e7fdd81855f05afd2bdb310c06219106e..84161409efdc83d3ed4d41517ff5623b107e759f 100644 (file)
@@ -3872,42 +3872,45 @@ ASTContext::getDependentTemplateSpecializationType(
   return QualType(T, 0);
 }
 
+TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) {
+  TemplateArgument Arg;
+  if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+    QualType ArgType = getTypeDeclType(TTP);
+    if (TTP->isParameterPack())
+      ArgType = getPackExpansionType(ArgType, None);
+
+    Arg = TemplateArgument(ArgType);
+  } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+    Expr *E = new (*this) DeclRefExpr(
+        NTTP, /*enclosing*/false,
+        NTTP->getType().getNonLValueExprType(*this),
+        Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation());
+
+    if (NTTP->isParameterPack())
+      E = new (*this) PackExpansionExpr(DependentTy, E, NTTP->getLocation(),
+                                        None);
+    Arg = TemplateArgument(E);
+  } else {
+    auto *TTP = cast<TemplateTemplateParmDecl>(Param);
+    if (TTP->isParameterPack())
+      Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>());
+    else
+      Arg = TemplateArgument(TemplateName(TTP));
+  }
+
+  if (Param->isTemplateParameterPack())
+    Arg = TemplateArgument::CreatePackCopy(*this, Arg);
+
+  return Arg;
+}
+
 void
 ASTContext::getInjectedTemplateArgs(const TemplateParameterList *Params,
                                     SmallVectorImpl<TemplateArgument> &Args) {
   Args.reserve(Args.size() + Params->size());
 
-  for (NamedDecl *Param : *Params) {
-    TemplateArgument Arg;
-    if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
-      QualType ArgType = getTypeDeclType(TTP);
-      if (TTP->isParameterPack())
-        ArgType = getPackExpansionType(ArgType, None);
-
-      Arg = TemplateArgument(ArgType);
-    } else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
-      Expr *E = new (*this) DeclRefExpr(
-          NTTP, /*enclosing*/false,
-          NTTP->getType().getNonLValueExprType(*this),
-          Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation());
-
-      if (NTTP->isParameterPack())
-        E = new (*this) PackExpansionExpr(DependentTy, E, NTTP->getLocation(),
-                                          None);
-      Arg = TemplateArgument(E);
-    } else {
-      auto *TTP = cast<TemplateTemplateParmDecl>(Param);
-      if (TTP->isParameterPack())
-        Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>());
-      else
-        Arg = TemplateArgument(TemplateName(TTP));
-    }
-
-    if (Param->isTemplateParameterPack())
-      Arg = TemplateArgument::CreatePackCopy(*this, Arg);
-
-    Args.push_back(Arg);
-  }
+  for (NamedDecl *Param : *Params)
+    Args.push_back(getInjectedTemplateArg(Param));
 }
 
 QualType ASTContext::getPackExpansionType(QualType Pattern,
index 32e7ae0d8d86633e22805aef96a967c034ed62f3..a455717c4d60768890fa9794aec3ed23b80e2129 100644 (file)
@@ -8242,45 +8242,27 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
     return QualType();
   }
 
+  // Can't deduce from dependent arguments.
+  if (Expr::hasAnyTypeDependentArguments(Inits))
+    return Context.DependentTy;
+
   // 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?
 
+  // Look up deduction guides, including those synthesized from constructors.
+  //
   // 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 constructor of the class template designated by the
+  //     template-name, a function template [...]
   //  - 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.
@@ -8307,8 +8289,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
   auto tryToResolveOverload =
       [&](bool OnlyListConstructors) -> OverloadingResult {
     Candidates.clear();
-    for (DeclAccessPair Pair : CtorsAndGuides) {
-      NamedDecl *D = Pair.getDecl()->getUnderlyingDecl();
+    for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
+      NamedDecl *D = (*I)->getUnderlyingDecl();
       if (D->isInvalidDecl())
         continue;
 
@@ -8357,10 +8339,11 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
       bool SuppressUserConversions = Kind.isCopyInit();
 
       if (TD)
-        AddTemplateOverloadCandidate(TD, Pair, /*ExplicitArgs*/ nullptr, Inits,
-                                     Candidates, SuppressUserConversions);
+        AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr,
+                                     Inits, Candidates,
+                                     SuppressUserConversions);
       else
-        AddOverloadCandidate(FD, Pair, Inits, Candidates,
+        AddOverloadCandidate(FD, I.getPair(), Inits, Candidates,
                              SuppressUserConversions);
     }
     return Candidates.BestViableFunction(*this, Kind.getLocation(), Best);
@@ -8371,7 +8354,21 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
   // C++11 [over.match.list]p1, per DR1467: for list-initialization, first
   // try initializer-list constructors.
   if (ListInit) {
-    if (ListInit->getNumInits() || !HasDefaultConstructor)
+    bool TryListConstructors = true;
+
+    // Try list constructors unless the list is empty and the class has one or
+    // more default constructors, in which case those constructors win.
+    if (!ListInit->getNumInits()) {
+      for (NamedDecl *D : Guides) {
+        auto *FD = dyn_cast<FunctionDecl>(D->getUnderlyingDecl());
+        if (FD && FD->getMinRequiredArguments() == 0) {
+          TryListConstructors = false;
+          break;
+        }
+      }
+    }
+
+    if (TryListConstructors)
       Result = tryToResolveOverload(/*OnlyListConstructor*/true);
     // Then unwrap the initializer list and try again considering all
     // constructors.
@@ -8393,13 +8390,18 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
     Candidates.NoteCandidates(*this, OCD_ViableCandidates, Inits);
     return QualType();
 
-  case OR_No_Viable_Function:
+  case OR_No_Viable_Function: {
+    CXXRecordDecl *Primary =
+        cast<ClassTemplateDecl>(Template)->getTemplatedDecl();
+    bool Complete =
+        isCompleteType(Kind.getLocation(), Context.getTypeDeclType(Primary));
     Diag(Kind.getLocation(),
          Complete ? diag::err_deduced_class_template_ctor_no_viable
                   : diag::err_deduced_class_template_incomplete)
-      << TemplateName << !CtorsAndGuides.empty();
+      << TemplateName << !Guides.empty();
     Candidates.NoteCandidates(*this, OCD_AllCandidates, Inits);
     return QualType();
+  }
 
   case OR_Deleted: {
     Diag(Kind.getLocation(), diag::err_deduced_class_template_deleted)
index 7066215b2b05460d945b5bfe7bbbf95774eb0488..9ea433ffe5cdac24dc03a49c57a906fec4067b39 100644 (file)
@@ -774,6 +774,7 @@ static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) {
 /// that need to be declared in the given declaration context, do so.
 static void DeclareImplicitMemberFunctionsWithName(Sema &S,
                                                    DeclarationName Name,
+                                                   SourceLocation Loc,
                                                    const DeclContext *DC) {
   if (!DC)
     return;
@@ -816,6 +817,10 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
     }
     break;
 
+  case DeclarationName::CXXDeductionGuideName:
+    S.DeclareImplicitDeductionGuides(Name.getCXXDeductionGuideTemplate(), Loc);
+    break;
+
   default:
     break;
   }
@@ -828,7 +833,8 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
 
   // Lazily declare C++ special member functions.
   if (S.getLangOpts().CPlusPlus)
-    DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), DC);
+    DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), R.getNameLoc(),
+                                           DC);
 
   // Perform lookup into this declaration context.
   DeclContext::lookup_result DR = DC->lookup(R.getLookupName());
@@ -1041,7 +1047,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
   if (isImplicitlyDeclaredMemberFunctionName(Name)) {
     for (Scope *PreS = S; PreS; PreS = PreS->getParent())
       if (DeclContext *DC = PreS->getEntity())
-        DeclareImplicitMemberFunctionsWithName(*this, Name, DC);
+        DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
   }
 
   // Implicitly declare member functions with the name we're looking for, if in
index 05caf923d0cc4331bb9ed08d29bc968b3742ca17..659d6226f3b8e8f96401e13115a1e8430d84f73b 100644 (file)
@@ -8991,6 +8991,14 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
     // C++14 [over.match.best]p1 section 2 bullet 3.
   }
 
+  //    -- F1 is generated from a deduction-guide and F2 is not
+  if (Cand1.Function && Cand2.Function && Cand1.Function->isDeductionGuide() &&
+      Cand1.Function->isImplicit() != Cand2.Function->isImplicit()) {
+    assert(Cand2.Function->isDeductionGuide() &&
+           "comparing deduction guide with non-deduction-guide");
+    return Cand2.Function->isImplicit();
+  }
+
   //    -- F1 is a non-template function and F2 is a function template
   //       specialization, or, if not that,
   bool Cand1IsSpecialization = Cand1.Function &&
index dd2dfe4235a9f8a5be316eb9bc93d160f641ae47..e86f287e0c592e0e8cdd21542e607b98717c4cbc 100644 (file)
@@ -1415,6 +1415,350 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
   return NewTemplate;
 }
 
+namespace {
+/// Transform to convert portions of a constructor declaration into the
+/// corresponding deduction guide, per C++1z [over.match.class.deduct]p1.
+struct ConvertConstructorToDeductionGuideTransform {
+  ConvertConstructorToDeductionGuideTransform(Sema &S,
+                                              ClassTemplateDecl *Template)
+      : SemaRef(S), Template(Template) {}
+
+  Sema &SemaRef;
+  ClassTemplateDecl *Template;
+
+  DeclContext *DC = Template->getDeclContext();
+  CXXRecordDecl *Primary = Template->getTemplatedDecl();
+  DeclarationName DeductionGuideName =
+      SemaRef.Context.DeclarationNames.getCXXDeductionGuideName(Template);
+
+  QualType DeducedType = SemaRef.Context.getTypeDeclType(Primary);
+
+  // Index adjustment to apply to convert depth-1 template parameters into
+  // depth-0 template parameters.
+  unsigned Depth1IndexAdjustment = Template->getTemplateParameters()->size();
+
+  /// Transform a constructor declaration into a deduction guide.
+  NamedDecl *transformConstructor(FunctionTemplateDecl *FTD, FunctionDecl *FD) {
+    SmallVector<TemplateArgument, 16> SubstArgs;
+
+    // C++ [over.match.class.deduct]p1:
+    // -- For each constructor of the class template designated by the
+    //    template-name, a function template with the following properties:
+
+    //    -- The template parameters are the template parameters of the class
+    //       template followed by the template parameters (including default
+    //       template arguments) of the constructor, if any.
+    TemplateParameterList *TemplateParams = Template->getTemplateParameters();
+    if (FTD) {
+      TemplateParameterList *InnerParams = FTD->getTemplateParameters();
+      SmallVector<NamedDecl *, 16> AllParams;
+      AllParams.reserve(TemplateParams->size() + InnerParams->size());
+      AllParams.insert(AllParams.begin(),
+                       TemplateParams->begin(), TemplateParams->end());
+      SubstArgs.reserve(InnerParams->size());
+
+      // Later template parameters could refer to earlier ones, so build up
+      // a list of substituted template arguments as we go.
+      for (NamedDecl *Param : *InnerParams) {
+        MultiLevelTemplateArgumentList Args;
+        Args.addOuterTemplateArguments(SubstArgs);
+        Args.addOuterTemplateArguments(None);
+        NamedDecl *NewParam = transformTemplateParameter(Param, Args);
+        if (!NewParam)
+          return nullptr;
+        AllParams.push_back(NewParam);
+        SubstArgs.push_back(SemaRef.Context.getCanonicalTemplateArgument(
+            SemaRef.Context.getInjectedTemplateArg(NewParam)));
+      }
+      TemplateParams = TemplateParameterList::Create(
+          SemaRef.Context, InnerParams->getTemplateLoc(),
+          InnerParams->getLAngleLoc(), AllParams, InnerParams->getRAngleLoc(),
+          /*FIXME: RequiresClause*/ nullptr);
+    }
+
+    // If we built a new template-parameter-list, track that we need to
+    // substitute references to the old parameters into references to the
+    // new ones.
+    MultiLevelTemplateArgumentList Args;
+    if (FTD) {
+      Args.addOuterTemplateArguments(SubstArgs);
+      Args.addOuterTemplateArguments(None);
+    }
+
+    FunctionProtoTypeLoc FPTL = FD->getTypeSourceInfo()->getTypeLoc()
+                                   .getAsAdjusted<FunctionProtoTypeLoc>();
+    assert(FPTL && "no prototype for constructor declaration");
+
+    // Transform the type of the function, adjusting the return type and
+    // replacing references to the old parameters with references to the
+    // new ones.
+    TypeLocBuilder TLB;
+    SmallVector<ParmVarDecl*, 8> Params;
+    QualType NewType = transformFunctionProtoType(TLB, FPTL, Params, Args);
+    if (NewType.isNull())
+      return nullptr;
+    TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
+
+    return buildDeductionGuide(TemplateParams, FD->isExplicit(), NewTInfo,
+                               FD->getLocStart(), FD->getLocation(),
+                               FD->getLocEnd());
+  }
+
+  /// Build a deduction guide with the specified parameter types.
+  NamedDecl *buildSimpleDeductionGuide(MutableArrayRef<QualType> ParamTypes) {
+    SourceLocation Loc = Template->getLocation();
+
+    // Build the requested type.
+    FunctionProtoType::ExtProtoInfo EPI;
+    EPI.HasTrailingReturn = true;
+    QualType Result = SemaRef.BuildFunctionType(DeducedType, ParamTypes, Loc,
+                                                DeductionGuideName, EPI);
+    TypeSourceInfo *TSI = SemaRef.Context.getTrivialTypeSourceInfo(Result, Loc);
+
+    FunctionProtoTypeLoc FPTL =
+        TSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
+
+    // Build the parameters, needed during deduction / substitution.
+    SmallVector<ParmVarDecl*, 4> Params;
+    for (auto T : ParamTypes) {
+      ParmVarDecl *NewParam = ParmVarDecl::Create(
+          SemaRef.Context, DC, Loc, Loc, nullptr, T,
+          SemaRef.Context.getTrivialTypeSourceInfo(T, Loc), SC_None, nullptr);
+      NewParam->setScopeInfo(0, Params.size());
+      FPTL.setParam(Params.size(), NewParam);
+      Params.push_back(NewParam);
+    }
+
+    return buildDeductionGuide(Template->getTemplateParameters(), false, TSI,
+                               Loc, Loc, Loc);
+  }
+
+private:
+  /// Transform a constructor template parameter into a deduction guide template
+  /// parameter, rebuilding any internal references to earlier parameters and
+  /// renumbering as we go.
+  NamedDecl *transformTemplateParameter(NamedDecl *TemplateParam,
+                                        MultiLevelTemplateArgumentList &Args) {
+    if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParam)) {
+      // TemplateTypeParmDecl's index cannot be changed after creation, so
+      // substitute it directly.
+      auto *NewTTP = TemplateTypeParmDecl::Create(
+          SemaRef.Context, DC, TTP->getLocStart(), TTP->getLocation(),
+          /*Depth*/0, Depth1IndexAdjustment + TTP->getIndex(),
+          TTP->getIdentifier(), TTP->wasDeclaredWithTypename(),
+          TTP->isParameterPack());
+      if (TTP->hasDefaultArgument()) {
+        TypeSourceInfo *InstantiatedDefaultArg =
+            SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,
+                              TTP->getDefaultArgumentLoc(), TTP->getDeclName());
+        if (InstantiatedDefaultArg)
+          NewTTP->setDefaultArgument(InstantiatedDefaultArg);
+      }
+      return NewTTP;
+    }
+
+    if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParam))
+      return transformTemplateParameterImpl(TTP, Args);
+
+    return transformTemplateParameterImpl(
+        cast<NonTypeTemplateParmDecl>(TemplateParam), Args);
+  }
+  template<typename TemplateParmDecl>
+  TemplateParmDecl *
+  transformTemplateParameterImpl(TemplateParmDecl *OldParam,
+                                 MultiLevelTemplateArgumentList &Args) {
+    // Ask the template instantiator to do the heavy lifting for us, then adjust
+    // the index of the parameter once it's done.
+    auto *NewParam =
+        cast_or_null<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args));
+    assert(NewParam->getDepth() == 0 && "unexpected template param depth");
+    NewParam->setPosition(NewParam->getPosition() + Depth1IndexAdjustment);
+    return NewParam;
+  }
+
+  QualType transformFunctionProtoType(TypeLocBuilder &TLB,
+                                      FunctionProtoTypeLoc TL,
+                                      SmallVectorImpl<ParmVarDecl*> &Params,
+                                      MultiLevelTemplateArgumentList &Args) {
+    SmallVector<QualType, 4> ParamTypes;
+    const FunctionProtoType *T = TL.getTypePtr();
+
+    //    -- The types of the function parameters are those of the constructor.
+    for (auto *OldParam : TL.getParams()) {
+      // If we're transforming a non-template constructor, just reuse its
+      // parameters as the parameters of the deduction guide. Otherwise, we
+      // need to transform their references to constructor template parameters.
+      ParmVarDecl *NewParam = Args.getNumLevels()
+                                  ? transformFunctionTypeParam(OldParam, Args)
+                                  : OldParam;
+      if (!NewParam)
+        return QualType();
+      ParamTypes.push_back(NewParam->getType());
+      Params.push_back(NewParam);
+    }
+
+    //    -- The return type is the class template specialization designated by
+    //       the template-name and template arguments corresponding to the
+    //       template parameters obtained from the class template.
+    //
+    // We use the injected-class-name type of the primary template instead.
+    // This has the convenient property that it is different from any type that
+    // the user can write in a deduction-guide (because they cannot enter the
+    // context of the template), so implicit deduction guides can never collide
+    // with explicit ones.
+    QualType ReturnType = DeducedType;
+    TLB.pushTypeSpec(ReturnType).setNameLoc(Primary->getLocation());
+
+    // Resolving a wording defect, we also inherit the variadicness of the
+    // constructor.
+    FunctionProtoType::ExtProtoInfo EPI;
+    EPI.Variadic = T->isVariadic();
+    EPI.HasTrailingReturn = true;
+
+    QualType Result = SemaRef.BuildFunctionType(
+        ReturnType, ParamTypes, TL.getLocStart(), DeductionGuideName, EPI);
+    if (Result.isNull())
+      return QualType();
+
+    FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result);
+    NewTL.setLocalRangeBegin(TL.getLocalRangeBegin());
+    NewTL.setLParenLoc(TL.getLParenLoc());
+    NewTL.setRParenLoc(TL.getRParenLoc());
+    NewTL.setExceptionSpecRange(SourceRange());
+    NewTL.setLocalRangeEnd(TL.getLocalRangeEnd());
+    for (unsigned I = 0, E = NewTL.getNumParams(); I != E; ++I)
+      NewTL.setParam(I, Params[I]);
+
+    return Result;
+  }
+
+  ParmVarDecl *
+  transformFunctionTypeParam(ParmVarDecl *OldParam,
+                             MultiLevelTemplateArgumentList &Args) {
+    TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo();
+    TypeSourceInfo *NewDI = SemaRef.SubstType(
+        OldDI, Args, OldParam->getLocation(), OldParam->getDeclName());
+    if (!NewDI)
+      return nullptr;
+
+    // Resolving a wording defect, we also inherit default arguments from the
+    // constructor.
+    ExprResult NewDefArg;
+    if (OldParam->hasDefaultArg()) {
+      NewDefArg = SemaRef.SubstExpr(OldParam->getDefaultArg(), Args);
+      if (NewDefArg.isInvalid())
+        return nullptr;
+    }
+
+    ParmVarDecl *NewParam = ParmVarDecl::Create(SemaRef.Context, DC,
+                                                OldParam->getInnerLocStart(),
+                                                OldParam->getLocation(),
+                                                OldParam->getIdentifier(),
+                                                NewDI->getType(),
+                                                NewDI,
+                                                OldParam->getStorageClass(),
+                                                NewDefArg.get());
+    NewParam->setScopeInfo(OldParam->getFunctionScopeDepth(),
+                           OldParam->getFunctionScopeIndex());
+    return NewParam;
+  }
+
+  NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams,
+                                 bool Explicit, TypeSourceInfo *TInfo,
+                                 SourceLocation LocStart, SourceLocation Loc,
+                                 SourceLocation LocEnd) {
+    // Build the implicit deduction guide template.
+    auto *Guide = FunctionDecl::Create(SemaRef.Context, DC, LocStart, Loc,
+                                       DeductionGuideName, TInfo->getType(),
+                                       TInfo, SC_None);
+    Guide->setImplicit();
+    if (Explicit)
+      Guide->setExplicitSpecified();
+    Guide->setRangeEnd(LocEnd);
+    Guide->setParams(
+        TInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams());
+
+    auto *GuideTemplate = FunctionTemplateDecl::Create(
+        SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide);
+    GuideTemplate->setImplicit();
+    Guide->setDescribedFunctionTemplate(GuideTemplate);
+
+    if (isa<CXXRecordDecl>(DC)) {
+      Guide->setAccess(AS_public);
+      GuideTemplate->setAccess(AS_public);
+    }
+
+    DC->addDecl(GuideTemplate);
+    return GuideTemplate;
+  }
+};
+}
+
+void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
+                                          SourceLocation Loc) {
+  DeclContext *DC = Template->getDeclContext();
+  if (DC->isDependentContext())
+    return;
+
+  ConvertConstructorToDeductionGuideTransform Transform(
+      *this, cast<ClassTemplateDecl>(Template));
+  if (!isCompleteType(Loc, Transform.DeducedType))
+    return;
+
+  // Check whether we've already declared deduction guides for this template.
+  // FIXME: Consider storing a flag on the template to indicate this.
+  auto Existing = DC->lookup(Transform.DeductionGuideName);
+  for (auto *D : Existing)
+    if (D->isImplicit())
+      return;
+
+  // In case we were expanding a pack when we attempted to declare deduction
+  // guides, turn off pack expansion for everything we're about to do.
+  ArgumentPackSubstitutionIndexRAII SubstIndex(*this, -1);
+  // Create a template instantiation record to track the "instantiation" of
+  // constructors into deduction guides.
+  // FIXME: Add a kind for this to give more meaningful diagnostics. But can
+  // this substitution process actually fail?
+  InstantiatingTemplate BuildingDeductionGuides(*this, Loc, Template);
+
+  // Convert declared constructors into deduction guide templates.
+  // FIXME: Skip constructors for which deduction must necessarily fail (those
+  // for which some class template parameter without a default argument never
+  // appears in a deduced context).
+  bool AddedAny = false;
+  bool AddedCopyOrMove = false;
+  for (NamedDecl *D : LookupConstructors(Transform.Primary)) {
+    D = D->getUnderlyingDecl();
+    if (D->isInvalidDecl() || D->isImplicit())
+      continue;
+    D = cast<NamedDecl>(D->getCanonicalDecl());
+
+    auto *FTD = dyn_cast<FunctionTemplateDecl>(D);
+    auto *FD = FTD ? FTD->getTemplatedDecl() : dyn_cast<FunctionDecl>(D);
+    // Class-scope explicit specializations (MS extension) do not result in
+    // deduction guides.
+    if (!FD || (!FTD && FD->isFunctionTemplateSpecialization()))
+      continue;
+
+    Transform.transformConstructor(FTD, FD);
+    AddedAny = true;
+
+    CXXConstructorDecl *CD = cast<CXXConstructorDecl>(FD);
+    AddedCopyOrMove |= CD->isCopyOrMoveConstructor();
+  }
+
+  // Synthesize an X() -> X<...> guide if there were no declared constructors.
+  // FIXME: The standard doesn't say (how) to do this.
+  if (!AddedAny)
+    Transform.buildSimpleDeductionGuide(None);
+
+  // Synthesize an X(X<...>) -> X<...> guide if there was no declared constructor
+  // resembling a copy or move constructor.
+  // FIXME: The standard doesn't say (how) to do this.
+  if (!AddedCopyOrMove)
+    Transform.buildSimpleDeductionGuide(Transform.DeducedType);
+}
+
 /// \brief Diagnose the presence of a default template argument on a
 /// template parameter, which is ill-formed in certain contexts.
 ///
index 48c8c2b64ebf87e0b8d07649d53470a0cbc2cbb2..5d78fd437e2a0e80f22e3d4e7c2a1333cfa9d98d 100644 (file)
@@ -963,6 +963,32 @@ bool Sema::isSameOrCompatibleFunctionType(CanQualType Param,
   return Param == Arg;
 }
 
+/// Get the index of the first template parameter that was originally from the
+/// innermost template-parameter-list. This is 0 except when we concatenate
+/// the template parameter lists of a class template and a constructor template
+/// when forming an implicit deduction guide.
+static unsigned getFirstInnerIndex(FunctionTemplateDecl *FTD) {
+  if (!FTD->isImplicit() || !FTD->getTemplatedDecl()->isDeductionGuide())
+    return 0;
+  return FTD->getDeclName().getCXXDeductionGuideTemplate()
+            ->getTemplateParameters()->size();
+}
+
+/// Determine whether a type denotes a forwarding reference.
+static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) {
+  // C++1z [temp.deduct.call]p3:
+  //   A forwarding reference is an rvalue reference to a cv-unqualified
+  //   template parameter that does not represent a template parameter of a
+  //   class template.
+  if (auto *ParamRef = Param->getAs<RValueReferenceType>()) {
+    if (ParamRef->getPointeeType().getQualifiers())
+      return false;
+    auto *TypeParm = ParamRef->getPointeeType()->getAs<TemplateTypeParmType>();
+    return TypeParm && TypeParm->getIndex() >= FirstInnerIndex;
+  }
+  return false;
+}
+
 /// \brief Deduce the template arguments by comparing the parameter type and
 /// the argument type (C++ [temp.deduct.type]).
 ///
@@ -1083,21 +1109,15 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
       //   taking the address of a function template (14.8.2.2) or when deducing
       //   template arguments from a function declaration (14.8.2.6) and Pi and
       //   Ai are parameters of the top-level parameter-type-list of P and A,
-      //   respectively, Pi is adjusted if it is an rvalue reference to a
-      //   cv-unqualified template parameter and Ai is an lvalue reference, in
+      //   respectively, Pi is adjusted if it is a forwarding reference and Ai
+      //   is an lvalue reference, in
       //   which case the type of Pi is changed to be the template parameter
       //   type (i.e., T&& is changed to simply T). [ Note: As a result, when
       //   Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be
       //   deduced as X&. - end note ]
       TDF &= ~TDF_TopLevelParameterTypeList;
-
-      if (const RValueReferenceType *ParamRef
-                                        = Param->getAs<RValueReferenceType>()) {
-        if (isa<TemplateTypeParmType>(ParamRef->getPointeeType()) &&
-            !ParamRef->getPointeeType().getQualifiers())
-          if (Arg->isLValueReferenceType())
-            Param = ParamRef->getPointeeType();
-      }
+      if (isForwardingReference(Param, 0) && Arg->isLValueReferenceType())
+        Param = Param->getPointeeType();
     }
   }
 
@@ -3185,12 +3205,9 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
 /// \returns true if the caller should not attempt to perform any template
 /// argument deduction based on this P/A pair because the argument is an
 /// overloaded function set that could not be resolved.
-static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
-                                          TemplateParameterList *TemplateParams,
-                                                      QualType &ParamType,
-                                                      QualType &ArgType,
-                                                      Expr *Arg,
-                                                      unsigned &TDF) {
+static bool AdjustFunctionParmAndArgTypesForDeduction(
+    Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex,
+    QualType &ParamType, QualType &ArgType, Expr *Arg, unsigned &TDF) {
   // C++0x [temp.deduct.call]p3:
   //   If P is a cv-qualified type, the top level cv-qualifiers of P's type
   //   are ignored for type deduction.
@@ -3221,13 +3238,10 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
       ArgType = Arg->getType();
     }
 
-    // C++0x [temp.deduct.call]p3:
-    //   If P is an rvalue reference to a cv-unqualified template
-    //   parameter and the argument is an lvalue, the type "lvalue
-    //   reference to A" is used in place of A for type deduction.
-    if (ParamRefType->isRValueReferenceType() &&
-        !ParamType.getQualifiers() &&
-        isa<TemplateTypeParmType>(ParamType) &&
+    // C++1z [temp.deduct.call]p3:
+    //   If P is a forwarding reference and the argument is an lvalue, the type
+    //   "lvalue reference to A" is used in place of A for type deduction.
+    if (isForwardingReference(QualType(ParamRefType, 0), FirstInnerIndex) &&
         Arg->isLValue())
       ArgType = S.Context.getLValueReferenceType(ArgType);
   } else {
@@ -3286,8 +3300,8 @@ hasDeducibleTemplateParameters(Sema &S, FunctionTemplateDecl *FunctionTemplate,
                                QualType T);
 
 static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
-    Sema &S, TemplateParameterList *TemplateParams, QualType ParamType,
-    Expr *Arg, TemplateDeductionInfo &Info,
+    Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex,
+    QualType ParamType, Expr *Arg, TemplateDeductionInfo &Info,
     SmallVectorImpl<DeducedTemplateArgument> &Deduced,
     SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
     bool DecomposedParam, unsigned ArgIdx, unsigned TDF);
@@ -3325,7 +3339,7 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList(
   if (ElTy->isDependentType()) {
     for (Expr *E : ILE->inits()) {
       if (auto Result = DeduceTemplateArgumentsFromCallArgument(
-              S, TemplateParams, ElTy, E, Info, Deduced, OriginalCallArgs, true,
+              S, TemplateParams, 0, ElTy, E, Info, Deduced, OriginalCallArgs, true,
               ArgIdx, TDF))
         return Result;
     }
@@ -3354,8 +3368,8 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList(
 /// \brief Perform template argument deduction per [temp.deduct.call] for a
 ///        single parameter / argument pair.
 static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
-    Sema &S, TemplateParameterList *TemplateParams, QualType ParamType,
-    Expr *Arg, TemplateDeductionInfo &Info,
+    Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex,
+    QualType ParamType, Expr *Arg, TemplateDeductionInfo &Info,
     SmallVectorImpl<DeducedTemplateArgument> &Deduced,
     SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
     bool DecomposedParam, unsigned ArgIdx, unsigned TDF) {
@@ -3364,8 +3378,8 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
 
   //   If P is a reference type [...]
   //   If P is a cv-qualified type [...]
-  if (AdjustFunctionParmAndArgTypesForDeduction(S, TemplateParams, ParamType,
-                                                ArgType, Arg, TDF))
+  if (AdjustFunctionParmAndArgTypesForDeduction(
+          S, TemplateParams, FirstInnerIndex, ParamType, ArgType, Arg, TDF))
     return Sema::TDK_Success;
 
   //   If [...] the argument is a non-empty initializer list [...]
@@ -3421,6 +3435,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
   FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
   unsigned NumParams = Function->getNumParams();
 
+  unsigned FirstInnerIndex = getFirstInnerIndex(FunctionTemplate);
+
   // C++ [temp.deduct.call]p1:
   //   Template argument deduction is done by comparing each function template
   //   parameter type (call it P) with the type of the corresponding argument
@@ -3475,7 +3491,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
 
     //   ... with the type of the corresponding argument
     return DeduceTemplateArgumentsFromCallArgument(
-        *this, TemplateParams, ParamType, Args[ArgIdx], Info, Deduced,
+        *this, TemplateParams, FirstInnerIndex, ParamType, Args[ArgIdx], Info, Deduced,
         OriginalCallArgs, /*Decomposed*/false, ArgIdx, /*TDF*/ 0);
   };
 
@@ -4203,7 +4219,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
 
     for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
       if (DeduceTemplateArgumentsFromCallArgument(
-              *this, TemplateParamsSt.get(), TemplArg, InitList->getInit(i),
+              *this, TemplateParamsSt.get(), 0, TemplArg, InitList->getInit(i),
               Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
               /*ArgIdx*/ 0, /*TDF*/ 0))
         return DeductionFailed();
@@ -4215,7 +4231,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
     }
 
     if (DeduceTemplateArgumentsFromCallArgument(
-            *this, TemplateParamsSt.get(), FuncParam, Init, Info, Deduced,
+            *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
             OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
       return DeductionFailed();
   }
index a69d54c5dc5e980fb48abbbe04b7554c1b58e860..a0e4d2999d9fe2317a94ac657b2b4f3b7d98eb95 100644 (file)
@@ -3553,6 +3553,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
   if (Tmpl->isDeleted())
     New->setDeletedAsWritten();
 
+  New->setImplicit(Tmpl->isImplicit());
+
   // Forward the mangling number from the template to the instantiated decl.
   SemaRef.Context.setManglingNumber(New,
                                     SemaRef.Context.getManglingNumber(Tmpl));
@@ -4952,6 +4954,21 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
           DC = FD->getLexicalDeclContext();
           continue;
         }
+        // An implicit deduction guide acts as if it's within the class template
+        // specialization described by its name and first N template params.
+        if (FD->isDeductionGuide() && FD->isImplicit()) {
+          TemplateDecl *TD = FD->getDeclName().getCXXDeductionGuideTemplate();
+          TemplateArgumentListInfo Args(Loc, Loc);
+          for (auto Arg : TemplateArgs.getInnermost().take_front(
+                                      TD->getTemplateParameters()->size()))
+            Args.addArgument(
+                getTrivialTemplateArgumentLoc(Arg, QualType(), Loc));
+          QualType T = CheckTemplateIdType(TemplateName(TD), Loc, Args);
+          if (T.isNull())
+            return nullptr;
+          DC = T->getAsCXXRecordDecl();
+          continue;
+        }
       }
 
       DC = DC->getParent();
index 1bdd52c037091aa1761d41b52ec955f14cb2046b..f3608bc378bc78a2f7151008078e092734ba7ad6 100644 (file)
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -std=c++1z -verify %s
 
-template<typename T> struct A {
+template<typename T> struct A { // expected-note 2{{candidate}}
   T t, u;
 };
 template<typename T> A(T, T) -> A<T>; // expected-note {{deduced conflicting types for parameter 'T'}}
index 0fc51fb54ed697a622462c6987c70344f155568e..4ed1d30b83d5ac097f276f51b7a3f32a09c31056 100644 (file)
@@ -1,33 +1,31 @@
 // 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'}}
+  template <class T> struct A {
+    explicit A(const T &, ...) noexcept; // expected-note {{explicit}} expected-note 2{{candidate}}
+    A(T &&, ...); // expected-note 2{{candidate}}
   };
 
   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}}
+  A a1 = {i, i}; // expected-error {{class template argument deduction for 'A' selected an explicit constructor for copy-list-initialization}}
+  A a2{i, i};
+  A a3{0, i};
+  A a4 = {0, i};
 
-  template <class T> A(const T &, const T &) -> A<T &>;
+  template <class T> A(const T &, const T &) -> A<T &>; // expected-note 2{{candidate}}
   template <class T> explicit A(T &&, T &&) -> A<T>; // expected-note {{explicit deduction guide declared here}}
 
+  // FIXME: The standard gives an incorrect explanation for why a5, a7, and a8 are ill-formed.
   A a5 = {0, 1}; // expected-error {{class template argument deduction for 'A' selected an explicit deduction guide}}
   A a6{0, 1};
-  A a7 = {0, i}; // expected-note {{in instantiation of}}
-  A a8{0, i}; // expected-error {{no matching constructor}}
+  A a7 = {0, i}; // expected-error {{ambiguous deduction}}
+  A a8{0, i}; // expected-error {{ambiguous deduction}}
 
   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}}
+  B b{(int *)0, (char *)0};
 }
 
 namespace check {
@@ -39,5 +37,5 @@ namespace check {
   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*>>);
+  static_assert(same<decltype(b), B<char*>>);
 }
index e470dd01664436787ea2940702195a9a41ed4bc6..edc657c252e8d1be76d3bdde73c5d69273efa0cf 100644 (file)
@@ -1,9 +1,39 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s
 
+// A forwarding reference is an rvalue reference to a cv-unqualified template
+// parameter that does not represent a template parameter of a class template.
+#if __cplusplus > 201402L
+namespace ClassTemplateParamNotForwardingRef {
+  // This is not a forwarding reference.
+  template<typename T> struct A { // expected-note {{candidate}}
+    A(T&&); // expected-note {{no known conversion from 'int' to 'int &&'}}
+  };
+  int n;
+  A a = n; // expected-error {{no viable constructor or deduction guide}}
 
-// If P is an rvalue reference to a cv-unqualified template parameter
-// and the argument is an lvalue, the type "lvalue reference to A" is
-// used in place of A for type deduction.
+  A b = 0;
+  A<int> *pb = &b;
+
+  // This is a forwarding reference.
+  template<typename T> A(T&&) -> A<T>;
+  A c = n;
+  A<int&> *pc = &c;
+
+  A d = 0;
+  A<int> *pd = &d;
+
+  template<typename T = void> struct B {
+    // This is a forwarding reference.
+    template<typename U> B(U &&);
+  };
+  B e = n;
+  B<void> *pe = &e;
+}
+#endif
+
+// If P is a forwarding reference and the argument is an lvalue, the type
+// "lvalue reference to A" is used in place of A for type deduction.
 template<typename T> struct X { };
 
 template<typename T> X<T> f0(T&&);
index ab8c867f60a040fae6eecf4d0c287620098c5eee..b7c7ef7500c531504d98a9064fd7c3f114a1b152 100644 (file)
@@ -31,11 +31,11 @@ namespace template_template_arg {
 namespace injected_class_name {
   template<typename T> struct A {
     A(T);
-    void f(int) {
+    void f(int) { // expected-note {{previous}}
       A a = 1;
-      injected_class_name::A b = 1; // expected-error {{no viable constructor or deduction guide}}
+      injected_class_name::A b = 1; // expected-note {{in instantiation of template class 'injected_class_name::A<int>'}}
     }
-    void f(T);
+    void f(T); // expected-error {{multiple overloads of 'f' instantiate to the same signature 'void (int)'}}
   };
   A<short> ai = 1;
   A<double>::A b(1); // expected-error {{constructor name}}
@@ -165,19 +165,17 @@ namespace typename_specifier {
   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 {{type 'typename ::A<int>' (aka 'A<int>') decomposes into 0}}
 
-  struct X { template<typename T> struct A {}; }; // expected-note 8{{template}}
+  struct X { template<typename T> struct A { A(T); }; }; // expected-note 8{{declared here}}
 
-  // 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 {{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);
+    (void) typename T::A{0};
+    new typename T::A(0);
+    new typename T::A{0};
+    typename T::A a = 0;
+    const typename T::A b = 0;
+    if (typename T::A a = 0) {} // expected-error {{value of type 'typename X::A<int>' (aka 'typename_specifier::X::A<int>') is not contextually convertible to 'bool'}}
+    for (typename T::A a = 0; typename T::A b = 0; /**/) {} // expected-error {{value of type 'typename X::A<int>' (aka 'typename_specifier::X::A<int>') is not contextually convertible to 'bool'}}
 
     {(void)(typename T::A)(0);} // expected-error{{refers to class template member}}
     {(void)(typename T::A){0};} // expected-error{{refers to class template member}}
@@ -187,7 +185,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 {{no viable}}
+    {typename T::A [x, y] = 0;} // expected-error {{cannot be declared with type 'typename T::A'}} expected-error {{type 'typename X::A<int>' (aka 'typename_specifier::X::A<int>') decomposes into 0}}
   }
   template void f<X>(); // expected-note {{instantiation of}}