diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp | 1321 |
1 files changed, 1123 insertions, 198 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp index ad1e89a..e9b3855 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp @@ -45,6 +45,26 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps, return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc()); } +namespace clang { +/// \brief [temp.constr.decl]p2: A template's associated constraints are +/// defined as a single constraint-expression derived from the introduced +/// constraint-expressions [ ... ]. +/// +/// \param Params The template parameter list and optional requires-clause. +/// +/// \param FD The underlying templated function declaration for a function +/// template. +static Expr *formAssociatedConstraints(TemplateParameterList *Params, + FunctionDecl *FD); +} + +static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params, + FunctionDecl *FD) { + // FIXME: Concepts: collect additional introduced constraint-expressions + assert(!FD && "Cannot collect constraints from function declaration yet."); + return Params->getRequiresClause(); +} + /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns NULL. @@ -222,6 +242,37 @@ TemplateNameKind Sema::isTemplateName(Scope *S, return TemplateKind; } +bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name, + SourceLocation NameLoc, + ParsedTemplateTy *Template) { + CXXScopeSpec SS; + bool MemberOfUnknownSpecialization = false; + + // We could use redeclaration lookup here, but we don't need to: the + // syntactic form of a deduction guide is enough to identify it even + // if we can't look up the template name at all. + LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName); + LookupTemplateName(R, S, SS, /*ObjectType*/QualType(), + /*EnteringContext*/false, MemberOfUnknownSpecialization); + + if (R.empty()) return false; + if (R.isAmbiguous()) { + // FIXME: Diagnose an ambiguity if we find at least one template. + R.suppressDiagnostics(); + return false; + } + + // We only treat template-names that name type templates as valid deduction + // guide names. + TemplateDecl *TD = R.getAsSingle<TemplateDecl>(); + if (!TD || !getAsTypeTemplateDecl(TD)) + return false; + + if (Template) + *Template = TemplateTy::make(TemplateName(TD)); + return true; +} + bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, @@ -404,6 +455,85 @@ void Sema::LookupTemplateName(LookupResult &Found, } } +void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, + SourceLocation Less, + SourceLocation Greater) { + if (TemplateName.isInvalid()) + return; + + DeclarationNameInfo NameInfo; + CXXScopeSpec SS; + LookupNameKind LookupKind; + + DeclContext *LookupCtx = nullptr; + NamedDecl *Found = nullptr; + + // Figure out what name we looked up. + if (auto *ME = dyn_cast<MemberExpr>(TemplateName.get())) { + NameInfo = ME->getMemberNameInfo(); + SS.Adopt(ME->getQualifierLoc()); + LookupKind = LookupMemberName; + LookupCtx = ME->getBase()->getType()->getAsCXXRecordDecl(); + Found = ME->getMemberDecl(); + } else { + auto *DRE = cast<DeclRefExpr>(TemplateName.get()); + NameInfo = DRE->getNameInfo(); + SS.Adopt(DRE->getQualifierLoc()); + LookupKind = LookupOrdinaryName; + Found = DRE->getFoundDecl(); + } + + // Try to correct the name by looking for templates and C++ named casts. + struct TemplateCandidateFilter : CorrectionCandidateCallback { + TemplateCandidateFilter() { + WantTypeSpecifiers = false; + WantExpressionKeywords = false; + WantRemainingKeywords = false; + WantCXXNamedCasts = true; + }; + bool ValidateCandidate(const TypoCorrection &Candidate) override { + if (auto *ND = Candidate.getCorrectionDecl()) + return isAcceptableTemplateName(ND->getASTContext(), ND, true); + return Candidate.isKeyword(); + } + }; + + DeclarationName Name = NameInfo.getName(); + if (TypoCorrection Corrected = + CorrectTypo(NameInfo, LookupKind, S, &SS, + llvm::make_unique<TemplateCandidateFilter>(), + CTK_ErrorRecovery, LookupCtx)) { + auto *ND = Corrected.getFoundDecl(); + if (ND) + ND = isAcceptableTemplateName(Context, ND, + /*AllowFunctionTemplates*/ true); + if (ND || Corrected.isKeyword()) { + if (LookupCtx) { + std::string CorrectedStr(Corrected.getAsString(getLangOpts())); + bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && + Name.getAsString() == CorrectedStr; + diagnoseTypo(Corrected, + PDiag(diag::err_non_template_in_member_template_id_suggest) + << Name << LookupCtx << DroppedSpecifier + << SS.getRange(), false); + } else { + diagnoseTypo(Corrected, + PDiag(diag::err_non_template_in_template_id_suggest) + << Name, false); + } + if (Found) + Diag(Found->getLocation(), + diag::note_non_template_in_template_id_found); + return; + } + } + + Diag(NameInfo.getLoc(), diag::err_non_template_in_template_id) + << Name << SourceRange(Less, Greater); + if (Found) + Diag(Found->getLocation(), diag::note_non_template_in_template_id_found); +} + /// ActOnDependentIdExpression - Handle a dependent id-expression that /// was just parsed. This is only possible with an explicit scope /// specifier naming a dependent type. @@ -1137,6 +1267,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } } + // TODO Memory management; associated constraints are not always stored. + Expr *const CurAC = formAssociatedConstraints(TemplateParams, nullptr); + if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. Skip this check // for a friend in a dependent context: the template parameter list itself @@ -1148,6 +1281,29 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, TPL_TemplateMatch)) return true; + // Check for matching associated constraints on redeclarations. + const Expr *const PrevAC = PrevClassTemplate->getAssociatedConstraints(); + const bool RedeclACMismatch = [&] { + if (!(CurAC || PrevAC)) + return false; // Nothing to check; no mismatch. + if (CurAC && PrevAC) { + llvm::FoldingSetNodeID CurACInfo, PrevACInfo; + CurAC->Profile(CurACInfo, Context, /*Canonical=*/true); + PrevAC->Profile(PrevACInfo, Context, /*Canonical=*/true); + if (CurACInfo == PrevACInfo) + return false; // All good; no mismatch. + } + return true; + }(); + + if (RedeclACMismatch) { + Diag(CurAC ? CurAC->getLocStart() : NameLoc, + diag::err_template_different_associated_constraints); + Diag(PrevAC ? PrevAC->getLocStart() : PrevClassTemplate->getLocation(), + diag::note_template_prev_declaration) << /*declaration*/0; + return true; + } + // C++ [temp.class]p4: // In a redeclaration, partial specialization, explicit // specialization or explicit instantiation of a class template, @@ -1174,8 +1330,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate(); assert(Tmpl && "original definition of a class template is not a " "class template?"); - makeMergedDefinitionVisible(Hidden, KWLoc); - makeMergedDefinitionVisible(Tmpl, KWLoc); + makeMergedDefinitionVisible(Hidden); + makeMergedDefinitionVisible(Tmpl); return Def; } @@ -1250,10 +1406,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, AddMsStructLayoutForRecord(NewClass); } + // Attach the associated constraints when the declaration will not be part of + // a decl chain. + Expr *const ACtoAttach = + PrevClassTemplate && ShouldAddRedecl ? nullptr : CurAC; + ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, - NewClass); + NewClass, ACtoAttach); if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); @@ -1333,6 +1494,379 @@ 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, + CXXConstructorDecl *CD) { + SmallVector<TemplateArgument, 16> SubstArgs; + + LocalInstantiationScope Scope(SemaRef); + + // 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.addOuterRetainedLevel(); + 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.addOuterRetainedLevel(); + } + + FunctionProtoTypeLoc FPTL = CD->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, CD->isExplicit(), NewTInfo, + CD->getLocStart(), CD->getLocation(), + CD->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); + } + SemaRef.CurrentInstantiationScope->InstantiatedLocal(TemplateParam, + NewTTP); + 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()) { + ParmVarDecl *NewParam = transformFunctionTypeParam(OldParam, Args); + 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; + if (!Args.getNumLevels()) + NewDI = OldDI; + else if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) { + // Expand out the one and only element in each inner pack. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, 0); + NewDI = + SemaRef.SubstType(PackTL.getPatternLoc(), Args, + OldParam->getLocation(), OldParam->getDeclName()); + if (!NewDI) return nullptr; + NewDI = + SemaRef.CheckPackExpansion(NewDI, PackTL.getEllipsisLoc(), + PackTL.getTypePtr()->getNumExpansions()); + } else + NewDI = SemaRef.SubstType(OldDI, Args, OldParam->getLocation(), + OldParam->getDeclName()); + if (!NewDI) + return nullptr; + + // Canonicalize the type. This (for instance) replaces references to + // typedef members of the current instantiations with the definitions of + // those typedefs, avoiding triggering instantiation of the deduced type + // during deduction. + // FIXME: It would be preferable to retain type sugar and source + // information here (and handle this in substitution instead). + NewDI = SemaRef.Context.getTrivialTypeSourceInfo( + SemaRef.Context.getCanonicalType(NewDI->getType()), + OldParam->getLocation()); + + // Resolving a wording defect, we also inherit default arguments from the + // constructor. + ExprResult NewDefArg; + if (OldParam->hasDefaultArg()) { + NewDefArg = Args.getNumLevels() + ? SemaRef.SubstExpr(OldParam->getDefaultArg(), Args) + : OldParam->getDefaultArg(); + 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) { + DeclarationNameInfo Name(DeductionGuideName, Loc); + ArrayRef<ParmVarDecl *> Params = + TInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(); + + // Build the implicit deduction guide template. + auto *Guide = + CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, Explicit, + Name, TInfo->getType(), TInfo, LocEnd); + Guide->setImplicit(); + Guide->setParams(Params); + + for (auto *Param : Params) + Param->setDeclContext(Guide); + + 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 *CD = + dyn_cast_or_null<CXXConstructorDecl>(FTD ? FTD->getTemplatedDecl() : D); + // Class-scope explicit specializations (MS extension) do not result in + // deduction guides. + if (!CD || (!FTD && CD->isFunctionTemplateSpecialization())) + continue; + + Transform.transformConstructor(FTD, CD); + AddedAny = true; + + 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. /// @@ -1665,7 +2199,6 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { typedef RecursiveASTVisitor<DependencyChecker> super; unsigned Depth; - bool FindLessThanDepth; // Whether we're looking for a use of a template parameter that makes the // overall construct type-dependent / a dependent type. This is strictly @@ -1676,16 +2209,25 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { bool Match; SourceLocation MatchLoc; - DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent, - bool FindLessThanDepth = false) - : Depth(Depth), FindLessThanDepth(FindLessThanDepth), - IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) {} + DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent) + : Depth(Depth), IgnoreNonTypeDependent(IgnoreNonTypeDependent), + Match(false) {} DependencyChecker(TemplateParameterList *Params, bool IgnoreNonTypeDependent) - : DependencyChecker(Params->getDepth(), IgnoreNonTypeDependent) {} + : IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) { + NamedDecl *ND = Params->getParam(0); + if (TemplateTypeParmDecl *PD = dyn_cast<TemplateTypeParmDecl>(ND)) { + Depth = PD->getDepth(); + } else if (NonTypeTemplateParmDecl *PD = + dyn_cast<NonTypeTemplateParmDecl>(ND)) { + Depth = PD->getDepth(); + } else { + Depth = cast<TemplateTemplateParmDecl>(ND)->getDepth(); + } + } bool Matches(unsigned ParmDepth, SourceLocation Loc = SourceLocation()) { - if (FindLessThanDepth ^ (ParmDepth >= Depth)) { + if (ParmDepth >= Depth) { Match = true; MatchLoc = Loc; return true; @@ -1802,8 +2344,9 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context, /// matching template parameters to scope specifiers in friend /// declarations. /// -/// \param IsExplicitSpecialization will be set true if the entity being -/// declared is an explicit specialization, false otherwise. +/// \param IsMemberSpecialization will be set true if the scope specifier +/// denotes a fully-specialized type, and therefore this is a declaration of +/// a member specialization. /// /// \returns the template parameter list, if any, that corresponds to the /// name that is preceded by the scope specifier @p SS. This template @@ -1815,8 +2358,8 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend, - bool &IsExplicitSpecialization, bool &Invalid) { - IsExplicitSpecialization = false; + bool &IsMemberSpecialization, bool &Invalid) { + IsMemberSpecialization = false; Invalid = false; // The sequence of nested types to which we will match up the template @@ -1926,7 +2469,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( Diag(DeclLoc, diag::err_specialize_member_of_template) << !Recovery << Range; Invalid = true; - IsExplicitSpecialization = false; + IsMemberSpecialization = false; return true; } @@ -1996,7 +2539,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (Record->getTemplateSpecializationKind() != TSK_ExplicitSpecialization && TypeIdx == NumTypes - 1) - IsExplicitSpecialization = true; + IsMemberSpecialization = true; continue; } @@ -2030,9 +2573,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (NeedEmptyTemplateHeader) { // If we're on the last of the types, and we need a 'template<>' header - // here, then it's an explicit specialization. + // here, then it's a member specialization. if (TypeIdx == NumTypes - 1) - IsExplicitSpecialization = true; + IsMemberSpecialization = true; if (ParamIdx < ParamLists.size()) { if (ParamLists[ParamIdx]->size() > 0) { @@ -2105,7 +2648,6 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (TemplateId && !IsFriend) { // We don't have a template header for the declaration itself, but we // should. - IsExplicitSpecialization = true; DiagnoseMissingExplicitSpecialization(SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)); @@ -2264,6 +2806,101 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, llvm_unreachable("unexpected BuiltinTemplateDecl!"); } +/// Determine whether this alias template is "enable_if_t". +static bool isEnableIfAliasTemplate(TypeAliasTemplateDecl *AliasTemplate) { + return AliasTemplate->getName().equals("enable_if_t"); +} + +/// Collect all of the separable terms in the given condition, which +/// might be a conjunction. +/// +/// FIXME: The right answer is to convert the logical expression into +/// disjunctive normal form, so we can find the first failed term +/// within each possible clause. +static void collectConjunctionTerms(Expr *Clause, + SmallVectorImpl<Expr *> &Terms) { + if (auto BinOp = dyn_cast<BinaryOperator>(Clause->IgnoreParenImpCasts())) { + if (BinOp->getOpcode() == BO_LAnd) { + collectConjunctionTerms(BinOp->getLHS(), Terms); + collectConjunctionTerms(BinOp->getRHS(), Terms); + } + + return; + } + + Terms.push_back(Clause); +} + +// The ranges-v3 library uses an odd pattern of a top-level "||" with +// a left-hand side that is value-dependent but never true. Identify +// the idiom and ignore that term. +static Expr *lookThroughRangesV3Condition(Preprocessor &PP, Expr *Cond) { + // Top-level '||'. + auto *BinOp = dyn_cast<BinaryOperator>(Cond->IgnoreParenImpCasts()); + if (!BinOp) return Cond; + + if (BinOp->getOpcode() != BO_LOr) return Cond; + + // With an inner '==' that has a literal on the right-hand side. + Expr *LHS = BinOp->getLHS(); + auto *InnerBinOp = dyn_cast<BinaryOperator>(LHS->IgnoreParenImpCasts()); + if (!InnerBinOp) return Cond; + + if (InnerBinOp->getOpcode() != BO_EQ || + !isa<IntegerLiteral>(InnerBinOp->getRHS())) + return Cond; + + // If the inner binary operation came from a macro expansion named + // CONCEPT_REQUIRES or CONCEPT_REQUIRES_, return the right-hand side + // of the '||', which is the real, user-provided condition. + SourceLocation Loc = InnerBinOp->getExprLoc(); + if (!Loc.isMacroID()) return Cond; + + StringRef MacroName = PP.getImmediateMacroName(Loc); + if (MacroName == "CONCEPT_REQUIRES" || MacroName == "CONCEPT_REQUIRES_") + return BinOp->getRHS(); + + return Cond; +} + +/// Find the failed subexpression within enable_if, and describe it +/// with a string. +static std::pair<Expr *, std::string> +findFailedEnableIfCondition(Sema &S, Expr *Cond) { + Cond = lookThroughRangesV3Condition(S.PP, Cond); + + // Separate out all of the terms in a conjunction. + SmallVector<Expr *, 4> Terms; + collectConjunctionTerms(Cond, Terms); + + // Determine which term failed. + Expr *FailedCond = nullptr; + for (Expr *Term : Terms) { + // The initialization of the parameter from the argument is + // a constant-evaluated context. + EnterExpressionEvaluationContext ConstantEvaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + bool Succeeded; + if (Term->EvaluateAsBooleanCondition(Succeeded, S.Context) && + !Succeeded) { + FailedCond = Term->IgnoreParenImpCasts(); + break; + } + } + + if (!FailedCond) + FailedCond = Cond->IgnoreParenImpCasts(); + + std::string Description; + { + llvm::raw_string_ostream Out(Description); + FailedCond->printPretty(Out, nullptr, + PrintingPolicy(S.Context.getLangOpts())); + } + return { FailedCond, Description }; +} + QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { @@ -2310,12 +2947,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, if (Pattern->isInvalidDecl()) return QualType(); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted); + TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack, + Converted); // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs); unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth(); for (unsigned I = 0; I < Depth; ++I) TemplateArgLists.addOuterTemplateArguments(None); @@ -2328,8 +2965,42 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, CanonType = SubstType(Pattern->getUnderlyingType(), TemplateArgLists, AliasTemplate->getLocation(), AliasTemplate->getDeclName()); - if (CanonType.isNull()) + if (CanonType.isNull()) { + // If this was enable_if and we failed to find the nested type + // within enable_if in a SFINAE context, dig out the specific + // enable_if condition that failed and present that instead. + if (isEnableIfAliasTemplate(AliasTemplate)) { + if (auto DeductionInfo = isSFINAEContext()) { + if (*DeductionInfo && + (*DeductionInfo)->hasSFINAEDiagnostic() && + (*DeductionInfo)->peekSFINAEDiagnostic().second.getDiagID() == + diag::err_typename_nested_not_found_enable_if && + TemplateArgs[0].getArgument().getKind() + == TemplateArgument::Expression) { + Expr *FailedCond; + std::string FailedDescription; + std::tie(FailedCond, FailedDescription) = + findFailedEnableIfCondition( + *this, TemplateArgs[0].getSourceExpression()); + + // Remove the old SFINAE diagnostic. + PartialDiagnosticAt OldDiag = + {SourceLocation(), PartialDiagnostic::NullDiagnostic()}; + (*DeductionInfo)->takeSFINAEDiagnostic(OldDiag); + + // Add a new SFINAE diagnostic specifying which condition + // failed. + (*DeductionInfo)->addSFINAEDiagnostic( + OldDiag.first, + PDiag(diag::err_typename_nested_not_found_requirement) + << FailedDescription + << FailedCond->getSourceRange()); + } + } + } + return QualType(); + } } else if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, InstantiationDependent)) { @@ -2402,6 +3073,13 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext()); } + if (Decl->getSpecializationKind() == TSK_Undeclared) { + MultiLevelTemplateArgumentList TemplateArgLists; + TemplateArgLists.addOuterTemplateArguments(Converted); + InstantiateAttrsForDecl(TemplateArgLists, ClassTemplate->getTemplatedDecl(), + Decl); + } + // Diagnose uses of this specialization. (void)DiagnoseUseOfDecl(Decl, TemplateLoc); @@ -2421,14 +3099,51 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, TypeResult Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - TemplateTy TemplateD, SourceLocation TemplateLoc, + TemplateTy TemplateD, IdentifierInfo *TemplateII, + SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc, - bool IsCtorOrDtorName) { + bool IsCtorOrDtorName, bool IsClassName) { if (SS.isInvalid()) return true; + if (!IsCtorOrDtorName && !IsClassName && SS.isSet()) { + DeclContext *LookupCtx = computeDeclContext(SS, /*EnteringContext*/false); + + // C++ [temp.res]p3: + // A qualified-id that refers to a type and in which the + // nested-name-specifier depends on a template-parameter (14.6.2) + // shall be prefixed by the keyword typename to indicate that the + // qualified-id denotes a type, forming an + // elaborated-type-specifier (7.1.5.3). + if (!LookupCtx && isDependentScopeSpecifier(SS)) { + Diag(SS.getBeginLoc(), diag::err_typename_missing_template) + << SS.getScopeRep() << TemplateII->getName(); + // Recover as if 'typename' were specified. + // FIXME: This is not quite correct recovery as we don't transform SS + // into the corresponding dependent form (and we don't diagnose missing + // 'template' keywords within SS as a result). + return ActOnTypenameType(nullptr, SourceLocation(), SS, TemplateKWLoc, + TemplateD, TemplateII, TemplateIILoc, LAngleLoc, + TemplateArgsIn, RAngleLoc); + } + + // Per C++ [class.qual]p2, if the template-id was an injected-class-name, + // it's not actually allowed to be used as a type in most cases. Because + // we annotate it before we know whether it's valid, we have to check for + // this case here. + auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx); + if (LookupRD && LookupRD->getIdentifier() == TemplateII) { + Diag(TemplateIILoc, + TemplateKWLoc.isInvalid() + ? diag::err_out_of_line_qualified_id_type_names_constructor + : diag::ext_out_of_line_qualified_id_type_names_constructor) + << TemplateII << 0 /*injected-class-name used as template name*/ + << 1 /*if any keyword was present, it was 'template'*/; + } + } + TemplateName Template = TemplateD.get(); // Translate the parser's template argument list in our AST format. @@ -2448,7 +3163,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, SpecTL.setElaboratedKeywordLoc(SourceLocation()); SpecTL.setQualifierLoc(SS.getWithLocInContext(Context)); SpecTL.setTemplateKeywordLoc(TemplateKWLoc); - SpecTL.setTemplateNameLoc(TemplateLoc); + SpecTL.setTemplateNameLoc(TemplateIILoc); SpecTL.setLAngleLoc(LAngleLoc); SpecTL.setRAngleLoc(RAngleLoc); for (unsigned I = 0, N = SpecTL.getNumArgs(); I != N; ++I) @@ -2456,8 +3171,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } - QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); - + QualType Result = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs); if (Result.isNull()) return true; @@ -2466,7 +3180,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateSpecializationTypeLoc SpecTL = TLB.push<TemplateSpecializationTypeLoc>(Result); SpecTL.setTemplateKeywordLoc(TemplateKWLoc); - SpecTL.setTemplateNameLoc(TemplateLoc); + SpecTL.setTemplateNameLoc(TemplateIILoc); SpecTL.setLAngleLoc(LAngleLoc); SpecTL.setRAngleLoc(RAngleLoc); for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i) @@ -2690,6 +3404,23 @@ static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { S.Diag(Template->getLocation(), diag::note_template_decl_here); } +static void +noteNonDeducibleParameters(Sema &S, TemplateParameterList *TemplateParams, + const llvm::SmallBitVector &DeducibleParams) { + for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { + if (!DeducibleParams[I]) { + NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); + if (Param->getDeclName()) + S.Diag(Param->getLocation(), diag::note_non_deducible_parameter) + << Param->getDeclName(); + else + S.Diag(Param->getLocation(), diag::note_non_deducible_parameter) + << "(anonymous)"; + } + } +} + + template<typename PartialSpecDecl> static void checkTemplatePartialSpecialization(Sema &S, PartialSpecDecl *Partial) { @@ -2717,19 +3448,7 @@ static void checkTemplatePartialSpecialization(Sema &S, << (NumNonDeducible > 1) << SourceRange(Partial->getLocation(), Partial->getTemplateArgsAsWritten()->RAngleLoc); - for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { - if (!DeducibleParams[I]) { - NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); - if (Param->getDeclName()) - S.Diag(Param->getLocation(), - diag::note_partial_spec_unused_parameter) - << Param->getDeclName(); - else - S.Diag(Param->getLocation(), - diag::note_partial_spec_unused_parameter) - << "(anonymous)"; - } - } + noteNonDeducibleParameters(S, TemplateParams, DeducibleParams); } } @@ -2743,6 +3462,29 @@ void Sema::CheckTemplatePartialSpecialization( checkTemplatePartialSpecialization(*this, Partial); } +void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) { + // C++1z [temp.param]p11: + // A template parameter of a deduction guide template that does not have a + // default-argument shall be deducible from the parameter-type-list of the + // deduction guide template. + auto *TemplateParams = TD->getTemplateParameters(); + llvm::SmallBitVector DeducibleParams(TemplateParams->size()); + MarkDeducedTemplateParameters(TD, DeducibleParams); + for (unsigned I = 0; I != TemplateParams->size(); ++I) { + // A parameter pack is deducible (to an empty pack). + auto *Param = TemplateParams->getParam(I); + if (Param->isParameterPack() || hasVisibleDefaultArgument(Param)) + DeducibleParams[I] = true; + } + + if (!DeducibleParams.all()) { + unsigned NumNonDeducible = DeducibleParams.size() - DeducibleParams.count(); + Diag(TD->getLocation(), diag::err_deduction_guide_template_not_deducible) + << (NumNonDeducible > 1); + noteNonDeducibleParameters(*this, TemplateParams, DeducibleParams); + } +} + DeclResult Sema::ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, StorageClass SC, @@ -3224,7 +3966,8 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, - TemplateTy &Result) { + TemplateTy &Result, + bool AllowInjectedClassName) { if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent()) Diag(TemplateKWLoc, getLangOpts().CPlusPlus11 ? @@ -3272,6 +4015,24 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, return TNK_Non_template; } else { // We found something; return it. + auto *LookupRD = dyn_cast<CXXRecordDecl>(LookupCtx); + if (!AllowInjectedClassName && SS.isSet() && LookupRD && + Name.getKind() == UnqualifiedId::IK_Identifier && Name.Identifier && + LookupRD->getIdentifier() == Name.Identifier) { + // C++14 [class.qual]p2: + // In a lookup in which function names are not ignored and the + // nested-name-specifier nominates a class C, if the name specified + // [...] is the injected-class-name of C, [...] the name is instead + // considered to name the constructor + // + // We don't get here if naming the constructor would be valid, so we + // just reject immediately and recover by treating the + // injected-class-name as naming the template. + Diag(Name.getLocStart(), + diag::ext_out_of_line_qualified_id_type_names_constructor) + << Name.Identifier << 0 /*injected-class-name used as template name*/ + << 1 /*'template' keyword was used*/; + } return TNK; } } @@ -3326,7 +4087,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, SourceRange SR = AL.getSourceRange(); TemplateName Name = Arg.getAsTemplate(); Diag(SR.getBegin(), diag::err_template_missing_args) - << Name << SR; + << (int)getTemplateNameKindForDiagnostics(Name) << Name << SR; if (TemplateDecl *Decl = Name.getAsTemplateDecl()) Diag(Decl->getLocation(), diag::note_template_decl_here); @@ -3388,6 +4149,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, } } // fallthrough + LLVM_FALLTHROUGH; } default: { // We have a template type parameter but the template argument @@ -3520,8 +4282,8 @@ SubstDefaultTemplateArgument(Sema &SemaRef, for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) TemplateArgLists.addOuterTemplateArguments(None); - EnterExpressionEvaluationContext ConstantEvaluated(SemaRef, - Sema::ConstantEvaluated); + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists); } @@ -3657,6 +4419,39 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, TempTempParm->getDefaultArgument().getTemplateNameLoc()); } +/// Convert a template-argument that we parsed as a type into a template, if +/// possible. C++ permits injected-class-names to perform dual service as +/// template template arguments and as template type arguments. +static TemplateArgumentLoc convertTypeTemplateArgumentToTemplate(TypeLoc TLoc) { + // Extract and step over any surrounding nested-name-specifier. + NestedNameSpecifierLoc QualLoc; + if (auto ETLoc = TLoc.getAs<ElaboratedTypeLoc>()) { + if (ETLoc.getTypePtr()->getKeyword() != ETK_None) + return TemplateArgumentLoc(); + + QualLoc = ETLoc.getQualifierLoc(); + TLoc = ETLoc.getNamedTypeLoc(); + } + + // If this type was written as an injected-class-name, it can be used as a + // template template argument. + if (auto InjLoc = TLoc.getAs<InjectedClassNameTypeLoc>()) + return TemplateArgumentLoc(InjLoc.getTypePtr()->getTemplateName(), + QualLoc, InjLoc.getNameLoc()); + + // If this type was written as an injected-class-name, it may have been + // converted to a RecordType during instantiation. If the RecordType is + // *not* wrapped in a TemplateSpecializationType and denotes a class + // template specialization, it must have come from an injected-class-name. + if (auto RecLoc = TLoc.getAs<RecordTypeLoc>()) + if (auto *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(RecLoc.getDecl())) + return TemplateArgumentLoc(TemplateName(CTSD->getSpecializedTemplate()), + QualLoc, RecLoc.getNameLoc()); + + return TemplateArgumentLoc(); +} + /// \brief Check that the given template argument corresponds to the given /// template parameter. /// @@ -3863,6 +4658,17 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return true; } + // C++1z [temp.local]p1: (DR1004) + // When [the injected-class-name] is used [...] as a template-argument for + // a template template-parameter [...] it refers to the class template + // itself. + if (Arg.getArgument().getKind() == TemplateArgument::Type) { + TemplateArgumentLoc ConvertedArg = convertTypeTemplateArgumentToTemplate( + Arg.getTypeSourceInfo()->getTypeLoc()); + if (!ConvertedArg.getArgument().isNull()) + Arg = ConvertedArg; + } + switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: llvm_unreachable("Should never see a NULL template argument here"); @@ -3911,9 +4717,7 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template, TemplateArgs.getRAngleLoc()); S.Diag(TemplateLoc, diag::err_template_arg_list_different_arity) << (NumArgs > NumParams) - << (isa<ClassTemplateDecl>(Template)? 0 : - isa<FunctionTemplateDecl>(Template)? 1 : - isa<TemplateTemplateParmDecl>(Template)? 2 : 3) + << (int)S.getTemplateNameKindForDiagnostics(TemplateName(Template)) << Template << Range; S.Diag(Template->getLocation(), diag::note_template_decl_here) << Params->getSourceRange(); @@ -3978,11 +4782,11 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, /// \brief Check that the given template argument list is well-formed /// for specializing the given template. -bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, - SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs, - bool PartialTemplateArgs, - SmallVectorImpl<TemplateArgument> &Converted) { +bool Sema::CheckTemplateArgumentList( + TemplateDecl *Template, SourceLocation TemplateLoc, + TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, + SmallVectorImpl<TemplateArgument> &Converted, + bool UpdateArgsWithConversions) { // Make a copy of the template arguments for processing. Only make the // changes at the end when successful in matching the arguments to the // template. @@ -4021,9 +4825,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // Not enough arguments for this parameter pack. Diag(TemplateLoc, diag::err_template_arg_list_different_arity) << false - << (isa<ClassTemplateDecl>(Template)? 0 : - isa<FunctionTemplateDecl>(Template)? 1 : - isa<TemplateTemplateParmDecl>(Template)? 2 : 3) + << (int)getTemplateNameKindForDiagnostics(TemplateName(Template)) << Template; Diag(Template->getLocation(), diag::note_template_decl_here) << Params->getSourceRange(); @@ -4222,7 +5024,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // No problems found with the new argument list, propagate changes back // to caller. - TemplateArgs = std::move(NewArgs); + if (UpdateArgsWithConversions) + TemplateArgs = std::move(NewArgs); return false; } @@ -4362,6 +5165,11 @@ bool UnnamedLocalNoLinkageFinder::VisitAutoType(const AutoType *T) { return Visit(T->getDeducedType()); } +bool UnnamedLocalNoLinkageFinder::VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType *T) { + return Visit(T->getDeducedType()); +} + bool UnnamedLocalNoLinkageFinder::VisitRecordType(const RecordType* T) { return VisitTagDecl(T->getDecl()); } @@ -4511,10 +5319,16 @@ enum NullPointerValueKind { /// value of the appropriate type. static NullPointerValueKind isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, - QualType ParamType, Expr *Arg) { + QualType ParamType, Expr *Arg, + Decl *Entity = nullptr) { if (Arg->isValueDependent() || Arg->isTypeDependent()) return NPV_NotNullPointer; + // dllimport'd entities aren't constant but are available inside of template + // arguments. + if (Entity && Entity->hasAttr<DLLImportAttr>()) + return NPV_NotNullPointer; + if (!S.isCompleteType(Arg->getExprLoc(), ParamType)) llvm_unreachable( "Incomplete parameter type in isNullPointerValueTemplateArgument!"); @@ -4758,14 +5572,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // If our parameter has pointer type, check for a null template value. if (ParamType->isPointerType() || ParamType->isNullPtrType()) { - NullPointerValueKind NPV; - // dllimport'd entities aren't constant but are available inside of template - // arguments. - if (Entity && Entity->hasAttr<DLLImportAttr>()) - NPV = NPV_NotNullPointer; - else - NPV = isNullPointerValueTemplateArgument(S, Param, ParamType, ArgIn); - switch (NPV) { + switch (isNullPointerValueTemplateArgument(S, Param, ParamType, ArgIn, + Entity)) { case NPV_NullPointer: S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), @@ -4957,39 +5765,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, TemplateArgument &Converted) { bool Invalid = false; - // Check for a null pointer value. Expr *Arg = ResultArg; - switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) { - case NPV_Error: - return true; - case NPV_NullPointer: - S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), - /*isNullPtr*/true); - return false; - case NPV_NotNullPointer: - break; - } - bool ObjCLifetimeConversion; - if (S.IsQualificationConversion(Arg->getType(), - ParamType.getNonReferenceType(), - false, ObjCLifetimeConversion)) { - Arg = S.ImpCastExprToType(Arg, ParamType, CK_NoOp, - Arg->getValueKind()).get(); - ResultArg = Arg; - } else if (!S.Context.hasSameUnqualifiedType(Arg->getType(), - ParamType.getNonReferenceType())) { - // We can't perform this conversion. - S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible) - << Arg->getType() << ParamType << Arg->getSourceRange(); - S.Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } - - // See through any implicit casts we added to fix the type. - while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) - Arg = Cast->getSubExpr(); // C++ [temp.arg.nontype]p1: // @@ -5046,6 +5823,37 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, DRE = nullptr; } + ValueDecl *Entity = DRE ? DRE->getDecl() : nullptr; + + // Check for a null pointer value. + switch (isNullPointerValueTemplateArgument(S, Param, ParamType, ResultArg, + Entity)) { + case NPV_Error: + return true; + case NPV_NullPointer: + S.Diag(ResultArg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); + Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), + /*isNullPtr*/true); + return false; + case NPV_NotNullPointer: + break; + } + + if (S.IsQualificationConversion(ResultArg->getType(), + ParamType.getNonReferenceType(), false, + ObjCLifetimeConversion)) { + ResultArg = S.ImpCastExprToType(ResultArg, ParamType, CK_NoOp, + ResultArg->getValueKind()) + .get(); + } else if (!S.Context.hasSameUnqualifiedType( + ResultArg->getType(), ParamType.getNonReferenceType())) { + // We can't perform this conversion. + S.Diag(ResultArg->getLocStart(), diag::err_template_arg_not_convertible) + << ResultArg->getType() << ParamType << ResultArg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + if (!DRE) return S.Diag(Arg->getLocStart(), diag::err_template_arg_not_pointer_to_member_form) @@ -5093,6 +5901,19 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // If the parameter type somehow involves auto, deduce the type now. if (getLangOpts().CPlusPlus1z && ParamType->isUndeducedType()) { + // During template argument deduction, we allow 'decltype(auto)' to + // match an arbitrary dependent argument. + // FIXME: The language rules don't say what happens in this case. + // FIXME: We get an opaque dependent type out of decltype(auto) if the + // expression is merely instantiation-dependent; is this enough? + if (CTAK == CTAK_Deduced && Arg->isTypeDependent()) { + auto *AT = dyn_cast<AutoType>(ParamType); + if (AT && AT->isDecltypeAuto()) { + Converted = TemplateArgument(Arg); + return Arg; + } + } + // When checking a deduced template argument, deduce from its type even if // the type is dependent, in order to check the types of non-type template // arguments line up properly in partial ordering. @@ -5160,8 +5981,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // The initialization of the parameter from the argument is // a constant-evaluated context. - EnterExpressionEvaluationContext ConstantEvaluated(*this, - Sema::ConstantEvaluated); + EnterExpressionEvaluationContext ConstantEvaluated( + *this, Sema::ExpressionEvaluationContext::ConstantEvaluated); if (getLangOpts().CPlusPlus1z) { // C++1z [temp.arg.nontype]p1: @@ -5217,7 +6038,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // -- a temporary object // -- a string literal // -- the result of a typeid expression, or - // -- a predefind __func__ variable + // -- a predefined __func__ variable if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) { if (isa<CXXUuidofExpr>(E)) { Converted = TemplateArgument(const_cast<Expr*>(E)); @@ -5748,8 +6569,9 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, if (RefExpr.isInvalid()) return ExprError(); - if (T->isFunctionType() || T->isArrayType()) { - // Decay functions and arrays. + if (!Context.hasSameUnqualifiedType(ParamType->getPointeeType(), T) && + (T->isFunctionType() || T->isArrayType())) { + // Decay functions and arrays unless we're forming a pointer to array. RefExpr = DefaultFunctionArrayConversion(RefExpr.get()); if (RefExpr.isInvalid()) return ExprError(); @@ -5838,15 +6660,6 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, return E; } -static bool isDependentOnOuter(NonTypeTemplateParmDecl *NTTP) { - if (NTTP->getDepth() == 0 || !NTTP->getType()->isDependentType()) - return false; - DependencyChecker Checker(NTTP->getDepth(), /*IgnoreNonTypeDependent*/ false, - /*FindLessThanDepth*/ true); - Checker.TraverseType(NTTP->getType()); - return Checker.Match; -} - /// \brief Match two template parameters within template parameter lists. static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, bool Complain, @@ -5903,10 +6716,11 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, // If we are matching a template template argument to a template // template parameter and one of the non-type template parameter types - // is dependent on an outer template's parameter, then we must wait until - // template instantiation time to actually compare the arguments. + // is dependent, then we must wait until template instantiation time + // to actually compare the arguments. if (Kind == Sema::TPL_TemplateTemplateArgumentMatch && - (isDependentOnOuter(OldNTTP) || isDependentOnOuter(NewNTTP))) + (OldNTTP->getType()->isDependentType() || + NewNTTP->getType()->isDependentType())) return true; if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { @@ -6205,7 +7019,7 @@ static bool CheckTemplateSpecializationScope(Sema &S, // Do not warn for class scope explicit specialization during // instantiation, warning was already emitted during pattern // semantic analysis. - if (!S.ActiveTemplateInstantiations.size()) + if (!S.inTemplateInstantiation()) S.Diag(Loc, diag::ext_function_specialization_in_class) << Specialized; } else { @@ -6479,7 +7293,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, return true; } - bool isExplicitSpecialization = false; + bool isMemberSpecialization = false; bool isPartialSpecialization = false; // Check the validity of the template headers that introduce this @@ -6490,7 +7304,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( KWLoc, TemplateNameLoc, SS, &TemplateId, - TemplateParameterLists, TUK == TUK_Friend, isExplicitSpecialization, + TemplateParameterLists, TUK == TUK_Friend, isMemberSpecialization, Invalid); if (Invalid) return true; @@ -6540,8 +7354,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc())) << SourceRange(LAngleLoc, RAngleLoc); - else - isExplicitSpecialization = true; } else { assert(TUK == TUK_Friend && "should have a 'template<>' for this decl"); } @@ -6749,7 +7561,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, NamedDecl *Hidden = nullptr; if (Def && SkipBody && !hasVisibleDefinition(Def, &Hidden)) { SkipBody->ShouldSkip = true; - makeMergedDefinitionVisible(Hidden, KWLoc); + makeMergedDefinitionVisible(Hidden); // From here on out, treat this as just a redeclaration. TUK = TUK_Declaration; } else if (Def) { @@ -6912,6 +7724,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, return false; } // Fall through + LLVM_FALLTHROUGH; case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: @@ -6938,6 +7751,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, return true; } + llvm_unreachable("The switch over PrevTSK must be exhaustive."); case TSK_ExplicitInstantiationDeclaration: switch (PrevTSK) { @@ -7219,9 +8033,13 @@ bool Sema::CheckFunctionTemplateSpecialization( TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind(); if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation) { Specialization->setLocation(FD->getLocation()); + Specialization->setLexicalDeclContext(FD->getLexicalDeclContext()); // C++11 [dcl.constexpr]p1: An explicit specialization of a constexpr // function can differ from the template declaration with respect to // the constexpr specifier. + // FIXME: We need an update record for this AST mutation. + // FIXME: What if there are multiple such prior declarations (for instance, + // from different modules)? Specialization->setConstexpr(FD->isConstexpr()); } @@ -7269,11 +8087,14 @@ bool Sema::CheckFunctionTemplateSpecialization( // flag to not-deleted, so that we can inherit that information from 'FD'. if (Specialization->isDeleted() && !SpecInfo->isExplicitSpecialization() && !Specialization->getCanonicalDecl()->isReferenced()) { + // FIXME: This assert will not hold in the presence of modules. assert( Specialization->getCanonicalDecl() == Specialization && "This must be the only existing declaration of this specialization"); + // FIXME: We need an update record for this AST mutation. Specialization->setDeletedAsWritten(false); } + // FIXME: We need an update record for this AST mutation. SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); MarkUnusedFileScopedDecl(Specialization); } @@ -7384,8 +8205,11 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { return false; } - // If this is a friend, just bail out here before we start turning - // things into explicit specializations. + // A member specialization in a friend declaration isn't really declaring + // an explicit specialization, just identifying a specific (possibly implicit) + // specialization. Don't change the template specialization kind. + // + // FIXME: Is this really valid? Other compilers reject. if (Member->getFriendObjectKind() != Decl::FOK_None) { // Preserve instantiation information. if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) { @@ -7435,66 +8259,36 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { false)) return true; - // Note that this is an explicit instantiation of a member. - // the original declaration to note that it is an explicit specialization - // (if it was previously an implicit instantiation). This latter step - // makes bookkeeping easier. - if (isa<FunctionDecl>(Member)) { + // Note that this member specialization is an "instantiation of" the + // corresponding member of the original template. + if (auto *MemberFunction = dyn_cast<FunctionDecl>(Member)) { FunctionDecl *InstantiationFunction = cast<FunctionDecl>(Instantiation); if (InstantiationFunction->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) { - InstantiationFunction->setTemplateSpecializationKind( - TSK_ExplicitSpecialization); - InstantiationFunction->setLocation(Member->getLocation()); // Explicit specializations of member functions of class templates do not // inherit '=delete' from the member function they are specializing. if (InstantiationFunction->isDeleted()) { + // FIXME: This assert will not hold in the presence of modules. assert(InstantiationFunction->getCanonicalDecl() == InstantiationFunction); + // FIXME: We need an update record for this AST mutation. InstantiationFunction->setDeletedAsWritten(false); } } - cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction( - cast<CXXMethodDecl>(InstantiatedFrom), - TSK_ExplicitSpecialization); - MarkUnusedFileScopedDecl(InstantiationFunction); - } else if (isa<VarDecl>(Member)) { - VarDecl *InstantiationVar = cast<VarDecl>(Instantiation); - if (InstantiationVar->getTemplateSpecializationKind() == - TSK_ImplicitInstantiation) { - InstantiationVar->setTemplateSpecializationKind( - TSK_ExplicitSpecialization); - InstantiationVar->setLocation(Member->getLocation()); - } - - cast<VarDecl>(Member)->setInstantiationOfStaticDataMember( + MemberFunction->setInstantiationOfMemberFunction( + cast<CXXMethodDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); + } else if (auto *MemberVar = dyn_cast<VarDecl>(Member)) { + MemberVar->setInstantiationOfStaticDataMember( cast<VarDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); - MarkUnusedFileScopedDecl(InstantiationVar); - } else if (isa<CXXRecordDecl>(Member)) { - CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation); - if (InstantiationClass->getTemplateSpecializationKind() == - TSK_ImplicitInstantiation) { - InstantiationClass->setTemplateSpecializationKind( - TSK_ExplicitSpecialization); - InstantiationClass->setLocation(Member->getLocation()); - } - - cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass( - cast<CXXRecordDecl>(InstantiatedFrom), - TSK_ExplicitSpecialization); - } else { - assert(isa<EnumDecl>(Member) && "Only member enums remain"); - EnumDecl *InstantiationEnum = cast<EnumDecl>(Instantiation); - if (InstantiationEnum->getTemplateSpecializationKind() == - TSK_ImplicitInstantiation) { - InstantiationEnum->setTemplateSpecializationKind( - TSK_ExplicitSpecialization); - InstantiationEnum->setLocation(Member->getLocation()); - } - - cast<EnumDecl>(Member)->setInstantiationOfMemberEnum( + } else if (auto *MemberClass = dyn_cast<CXXRecordDecl>(Member)) { + MemberClass->setInstantiationOfMemberClass( + cast<CXXRecordDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); + } else if (auto *MemberEnum = dyn_cast<EnumDecl>(Member)) { + MemberEnum->setInstantiationOfMemberEnum( cast<EnumDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); + } else { + llvm_unreachable("unknown member specialization kind"); } // Save the caller the trouble of having to figure out which declaration @@ -7504,6 +8298,43 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { return false; } +/// Complete the explicit specialization of a member of a class template by +/// updating the instantiated member to be marked as an explicit specialization. +/// +/// \param OrigD The member declaration instantiated from the template. +/// \param Loc The location of the explicit specialization of the member. +template<typename DeclT> +static void completeMemberSpecializationImpl(Sema &S, DeclT *OrigD, + SourceLocation Loc) { + if (OrigD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) + return; + + // FIXME: Inform AST mutation listeners of this AST mutation. + // FIXME: If there are multiple in-class declarations of the member (from + // multiple modules, or a declaration and later definition of a member type), + // should we update all of them? + OrigD->setTemplateSpecializationKind(TSK_ExplicitSpecialization); + OrigD->setLocation(Loc); +} + +void Sema::CompleteMemberSpecialization(NamedDecl *Member, + LookupResult &Previous) { + NamedDecl *Instantiation = cast<NamedDecl>(Member->getCanonicalDecl()); + if (Instantiation == Member) + return; + + if (auto *Function = dyn_cast<CXXMethodDecl>(Instantiation)) + completeMemberSpecializationImpl(*this, Function, Member->getLocation()); + else if (auto *Var = dyn_cast<VarDecl>(Instantiation)) + completeMemberSpecializationImpl(*this, Var, Member->getLocation()); + else if (auto *Record = dyn_cast<CXXRecordDecl>(Instantiation)) + completeMemberSpecializationImpl(*this, Record, Member->getLocation()); + else if (auto *Enum = dyn_cast<EnumDecl>(Instantiation)) + completeMemberSpecializationImpl(*this, Enum, Member->getLocation()); + else + llvm_unreachable("unknown member specialization kind"); +} + /// \brief Check the scope of an explicit instantiation. /// /// \returns true if a serious error occurs, false otherwise. @@ -7910,7 +8741,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(), Owned, IsDependent, SourceLocation(), false, TypeResult(), - /*IsTypeSpecifier*/false); + /*IsTypeSpecifier*/false, + /*IsTemplateParamOrArg*/false); assert(!IsDependent && "explicit instantiation of dependent name not yet handled"); if (!TagD) @@ -8087,6 +8919,14 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return true; } + // A deduction guide is not on the list of entities that can be explicitly + // instantiated. + if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) { + Diag(D.getDeclSpec().getLocStart(), diag::err_deduction_guide_specialized) + << /*explicit instantiation*/ 0; + return true; + } + // C++0x [temp.explicit]p2: // There are two forms of explicit instantiation: an explicit instantiation // definition and an explicit instantiation declaration. An explicit @@ -8248,7 +9088,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // A member function [...] of a class template can be explicitly // instantiated from the member definition associated with its class // template. - UnresolvedSet<8> Matches; + UnresolvedSet<8> TemplateMatches; + FunctionDecl *NonTemplateMatch = nullptr; AttributeList *Attr = D.getDeclSpec().getAttributes().getList(); TemplateSpecCandidateSet FailedCandidates(D.getIdentifierLoc()); for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); @@ -8259,11 +9100,13 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, QualType Adjusted = adjustCCAndNoReturn(R, Method->getType(), /*AdjustExceptionSpec*/true); if (Context.hasSameUnqualifiedType(Method->getType(), Adjusted)) { - Matches.clear(); - - Matches.addDecl(Method, P.getAccess()); - if (Method->getTemplateSpecializationKind() == TSK_Undeclared) - break; + if (Method->getPrimaryTemplate()) { + TemplateMatches.addDecl(Method, P.getAccess()); + } else { + // FIXME: Can this assert ever happen? Needs a test. + assert(!NonTemplateMatch && "Multiple NonTemplateMatches"); + NonTemplateMatch = Method; + } } } } @@ -8302,22 +9145,25 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, continue; } - Matches.addDecl(Specialization, P.getAccess()); + TemplateMatches.addDecl(Specialization, P.getAccess()); } - // Find the most specialized function template specialization. - UnresolvedSetIterator Result = getMostSpecialized( - Matches.begin(), Matches.end(), FailedCandidates, - D.getIdentifierLoc(), - PDiag(diag::err_explicit_instantiation_not_known) << Name, - PDiag(diag::err_explicit_instantiation_ambiguous) << Name, - PDiag(diag::note_explicit_instantiation_candidate)); - - if (Result == Matches.end()) - return true; + FunctionDecl *Specialization = NonTemplateMatch; + if (!Specialization) { + // Find the most specialized function template specialization. + UnresolvedSetIterator Result = getMostSpecialized( + TemplateMatches.begin(), TemplateMatches.end(), FailedCandidates, + D.getIdentifierLoc(), + PDiag(diag::err_explicit_instantiation_not_known) << Name, + PDiag(diag::err_explicit_instantiation_ambiguous) << Name, + PDiag(diag::note_explicit_instantiation_candidate)); + + if (Result == TemplateMatches.end()) + return true; - // Ignore access control bits, we don't need them for redeclaration checking. - FunctionDecl *Specialization = cast<FunctionDecl>(*Result); + // Ignore access control bits, we don't need them for redeclaration checking. + Specialization = cast<FunctionDecl>(*Result); + } // C++11 [except.spec]p4 // In an explicit instantiation an exception-specification may be specified, @@ -8491,7 +9337,8 @@ Sema::ActOnTypenameType(Scope *S, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy TemplateIn, - SourceLocation TemplateNameLoc, + IdentifierInfo *TemplateII, + SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc) { @@ -8502,6 +9349,19 @@ Sema::ActOnTypenameType(Scope *S, diag::ext_typename_outside_of_template) << FixItHint::CreateRemoval(TypenameLoc); + // Strangely, non-type results are not ignored by this lookup, so the + // program is ill-formed if it finds an injected-class-name. + if (TypenameLoc.isValid()) { + auto *LookupRD = + dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS, false)); + if (LookupRD && LookupRD->getIdentifier() == TemplateII) { + Diag(TemplateIILoc, + diag::ext_out_of_line_qualified_id_type_names_constructor) + << TemplateII << 0 /*injected-class-name used as template name*/ + << (TemplateKWLoc.isValid() ? 1 : 0 /*'template'/'typename' keyword*/); + } + } + // Translate the parser's template argument list in our AST format. TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); @@ -8523,7 +9383,7 @@ Sema::ActOnTypenameType(Scope *S, SpecTL.setElaboratedKeywordLoc(TypenameLoc); SpecTL.setQualifierLoc(SS.getWithLocInContext(Context)); SpecTL.setTemplateKeywordLoc(TemplateKWLoc); - SpecTL.setTemplateNameLoc(TemplateNameLoc); + SpecTL.setTemplateNameLoc(TemplateIILoc); SpecTL.setLAngleLoc(LAngleLoc); SpecTL.setRAngleLoc(RAngleLoc); for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) @@ -8531,7 +9391,7 @@ Sema::ActOnTypenameType(Scope *S, return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } - QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); + QualType T = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs); if (T.isNull()) return true; @@ -8540,7 +9400,7 @@ Sema::ActOnTypenameType(Scope *S, TemplateSpecializationTypeLoc SpecTL = Builder.push<TemplateSpecializationTypeLoc>(T); SpecTL.setTemplateKeywordLoc(TemplateKWLoc); - SpecTL.setTemplateNameLoc(TemplateNameLoc); + SpecTL.setTemplateNameLoc(TemplateIILoc); SpecTL.setLAngleLoc(LAngleLoc); SpecTL.setRAngleLoc(RAngleLoc); for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) @@ -8559,7 +9419,7 @@ Sema::ActOnTypenameType(Scope *S, /// Determine whether this failed name lookup should be treated as being /// disabled by a usage of std::enable_if. static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, - SourceRange &CondRange) { + SourceRange &CondRange, Expr *&Cond) { // We must be looking for a ::type... if (!II.isStr("type")) return false; @@ -8589,6 +9449,19 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, // Assume the first template argument is the condition. CondRange = EnableIfTSTLoc.getArgLoc(0).getSourceRange(); + + // Dig out the condition. + Cond = nullptr; + if (EnableIfTSTLoc.getArgLoc(0).getArgument().getKind() + != TemplateArgument::Expression) + return true; + + Cond = EnableIfTSTLoc.getArgLoc(0).getSourceExpression(); + + // Ignore Boolean literals; they add no value. + if (isa<CXXBoolLiteralExpr>(Cond->IgnoreParenCasts())) + Cond = nullptr; + return true; } @@ -8632,9 +9505,25 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // If we're looking up 'type' within a template named 'enable_if', produce // a more specific diagnostic. SourceRange CondRange; - if (isEnableIf(QualifierLoc, II, CondRange)) { + Expr *Cond = nullptr; + if (isEnableIf(QualifierLoc, II, CondRange, Cond)) { + // If we have a condition, narrow it down to the specific failed + // condition. + if (Cond) { + Expr *FailedCond; + std::string FailedDescription; + std::tie(FailedCond, FailedDescription) = + findFailedEnableIfCondition(*this, Cond); + + Diag(FailedCond->getExprLoc(), + diag::err_typename_nested_not_found_requirement) + << FailedDescription + << FailedCond->getSourceRange(); + return QualType(); + } + Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if) - << Ctx << CondRange; + << Ctx << CondRange; return QualType(); } @@ -8658,6 +9547,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, } // Fall through to create a dependent typename type, from which we can recover // better. + LLVM_FALLTHROUGH; case LookupResult::NotFoundInCurrentInstantiation: // Okay, it's a member of an unknown instantiation. @@ -8667,14 +9557,49 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, case LookupResult::Found: if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { + // C++ [class.qual]p2: + // In a lookup in which function names are not ignored and the + // nested-name-specifier nominates a class C, if the name specified + // after the nested-name-specifier, when looked up in C, is the + // injected-class-name of C [...] then the name is instead considered + // to name the constructor of class C. + // + // Unlike in an elaborated-type-specifier, function names are not ignored + // in typename-specifier lookup. However, they are ignored in all the + // contexts where we form a typename type with no keyword (that is, in + // mem-initializer-ids, base-specifiers, and elaborated-type-specifiers). + // + // FIXME: That's not strictly true: mem-initializer-id lookup does not + // ignore functions, but that appears to be an oversight. + auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(Ctx); + auto *FoundRD = dyn_cast<CXXRecordDecl>(Type); + if (Keyword == ETK_Typename && LookupRD && FoundRD && + FoundRD->isInjectedClassName() && + declaresSameEntity(LookupRD, cast<Decl>(FoundRD->getParent()))) + Diag(IILoc, diag::ext_out_of_line_qualified_id_type_names_constructor) + << &II << 1 << 0 /*'typename' keyword used*/; + // We found a type. Build an ElaboratedType, since the // typename-specifier was just sugar. MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); - return Context.getElaboratedType(ETK_Typename, + return Context.getElaboratedType(Keyword, QualifierLoc.getNestedNameSpecifier(), Context.getTypeDeclType(Type)); } + // C++ [dcl.type.simple]p2: + // A type-specifier of the form + // typename[opt] nested-name-specifier[opt] template-name + // is a placeholder for a deduced class type [...]. + if (getLangOpts().CPlusPlus1z) { + if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) { + return Context.getElaboratedType( + Keyword, QualifierLoc.getNestedNameSpecifier(), + Context.getDeducedTemplateSpecializationType(TemplateName(TD), + QualType(), false)); + } + } + DiagID = diag::err_typename_nested_not_type; Referenced = Result.getFoundDecl(); break; @@ -8991,7 +9916,7 @@ private: IsHiddenExplicitSpecialization = Spec->getMemberSpecializationInfo() ? !S.hasVisibleMemberSpecialization(Spec, &Modules) - : !S.hasVisibleDeclaration(Spec); + : !S.hasVisibleExplicitSpecialization(Spec, &Modules); } else { checkInstantiated(Spec); } |