diff options
Diffstat (limited to 'clang/lib/Sema/SemaTemplateDeduction.cpp')
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 210 |
1 files changed, 155 insertions, 55 deletions
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 9e56e697..0d70321 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -37,6 +37,7 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TemplateKinds.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Sema.h" @@ -146,11 +147,7 @@ static void MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, bool OnlyDeduced, unsigned Level, llvm::SmallBitVector &Deduced); -/// If the given expression is of a form that permits the deduction -/// of a non-type template parameter, return the declaration of that -/// non-type template parameter. -static const NonTypeTemplateParmDecl * -getDeducedParameterFromExpr(const Expr *E, unsigned Depth) { +static const Expr *unwrapExpressionForDeduction(const Expr *E) { // If we are within an alias template, the expression may have undergone // any number of parameter substitutions already. while (true) { @@ -170,18 +167,100 @@ getDeducedParameterFromExpr(const Expr *E, unsigned Depth) { } else break; } + return E; +} + +class NonTypeOrVarTemplateParmDecl { +public: + NonTypeOrVarTemplateParmDecl(const NamedDecl *Template) : Template(Template) { + assert( + !Template || isa<NonTypeTemplateParmDecl>(Template) || + (isa<TemplateTemplateParmDecl>(Template) && + (cast<TemplateTemplateParmDecl>(Template)->templateParameterKind() == + TNK_Var_template || + cast<TemplateTemplateParmDecl>(Template)->templateParameterKind() == + TNK_Concept_template))); + } + + QualType getType() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return NTTP->getType(); + return getTemplate()->templateParameterKind() == TNK_Concept_template + ? getTemplate()->getASTContext().BoolTy + : getTemplate()->getASTContext().DependentTy; + } + + unsigned getDepth() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return NTTP->getDepth(); + return getTemplate()->getDepth(); + } + + unsigned getIndex() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return NTTP->getIndex(); + return getTemplate()->getIndex(); + } + + const TemplateTemplateParmDecl *getTemplate() const { + return cast<TemplateTemplateParmDecl>(Template); + } + + const NonTypeTemplateParmDecl *getNTTP() const { + return cast<NonTypeTemplateParmDecl>(Template); + } + + TemplateParameter asTemplateParam() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return const_cast<NonTypeTemplateParmDecl *>(NTTP); + return const_cast<TemplateTemplateParmDecl *>(getTemplate()); + } + + bool isExpandedParameterPack() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return NTTP->isExpandedParameterPack(); + return getTemplate()->isExpandedParameterPack(); + } + + SourceLocation getLocation() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return NTTP->getLocation(); + return getTemplate()->getLocation(); + } + + operator bool() const { return Template; } +private: + const NamedDecl *Template; +}; + +/// If the given expression is of a form that permits the deduction +/// of a non-type template parameter, return the declaration of that +/// non-type template parameter. +static NonTypeOrVarTemplateParmDecl +getDeducedNTTParameterFromExpr(const Expr *E, unsigned Depth) { + // If we are within an alias template, the expression may have undergone + // any number of parameter substitutions already. + E = unwrapExpressionForDeduction(E); if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl())) if (NTTP->getDepth() == Depth) return NTTP; + if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E); + ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) { + if (auto *TTP = ULE->getTemplateTemplateDecl()) { + + if (TTP->getDepth() == Depth) + return TTP; + } + } return nullptr; } -static const NonTypeTemplateParmDecl * -getDeducedParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) { - return getDeducedParameterFromExpr(E, Info.getDeducedDepth()); +static const NonTypeOrVarTemplateParmDecl +getDeducedNTTParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) { + return getDeducedNTTParameterFromExpr(E, Info.getDeducedDepth()); } /// Determine whether two declaration pointers refer to the same @@ -386,29 +465,28 @@ checkDeducedTemplateArguments(ASTContext &Context, /// deduction is funneled through here. static TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, + const NonTypeOrVarTemplateParmDecl NTTP, const DeducedTemplateArgument &NewDeduced, QualType ValueType, TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool *HasDeducedAnyParam) { - assert(NTTP->getDepth() == Info.getDeducedDepth() && + assert(NTTP.getDepth() == Info.getDeducedDepth() && "deducing non-type template argument with wrong depth"); DeducedTemplateArgument Result = checkDeducedTemplateArguments( - S.Context, Deduced[NTTP->getIndex()], NewDeduced); + S.Context, Deduced[NTTP.getIndex()], NewDeduced); if (Result.isNull()) { - Info.Param = const_cast<NonTypeTemplateParmDecl*>(NTTP); - Info.FirstArg = Deduced[NTTP->getIndex()]; + Info.Param = NTTP.asTemplateParam(); + Info.FirstArg = Deduced[NTTP.getIndex()]; Info.SecondArg = NewDeduced; return TemplateDeductionResult::Inconsistent; } - - Deduced[NTTP->getIndex()] = Result; + Deduced[NTTP.getIndex()] = Result; if (!S.getLangOpts().CPlusPlus17) return TemplateDeductionResult::Success; - if (NTTP->isExpandedParameterPack()) + if (NTTP.isExpandedParameterPack()) // FIXME: We may still need to deduce parts of the type here! But we // don't have any way to find which slice of the type to use, and the // type stored on the NTTP itself is nonsense. Perhaps the type of an @@ -417,7 +495,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, // Get the type of the parameter for deduction. If it's a (dependent) array // or function type, we will not have decayed it yet, so do that now. - QualType ParamType = S.Context.getAdjustedParameterType(NTTP->getType()); + QualType ParamType = S.Context.getAdjustedParameterType(NTTP.getType()); if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType)) ParamType = Expansion->getPattern(); @@ -444,7 +522,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, /// from the given integral constant. static TemplateDeductionResult DeduceNonTypeTemplateArgument( Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value, + NonTypeOrVarTemplateParmDecl NTTP, const llvm::APSInt &Value, QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool *HasDeducedAnyParam) { @@ -459,14 +537,14 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument( /// from the given null pointer template argument type. static TemplateDeductionResult DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, + NonTypeOrVarTemplateParmDecl NTTP, QualType NullPtrType, TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool *HasDeducedAnyParam) { Expr *Value = S.ImpCastExprToType( new (S.Context) CXXNullPtrLiteralExpr(S.Context.NullPtrTy, - NTTP->getLocation()), + NTTP.getLocation()), NullPtrType, NullPtrType->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer) @@ -482,7 +560,7 @@ DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, /// \returns true if deduction succeeded, false otherwise. static TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, Expr *Value, + NonTypeOrVarTemplateParmDecl NTTP, Expr *Value, TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool *HasDeducedAnyParam) { @@ -497,7 +575,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, /// \returns true if deduction succeeded, false otherwise. static TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, ValueDecl *D, + NonTypeOrVarTemplateParmDecl NTTP, ValueDecl *D, QualType T, TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced, @@ -1930,14 +2008,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Determine the array bound is something we can deduce. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, DAP->getSizeExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, DAP->getSizeExpr()); if (!NTTP) return TemplateDeductionResult::Success; // We can perform template argument deduction for the given non-type // template parameter. - assert(NTTP->getDepth() == Info.getDeducedDepth() && + assert(NTTP.getDepth() == Info.getDeducedDepth() && "saw non-type template parameter with wrong depth"); if (const auto *CAA = dyn_cast<ConstantArrayType>(AA)) { llvm::APSInt Size(CAA->getSize()); @@ -1994,10 +2072,10 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // deducing through the noexcept-specifier if it's part of the canonical // type. libstdc++ relies on this. Expr *NoexceptExpr = FPP->getNoexceptExpr(); - if (const NonTypeTemplateParmDecl *NTTP = - NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr) + if (NonTypeOrVarTemplateParmDecl NTTP = + NoexceptExpr ? getDeducedNTTParameterFromExpr(Info, NoexceptExpr) : nullptr) { - assert(NTTP->getDepth() == Info.getDeducedDepth() && + assert(NTTP.getDepth() == Info.getDeducedDepth() && "saw non-type template parameter with wrong depth"); llvm::APSInt Noexcept(1); @@ -2191,8 +2269,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the vector size, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2217,8 +2295,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the vector size, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2246,8 +2324,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the vector size, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2271,8 +2349,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the vector size, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2348,8 +2426,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return TemplateDeductionResult::NonDeducedMismatch; } - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, ParamExpr); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, ParamExpr); if (!NTTP) return TemplateDeductionResult::Success; @@ -2395,8 +2473,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the address space, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2420,8 +2498,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the address space, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2440,8 +2518,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (IP->isUnsigned() != IA->isUnsigned()) return TemplateDeductionResult::NonDeducedMismatch; - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, IP->getNumBitsExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, IP->getNumBitsExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2573,8 +2651,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, return TemplateDeductionResult::NonDeducedMismatch; case TemplateArgument::Expression: - if (const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, P.getAsExpr())) { + if (NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, P.getAsExpr())) { switch (A.getKind()) { case TemplateArgument::Expression: { const Expr *E = A.getAsExpr(); @@ -2628,7 +2706,6 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, } llvm_unreachable("Unknown template argument kind"); } - // Can't deduce anything, but that's okay. return TemplateDeductionResult::Success; case TemplateArgument::Pack: @@ -4392,8 +4469,8 @@ static TemplateDeductionResult DeduceFromInitializerList( // from the length of the initializer list. if (auto *DependentArrTy = dyn_cast_or_null<DependentSizedArrayType>(ArrTy)) { // Determine the array bound is something we can deduce. - if (const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, DependentArrTy->getSizeExpr())) { + if (NonTypeOrVarTemplateParmDecl NTTP = getDeducedNTTParameterFromExpr( + Info, DependentArrTy->getSizeExpr())) { // We can perform template argument deduction for the given non-type // template parameter. // C++ [temp.deduct.type]p13: @@ -5098,7 +5175,7 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, AutoTypeLoc TypeLoc, QualType Deduced) { ConstraintSatisfaction Satisfaction; - ConceptDecl *Concept = Type.getTypeConstraintConcept(); + ConceptDecl *Concept = cast<ConceptDecl>(Type.getTypeConstraintConcept()); TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(), TypeLoc.getRAngleLoc()); TemplateArgs.addArgument( @@ -6654,6 +6731,18 @@ struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor { Used[NTTP->getIndex()] = true; return true; } + + bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *ULE) override { + if (ULE->isConceptReference() || ULE->isVarDeclReference()) { + if (auto *TTP = ULE->getTemplateTemplateDecl()) { + if (TTP->getDepth() == Depth) + Used[TTP->getIndex()] = true; + } + for (auto &TLoc : ULE->template_arguments()) + DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc(TLoc); + } + return true; + } }; } @@ -6675,17 +6764,28 @@ MarkUsedTemplateParameters(ASTContext &Ctx, if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E)) E = Expansion->getPattern(); - const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(E, Depth); - if (!NTTP) + E = unwrapExpressionForDeduction(E); + if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E); + ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) { + if (const auto *TTP = ULE->getTemplateTemplateDecl()) + Used[TTP->getIndex()] = true; + for (auto &TLoc : ULE->template_arguments()) + MarkUsedTemplateParameters(Ctx, TLoc.getArgument(), OnlyDeduced, Depth, + Used); return; + } - if (NTTP->getDepth() == Depth) - Used[NTTP->getIndex()] = true; + const NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(E, Depth); + if (!NTTP) + return; + if (NTTP.getDepth() == Depth) + Used[NTTP.getIndex()] = true; // In C++17 mode, additional arguments may be deduced from the type of a // non-type argument. if (Ctx.getLangOpts().CPlusPlus17) - MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used); + MarkUsedTemplateParameters(Ctx, NTTP.getType(), OnlyDeduced, Depth, Used); } /// Mark the template parameters that are used by the given |