diff options
Diffstat (limited to 'clang/lib/Sema/SemaTemplateInstantiate.cpp')
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 1000 |
1 files changed, 700 insertions, 300 deletions
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index f09b3473c074..2790e78aa53a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -15,10 +15,12 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/PrettyDeclStackTrace.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Stack.h" @@ -26,12 +28,15 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" #include "clang/Sema/SemaConcept.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TimeProfiler.h" +#include <optional> using namespace clang; using namespace sema; @@ -40,13 +45,231 @@ using namespace sema; // Template Instantiation Support //===----------------------------------------------------------------------===/ +namespace { +namespace TemplateInstArgsHelpers { +struct Response { + const Decl *NextDecl = nullptr; + bool IsDone = false; + bool ClearRelativeToPrimary = true; + static Response Done() { + Response R; + R.IsDone = true; + return R; + } + static Response ChangeDecl(const Decl *ND) { + Response R; + R.NextDecl = ND; + return R; + } + static Response ChangeDecl(const DeclContext *Ctx) { + Response R; + R.NextDecl = Decl::castFromDeclContext(Ctx); + return R; + } + + static Response UseNextDecl(const Decl *CurDecl) { + return ChangeDecl(CurDecl->getDeclContext()); + } + + static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) { + Response R = Response::UseNextDecl(CurDecl); + R.ClearRelativeToPrimary = false; + return R; + } +}; +// Add template arguments from a variable template instantiation. +Response +HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec, + MultiLevelTemplateArgumentList &Result, + bool SkipForSpecialization) { + // For a class-scope explicit specialization, there are no template arguments + // at this level, but there may be enclosing template arguments. + if (VarTemplSpec->isClassScopeExplicitSpecialization()) + return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); + + // We're done when we hit an explicit specialization. + if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa<VarTemplatePartialSpecializationDecl>(VarTemplSpec)) + return Response::Done(); + + // If this variable template specialization was instantiated from a + // specialized member that is a variable template, we're done. + assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?"); + llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> + Specialized = VarTemplSpec->getSpecializedTemplateOrPartial(); + if (VarTemplatePartialSpecializationDecl *Partial = + Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); + if (Partial->isMemberSpecialization()) + return Response::Done(); + } else { + VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>(); + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); + if (Tmpl->isMemberSpecialization()) + return Response::Done(); + } + return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); +} + +// If we have a template template parameter with translation unit context, +// then we're performing substitution into a default template argument of +// this template template parameter before we've constructed the template +// that will own this template template parameter. In this case, we +// use empty template parameter lists for all of the outer templates +// to avoid performing any substitutions. +Response +HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP, + MultiLevelTemplateArgumentList &Result) { + for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I) + Result.addOuterTemplateArguments(std::nullopt); + return Response::Done(); +} + +// Add template arguments from a class template instantiation. +Response +HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, + MultiLevelTemplateArgumentList &Result, + bool SkipForSpecialization) { + if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) { + // We're done when we hit an explicit specialization. + if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec)) + return Response::Done(); + + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec), + ClassTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); + + // If this class template specialization was instantiated from a + // specialized member that is a class template, we're done. + assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?"); + if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization()) + return Response::Done(); + } + return Response::UseNextDecl(ClassTemplSpec); +} + +Response HandleFunction(const FunctionDecl *Function, + MultiLevelTemplateArgumentList &Result, + const FunctionDecl *Pattern, bool RelativeToPrimary, + bool ForConstraintInstantiation) { + // Add template arguments from a function template specialization. + if (!RelativeToPrimary && + Function->getTemplateSpecializationKindForInstantiation() == + TSK_ExplicitSpecialization) + return Response::Done(); + + if (!RelativeToPrimary && + Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { + // This is an implicit instantiation of an explicit specialization. We + // don't get any template arguments from this function but might get + // some from an enclosing template. + return Response::UseNextDecl(Function); + } else if (const TemplateArgumentList *TemplateArgs = + Function->getTemplateSpecializationArgs()) { + // Add the template arguments for this specialization. + Result.addOuterTemplateArguments(const_cast<FunctionDecl *>(Function), + TemplateArgs->asArray(), + /*Final=*/false); + + // If this function was instantiated from a specialized member that is + // a function template, we're done. + assert(Function->getPrimaryTemplate() && "No function template?"); + if (Function->getPrimaryTemplate()->isMemberSpecialization()) + return Response::Done(); + + // If this function is a generic lambda specialization, we are done. + if (!ForConstraintInstantiation && + isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) + return Response::Done(); + + } else if (Function->getDescribedFunctionTemplate()) { + assert( + (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && + "Outer template not instantiated?"); + } + // If this is a friend or local declaration and it declares an entity at + // namespace scope, take arguments from its lexical parent + // instead of its semantic parent, unless of course the pattern we're + // instantiating actually comes from the file's context! + if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) && + Function->getNonTransparentDeclContext()->isFileContext() && + (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { + return Response::ChangeDecl(Function->getLexicalDeclContext()); + } + return Response::UseNextDecl(Function); +} + +Response HandleRecordDecl(const CXXRecordDecl *Rec, + MultiLevelTemplateArgumentList &Result, + ASTContext &Context, + bool ForConstraintInstantiation) { + if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { + assert( + (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && + "Outer template not instantiated?"); + if (ClassTemplate->isMemberSpecialization()) + return Response::Done(); + if (ForConstraintInstantiation) { + QualType RecordType = Context.getTypeDeclType(Rec); + QualType Injected = cast<InjectedClassNameType>(RecordType) + ->getInjectedSpecializationType(); + const auto *InjectedType = cast<TemplateSpecializationType>(Injected); + Result.addOuterTemplateArguments(const_cast<CXXRecordDecl *>(Rec), + InjectedType->template_arguments(), + /*Final=*/false); + } + } + + bool IsFriend = Rec->getFriendObjectKind() || + (Rec->getDescribedClassTemplate() && + Rec->getDescribedClassTemplate()->getFriendObjectKind()); + if (ForConstraintInstantiation && IsFriend && + Rec->getNonTransparentDeclContext()->isFileContext()) { + return Response::ChangeDecl(Rec->getLexicalDeclContext()); + } + + // This is to make sure we pick up the VarTemplateSpecializationDecl that this + // lambda is defined inside of. + if (Rec->isLambda()) + if (const Decl *LCD = Rec->getLambdaContextDecl()) + return Response::ChangeDecl(LCD); + + return Response::UseNextDecl(Rec); +} + +Response HandleImplicitConceptSpecializationDecl( + const ImplicitConceptSpecializationDecl *CSD, + MultiLevelTemplateArgumentList &Result) { + Result.addOuterTemplateArguments( + const_cast<ImplicitConceptSpecializationDecl *>(CSD), + CSD->getTemplateArguments(), + /*Final=*/false); + return Response::UseNextDecl(CSD); +} + +Response HandleGenericDeclContext(const Decl *CurDecl) { + return Response::UseNextDecl(CurDecl); +} +} // namespace TemplateInstArgsHelpers +} // namespace + /// Retrieve the template argument list(s) that should be used to /// instantiate the definition of the given declaration. /// -/// \param D the declaration for which we are computing template instantiation +/// \param ND the declaration for which we are computing template instantiation /// arguments. /// -/// \param Innermost if non-NULL, the innermost template argument list. +/// \param Innermost if non-NULL, specifies a template argument list for the +/// template declaration passed as ND. /// /// \param RelativeToPrimary true if we should get the template /// arguments relative to the primary template, even when we're @@ -54,137 +277,64 @@ using namespace sema; /// template specializations. /// /// \param Pattern If non-NULL, indicates the pattern from which we will be -/// instantiating the definition of the given declaration, \p D. This is +/// instantiating the definition of the given declaration, \p ND. This is /// used to determine the proper set of template instantiation arguments for /// friend function template specializations. +/// +/// \param ForConstraintInstantiation when collecting arguments, +/// ForConstraintInstantiation indicates we should continue looking when +/// encountering a lambda generic call operator, and continue looking for +/// arguments on an enclosing class template. + MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( - const NamedDecl *D, const TemplateArgumentList *Innermost, - bool RelativeToPrimary, const FunctionDecl *Pattern) { + const NamedDecl *ND, bool Final, const TemplateArgumentList *Innermost, + bool RelativeToPrimary, const FunctionDecl *Pattern, + bool ForConstraintInstantiation, bool SkipForSpecialization) { + assert(ND && "Can't find arguments for a decl if one isn't provided"); // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; if (Innermost) - Result.addOuterTemplateArguments(Innermost); - - const auto *Ctx = dyn_cast<DeclContext>(D); - if (!Ctx) { - Ctx = D->getDeclContext(); - - // Add template arguments from a variable template instantiation. For a - // class-scope explicit specialization, there are no template arguments - // at this level, but there may be enclosing template arguments. - const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(D); - if (Spec && !Spec->isClassScopeExplicitSpecialization()) { - // We're done when we hit an explicit specialization. - if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && - !isa<VarTemplatePartialSpecializationDecl>(Spec)) - return Result; - - Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); - - // If this variable template specialization was instantiated from a - // specialized member that is a variable template, we're done. - assert(Spec->getSpecializedTemplate() && "No variable template?"); - llvm::PointerUnion<VarTemplateDecl*, - VarTemplatePartialSpecializationDecl*> Specialized - = Spec->getSpecializedTemplateOrPartial(); - if (VarTemplatePartialSpecializationDecl *Partial = - Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { - if (Partial->isMemberSpecialization()) - return Result; - } else { - VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>(); - if (Tmpl->isMemberSpecialization()) - return Result; - } - } - - // If we have a template template parameter with translation unit context, - // then we're performing substitution into a default template argument of - // this template template parameter before we've constructed the template - // that will own this template template parameter. In this case, we - // use empty template parameter lists for all of the outer templates - // to avoid performing any substitutions. - if (Ctx->isTranslationUnit()) { - if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { - for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I) - Result.addOuterTemplateArguments(None); - return Result; - } - } - } - - while (!Ctx->isFileContext()) { - // Add template arguments from a class template instantiation. - const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Ctx); - if (Spec && !Spec->isClassScopeExplicitSpecialization()) { - // We're done when we hit an explicit specialization. - if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && - !isa<ClassTemplatePartialSpecializationDecl>(Spec)) - break; - - Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); - - // If this class template specialization was instantiated from a - // specialized member that is a class template, we're done. - assert(Spec->getSpecializedTemplate() && "No class template?"); - if (Spec->getSpecializedTemplate()->isMemberSpecialization()) - break; - } - // Add template arguments from a function template specialization. - else if (const auto *Function = dyn_cast<FunctionDecl>(Ctx)) { - if (!RelativeToPrimary && - Function->getTemplateSpecializationKindForInstantiation() == - TSK_ExplicitSpecialization) - break; - - if (!RelativeToPrimary && Function->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization) { - // This is an implicit instantiation of an explicit specialization. We - // don't get any template arguments from this function but might get - // some from an enclosing template. - } else if (const TemplateArgumentList *TemplateArgs - = Function->getTemplateSpecializationArgs()) { - // Add the template arguments for this specialization. - Result.addOuterTemplateArguments(TemplateArgs); - - // If this function was instantiated from a specialized member that is - // a function template, we're done. - assert(Function->getPrimaryTemplate() && "No function template?"); - if (Function->getPrimaryTemplate()->isMemberSpecialization()) - break; - - // If this function is a generic lambda specialization, we are done. - if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) - break; - - } else if (Function->getDescribedFunctionTemplate()) { - assert(Result.getNumSubstitutedLevels() == 0 && - "Outer template not instantiated?"); - } - - // If this is a friend declaration and it declares an entity at - // namespace scope, take arguments from its lexical parent - // instead of its semantic parent, unless of course the pattern we're - // instantiating actually comes from the file's context! - if (Function->getFriendObjectKind() && - Function->getDeclContext()->isFileContext() && - (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { - Ctx = Function->getLexicalDeclContext(); - RelativeToPrimary = false; - continue; - } - } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(Ctx)) { - if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { - assert(Result.getNumSubstitutedLevels() == 0 && - "Outer template not instantiated?"); - if (ClassTemplate->isMemberSpecialization()) - break; + Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), + Innermost->asArray(), Final); + + const Decl *CurDecl = ND; + + while (!CurDecl->isFileContextDecl()) { + using namespace TemplateInstArgsHelpers; + Response R; + if (const auto *VarTemplSpec = + dyn_cast<VarTemplateSpecializationDecl>(CurDecl)) { + R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization); + } else if (const auto *ClassTemplSpec = + dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) { + R = HandleClassTemplateSpec(ClassTemplSpec, Result, + SkipForSpecialization); + } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) { + R = HandleFunction(Function, Result, Pattern, RelativeToPrimary, + ForConstraintInstantiation); + } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) { + R = HandleRecordDecl(Rec, Result, Context, ForConstraintInstantiation); + } else if (const auto *CSD = + dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) { + R = HandleImplicitConceptSpecializationDecl(CSD, Result); + } else if (!isa<DeclContext>(CurDecl)) { + R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl); + if (CurDecl->getDeclContext()->isTranslationUnit()) { + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) { + R = HandleDefaultTempArgIntoTempTempParam(TTP, Result); + } } + } else { + R = HandleGenericDeclContext(CurDecl); } - Ctx = Ctx->getParent(); - RelativeToPrimary = false; + if (R.IsDone) + return Result; + if (R.ClearRelativeToPrimary) + RelativeToPrimary = false; + assert(R.NextDecl); + CurDecl = R.NextDecl; } return Result; @@ -204,6 +354,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { return true; case RequirementInstantiation: + case RequirementParameterInstantiation: case DefaultTemplateArgumentChecking: case DeclaringSpecialMember: case DeclaringImplicitEqualityComparison: @@ -377,8 +528,8 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( : InstantiatingTemplate( SemaRef, CodeSynthesisContext::RequirementInstantiation, PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, - /*Template=*/nullptr, /*TemplateArgs=*/None, &DeductionInfo) {} - + /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt, &DeductionInfo) { +} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -387,8 +538,16 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( : InstantiatingTemplate( SemaRef, CodeSynthesisContext::NestedRequirementConstraintsCheck, PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, - /*Template=*/nullptr, /*TemplateArgs=*/None) {} + /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt) {} +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, const RequiresExpr *RE, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::RequirementParameterInstantiation, + PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, + /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt, &DeductionInfo) { +} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -424,6 +583,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( SemaRef, CodeSynthesisContext::ParameterMappingSubstitution, PointOfInstantiation, InstantiationRange, Template) {} + void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) { Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext; InNonInstantiationSFINAEContext = false; @@ -593,7 +753,7 @@ void Sema::PrintInstantiationStack() { TemplateDecl *Template = cast<TemplateDecl>(Active->Template); SmallString<128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); - Template->printName(OS); + Template->printName(OS, getPrintingPolicy()); printTemplateArgumentList(OS, Active->template_arguments(), getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, @@ -659,7 +819,7 @@ void Sema::PrintInstantiationStack() { SmallString<128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); - FD->printName(OS); + FD->printName(OS, getPrintingPolicy()); printTemplateArgumentList(OS, Active->template_arguments(), getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, @@ -729,6 +889,11 @@ void Sema::PrintInstantiationStack() { diag::note_template_requirement_instantiation_here) << Active->InstantiationRange; break; + case CodeSynthesisContext::RequirementParameterInstantiation: + Diags.Report(Active->PointOfInstantiation, + diag::note_template_requirement_params_instantiation_here) + << Active->InstantiationRange; + break; case CodeSynthesisContext::NestedRequirementConstraintsCheck: Diags.Report(Active->PointOfInstantiation, @@ -790,8 +955,7 @@ void Sema::PrintInstantiationStack() { Diags.Report(Active->PointOfInstantiation, diag::note_building_builtin_dump_struct_call) << convertCallArgsToString( - *this, - llvm::makeArrayRef(Active->CallArgs, Active->NumCallArgs)); + *this, llvm::ArrayRef(Active->CallArgs, Active->NumCallArgs)); break; case CodeSynthesisContext::Memoization: @@ -819,7 +983,7 @@ void Sema::PrintInstantiationStack() { } SmallString<128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); - cast<NamedDecl>(Active->Entity)->printName(OS); + cast<NamedDecl>(Active->Entity)->printName(OS, getPrintingPolicy()); if (!isa<FunctionDecl>(Active->Entity)) { printTemplateArgumentList(OS, Active->template_arguments(), getPrintingPolicy()); @@ -848,9 +1012,9 @@ void Sema::PrintInstantiationStack() { } } -Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { +std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { if (InNonInstantiationSFINAEContext) - return Optional<TemplateDeductionInfo *>(nullptr); + return std::optional<TemplateDeductionInfo *>(nullptr); for (SmallVectorImpl<CodeSynthesisContext>::const_reverse_iterator Active = CodeSynthesisContexts.rbegin(), @@ -864,7 +1028,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { // context, depending on what else is on the stack. if (isa<TypeAliasTemplateDecl>(Active->Entity)) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case CodeSynthesisContext::DefaultFunctionArgumentInstantiation: case CodeSynthesisContext::ExceptionSpecInstantiation: case CodeSynthesisContext::ConstraintsCheck: @@ -872,7 +1036,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::ConstraintNormalization: case CodeSynthesisContext::NestedRequirementConstraintsCheck: // This is a template instantiation, so there is no SFINAE. - return None; + return std::nullopt; case CodeSynthesisContext::DefaultTemplateArgumentInstantiation: case CodeSynthesisContext::PriorTemplateArgumentSubstitution: @@ -887,6 +1051,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: case CodeSynthesisContext::ConstraintSubstitution: case CodeSynthesisContext::RequirementInstantiation: + case CodeSynthesisContext::RequirementParameterInstantiation: // We're either substituting explicitly-specified template arguments, // deduced template arguments, a constraint expression or a requirement // in a requires expression, so SFINAE applies. @@ -901,7 +1066,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::BuildingBuiltinDumpStructCall: // This happens in a context unrelated to template instantiation, so // there is no SFINAE. - return None; + return std::nullopt; case CodeSynthesisContext::ExceptionSpecEvaluation: // FIXME: This should not be treated as a SFINAE context, because @@ -916,10 +1081,10 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { // The inner context was transparent for SFINAE. If it occurred within a // non-instantiation SFINAE context, then SFINAE applies. if (Active->SavedInNonInstantiationSFINAEContext) - return Optional<TemplateDeductionInfo *>(nullptr); + return std::optional<TemplateDeductionInfo *>(nullptr); } - return None; + return std::nullopt; } //===----------------------------------------------------------------------===/ @@ -930,16 +1095,23 @@ namespace { const MultiLevelTemplateArgumentList &TemplateArgs; SourceLocation Loc; DeclarationName Entity; + bool EvaluateConstraints = true; public: typedef TreeTransform<TemplateInstantiator> inherited; TemplateInstantiator(Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs, - SourceLocation Loc, - DeclarationName Entity) - : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc), - Entity(Entity) { } + SourceLocation Loc, DeclarationName Entity) + : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc), + Entity(Entity) {} + + void setEvaluateConstraints(bool B) { + EvaluateConstraints = B; + } + bool getEvaluateConstraints() { + return EvaluateConstraints; + } /// Determine whether the given type \p T has already been /// transformed. @@ -965,11 +1137,18 @@ namespace { return TemplateArgs.getNewDepth(Depth); } + std::optional<unsigned> getPackIndex(TemplateArgument Pack) { + int Index = getSema().ArgumentPackSubstitutionIndex; + if (Index == -1) + return std::nullopt; + return Pack.pack_size() - 1 - Index; + } + bool TryExpandParameterPacks(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, bool &ShouldExpand, bool &RetainExpansion, - Optional<unsigned> &NumExpansions) { + std::optional<unsigned> &NumExpansions) { return getSema().CheckParameterPacksForExpansion(EllipsisLoc, PatternRange, Unexpanded, TemplateArgs, @@ -1052,7 +1231,7 @@ namespace { // We recreated a local declaration, but not by instantiating it. There // may be pending dependent diagnostics to produce. - if (auto *DC = dyn_cast<DeclContext>(Old)) + if (auto *DC = dyn_cast<DeclContext>(Old); DC && DC->isDependentContext()) SemaRef.PerformDependentDiagnostics(DC, TemplateArgs); } @@ -1128,30 +1307,79 @@ namespace { Qualifiers ThisTypeQuals, Fn TransformExceptionSpec); - ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, - int indexAdjustment, - Optional<unsigned> NumExpansions, - bool ExpectParameterPack); + ParmVarDecl * + TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, + std::optional<unsigned> NumExpansions, + bool ExpectParameterPack); + using inherited::TransformTemplateTypeParmType; /// Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL); + TemplateTypeParmTypeLoc TL, + bool SuppressObjCLifetime); + + QualType BuildSubstTemplateTypeParmType( + TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Final, + Decl *AssociatedDecl, unsigned Index, std::optional<unsigned> PackIndex, + TemplateArgument Arg, SourceLocation NameLoc); /// Transforms an already-substituted template type parameter pack /// into either itself (if we aren't substituting into its pack expansion) /// or the appropriate substituted argument. - QualType TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB, - SubstTemplateTypeParmPackTypeLoc TL); + using inherited::TransformSubstTemplateTypeParmPackType; + QualType + TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB, + SubstTemplateTypeParmPackTypeLoc TL, + bool SuppressObjCLifetime); ExprResult TransformLambdaExpr(LambdaExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - return inherited::TransformLambdaExpr(E); + Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this); + ExprResult Result = inherited::TransformLambdaExpr(E); + if (Result.isInvalid()) + return Result; + + CXXMethodDecl *MD = Result.getAs<LambdaExpr>()->getCallOperator(); + for (ParmVarDecl *PVD : MD->parameters()) { + if (!PVD->hasDefaultArg()) + continue; + Expr *UninstExpr = PVD->getUninstantiatedDefaultArg(); + // FIXME: Obtain the source location for the '=' token. + SourceLocation EqualLoc = UninstExpr->getBeginLoc(); + if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) { + // If substitution fails, the default argument is set to a + // RecoveryExpr that wraps the uninstantiated default argument so + // that downstream diagnostics are omitted. + ExprResult ErrorResult = SemaRef.CreateRecoveryExpr( + UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), + { UninstExpr }, UninstExpr->getType()); + if (ErrorResult.isUsable()) + PVD->setDefaultArg(ErrorResult.get()); + } + } + + return Result; } ExprResult TransformRequiresExpr(RequiresExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - return inherited::TransformRequiresExpr(E); + ExprResult TransReq = inherited::TransformRequiresExpr(E); + if (TransReq.isInvalid()) + return TransReq; + assert(TransReq.get() != E && + "Do not change value of isSatisfied for the existing expression. " + "Create a new expression instead."); + if (E->getBody()->isDependentContext()) { + Sema::SFINAETrap Trap(SemaRef); + // We recreate the RequiresExpr body, but not by instantiating it. + // Produce pending diagnostics for dependent access check. + SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs); + // FIXME: Store SFINAE diagnostics in RequiresExpr for diagnosis. + if (Trap.hasErrorOccurred()) + TransReq.getAs<RequiresExpr>()->setSatisfied(false); + } + return TransReq; } bool TransformRequiresExprRequirements( @@ -1191,6 +1419,7 @@ namespace { DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext(); TemplateDeclInstantiator DeclInstantiator(getSema(), /* DeclContext *Owner */ Owner, TemplateArgs); + DeclInstantiator.setEvaluateConstraints(EvaluateConstraints); return DeclInstantiator.SubstTemplateParams(OrigTPL); } @@ -1200,11 +1429,19 @@ namespace { TransformExprRequirement(concepts::ExprRequirement *Req); concepts::NestedRequirement * TransformNestedRequirement(concepts::NestedRequirement *Req); + ExprResult TransformRequiresTypeParams( + SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE, + RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params, + SmallVectorImpl<QualType> &PTypes, + SmallVectorImpl<ParmVarDecl *> &TransParams, + Sema::ExtParameterInfoBuilder &PInfos); private: - ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm, - SourceLocation loc, - TemplateArgument arg); + ExprResult + transformNonTypeTemplateParmRef(Decl *AssociatedDecl, + const NonTypeTemplateParmDecl *parm, + SourceLocation loc, TemplateArgument arg, + std::optional<unsigned> PackIndex); }; } @@ -1394,6 +1631,9 @@ TemplateName TemplateInstantiator::TransformTemplateName( return Arg.getAsTemplate(); } + auto [AssociatedDecl, Final] = + TemplateArgs.getAssociatedDecl(TTP->getDepth()); + std::optional<unsigned> PackIndex; if (TTP->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); @@ -1402,9 +1642,11 @@ TemplateName TemplateInstantiator::TransformTemplateName( // We have the template argument pack to substitute, but we're not // actually expanding the enclosing pack expansion yet. So, just // keep the entire argument pack. - return getSema().Context.getSubstTemplateTemplateParmPack(TTP, Arg); + return getSema().Context.getSubstTemplateTemplateParmPack( + Arg, AssociatedDecl, TTP->getIndex(), Final); } + PackIndex = getPackIndex(Arg); Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } @@ -1413,8 +1655,10 @@ TemplateName TemplateInstantiator::TransformTemplateName( assert(!Template.getAsQualifiedTemplateName() && "template decl to substitute is qualified?"); - Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template); - return Template; + if (Final) + return Template; + return getSema().Context.getSubstTemplateTemplateParm( + Template, AssociatedDecl, TTP->getIndex(), PackIndex); } } @@ -1423,9 +1667,14 @@ TemplateName TemplateInstantiator::TransformTemplateName( if (getSema().ArgumentPackSubstitutionIndex == -1) return Name; - TemplateArgument Arg = SubstPack->getArgumentPack(); - Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); - return Arg.getAsTemplate().getNameToSubstitute(); + TemplateArgument Pack = SubstPack->getArgumentPack(); + TemplateName Template = + getPackSubstitutedTemplateArgument(getSema(), Pack).getAsTemplate(); + if (SubstPack->getFinal()) + return Template; + return getSema().Context.getSubstTemplateTemplateParm( + Template.getNameToSubstitute(), SubstPack->getAssociatedDecl(), + SubstPack->getIndex(), getPackIndex(Pack)); } return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType, @@ -1469,6 +1718,8 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, return Arg.getAsExpr(); } + auto [AssociatedDecl, _] = TemplateArgs.getAssociatedDecl(NTTP->getDepth()); + std::optional<unsigned> PackIndex; if (NTTP->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); @@ -1486,16 +1737,17 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, QualType ExprType = TargetType.getNonLValueExprType(SemaRef.Context); if (TargetType->isRecordType()) ExprType.addConst(); - + // FIXME: Pass in Final. return new (SemaRef.Context) SubstNonTypeTemplateParmPackExpr( ExprType, TargetType->isReferenceType() ? VK_LValue : VK_PRValue, - NTTP, E->getLocation(), Arg); + E->getLocation(), Arg, AssociatedDecl, NTTP->getPosition()); } - + PackIndex = getPackIndex(Arg); Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } - - return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg); + // FIXME: Don't put subst node on Final replacement. + return transformNonTypeTemplateParmRef(AssociatedDecl, NTTP, E->getLocation(), + Arg, PackIndex); } const LoopHintAttr * @@ -1516,9 +1768,9 @@ TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) { } ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( - NonTypeTemplateParmDecl *parm, - SourceLocation loc, - TemplateArgument arg) { + Decl *AssociatedDecl, const NonTypeTemplateParmDecl *parm, + SourceLocation loc, TemplateArgument arg, + std::optional<unsigned> PackIndex) { ExprResult result; // Determine the substituted parameter type. We can usually infer this from @@ -1586,9 +1838,10 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( return ExprError(); Expr *resultExpr = result.get(); + // FIXME: Don't put subst node on final replacement. return new (SemaRef.Context) SubstNonTypeTemplateParmExpr( - resultExpr->getType(), resultExpr->getValueKind(), loc, parm, refParam, - resultExpr); + resultExpr->getType(), resultExpr->getValueKind(), loc, resultExpr, + AssociatedDecl, parm->getIndex(), PackIndex, refParam); } ExprResult @@ -1599,11 +1852,12 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( return E; } - TemplateArgument Arg = E->getArgumentPack(); - Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); - return transformNonTypeTemplateParmRef(E->getParameterPack(), - E->getParameterPackLocation(), - Arg); + TemplateArgument Pack = E->getArgumentPack(); + TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack); + // FIXME: Don't put subst node on final replacement. + return transformNonTypeTemplateParmRef( + E->getAssociatedDecl(), E->getParameterPack(), + E->getParameterPackLocation(), Arg, getPackIndex(Pack)); } ExprResult @@ -1637,13 +1891,16 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr( // Type=char)), // Type=decltype(2))) // The call to CheckTemplateArgument here produces the ImpCast. - TemplateArgument Converted; - if (SemaRef.CheckTemplateArgument(E->getParameter(), SubstType, - SubstReplacement.get(), - Converted).isInvalid()) + TemplateArgument SugaredConverted, CanonicalConverted; + if (SemaRef + .CheckTemplateArgument(E->getParameter(), SubstType, + SubstReplacement.get(), SugaredConverted, + CanonicalConverted, Sema::CTAK_Specified) + .isInvalid()) return true; - return transformNonTypeTemplateParmRef(E->getParameter(), - E->getExprLoc(), Converted); + return transformNonTypeTemplateParmRef(E->getAssociatedDecl(), + E->getParameter(), E->getExprLoc(), + SugaredConverted, E->getPackIndex()); } ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD, @@ -1744,9 +2001,9 @@ ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( assert(!cast<FunctionDecl>(E->getParam()->getDeclContext())-> getDescribedFunctionTemplate() && "Default arg expressions are never formed in dependent cases."); - return SemaRef.BuildCXXDefaultArgExpr(E->getUsedLocation(), - cast<FunctionDecl>(E->getParam()->getDeclContext()), - E->getParam()); + return SemaRef.BuildCXXDefaultArgExpr( + E->getUsedLocation(), cast<FunctionDecl>(E->getParam()->getDeclContext()), + E->getParam()); } template<typename Fn> @@ -1761,22 +2018,50 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec); } -ParmVarDecl * -TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm, - int indexAdjustment, - Optional<unsigned> NumExpansions, - bool ExpectParameterPack) { - auto NewParm = - SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment, - NumExpansions, ExpectParameterPack); +ParmVarDecl *TemplateInstantiator::TransformFunctionTypeParam( + ParmVarDecl *OldParm, int indexAdjustment, + std::optional<unsigned> NumExpansions, bool ExpectParameterPack) { + auto NewParm = SemaRef.SubstParmVarDecl( + OldParm, TemplateArgs, indexAdjustment, NumExpansions, + ExpectParameterPack, EvaluateConstraints); if (NewParm && SemaRef.getLangOpts().OpenCL) SemaRef.deduceOpenCLAddressSpace(NewParm); return NewParm; } +QualType TemplateInstantiator::BuildSubstTemplateTypeParmType( + TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Final, + Decl *AssociatedDecl, unsigned Index, std::optional<unsigned> PackIndex, + TemplateArgument Arg, SourceLocation NameLoc) { + QualType Replacement = Arg.getAsType(); + + // If the template parameter had ObjC lifetime qualifiers, + // then any such qualifiers on the replacement type are ignored. + if (SuppressObjCLifetime) { + Qualifiers RQs; + RQs = Replacement.getQualifiers(); + RQs.removeObjCLifetime(); + Replacement = + SemaRef.Context.getQualifiedType(Replacement.getUnqualifiedType(), RQs); + } + + if (Final) { + TLB.pushTrivial(SemaRef.Context, Replacement, NameLoc); + return Replacement; + } + // TODO: only do this uniquing once, at the start of instantiation. + QualType Result = getSema().Context.getSubstTemplateTypeParmType( + Replacement, AssociatedDecl, Index, PackIndex); + SubstTemplateTypeParmTypeLoc NewTL = + TLB.push<SubstTemplateTypeParmTypeLoc>(Result); + NewTL.setNameLoc(NameLoc); + return Result; +} + QualType TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL) { + TemplateTypeParmTypeLoc TL, + bool SuppressObjCLifetime) { const TemplateTypeParmType *T = TL.getTypePtr(); if (T->getDepth() < TemplateArgs.getNumLevels()) { // Replace the template type parameter with its corresponding @@ -1813,6 +2098,9 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, return NewT; } + auto [AssociatedDecl, Final] = + TemplateArgs.getAssociatedDecl(T->getDepth()); + std::optional<unsigned> PackIndex; if (T->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); @@ -1821,29 +2109,25 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, // We have the template argument pack, but we're not expanding the // enclosing pack expansion yet. Just save the template argument // pack for later substitution. - QualType Result - = getSema().Context.getSubstTemplateTypeParmPackType(T, Arg); + QualType Result = getSema().Context.getSubstTemplateTypeParmPackType( + AssociatedDecl, T->getIndex(), Final, Arg); SubstTemplateTypeParmPackTypeLoc NewTL = TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } + // PackIndex starts from last element. + PackIndex = getPackIndex(Arg); Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } assert(Arg.getKind() == TemplateArgument::Type && "Template argument kind mismatch"); - QualType Replacement = Arg.getAsType(); - - // TODO: only do this uniquing once, at the start of instantiation. - QualType Result - = getSema().Context.getSubstTemplateTypeParmType(T, Replacement); - SubstTemplateTypeParmTypeLoc NewTL - = TLB.push<SubstTemplateTypeParmTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - return Result; + return BuildSubstTemplateTypeParmType(TLB, SuppressObjCLifetime, Final, + AssociatedDecl, T->getIndex(), + PackIndex, Arg, TL.getNameLoc()); } // The template type parameter comes from an inner template (e.g., @@ -1853,8 +2137,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, TemplateTypeParmDecl *NewTTPDecl = nullptr; if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl()) NewTTPDecl = cast_or_null<TemplateTypeParmDecl>( - TransformDecl(TL.getNameLoc(), OldTTPDecl)); - + TransformDecl(TL.getNameLoc(), OldTTPDecl)); QualType Result = getSema().Context.getTemplateTypeParmType( T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(), T->isParameterPack(), NewTTPDecl); @@ -1863,29 +2146,30 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, return Result; } -QualType -TemplateInstantiator::TransformSubstTemplateTypeParmPackType( - TypeLocBuilder &TLB, - SubstTemplateTypeParmPackTypeLoc TL) { +QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType( + TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL, + bool SuppressObjCLifetime) { + const SubstTemplateTypeParmPackType *T = TL.getTypePtr(); + + Decl *NewReplaced = TransformDecl(TL.getNameLoc(), T->getAssociatedDecl()); + if (getSema().ArgumentPackSubstitutionIndex == -1) { // We aren't expanding the parameter pack, so just return ourselves. - SubstTemplateTypeParmPackTypeLoc NewTL - = TLB.push<SubstTemplateTypeParmPackTypeLoc>(TL.getType()); + QualType Result = TL.getType(); + if (NewReplaced != T->getAssociatedDecl()) + Result = getSema().Context.getSubstTemplateTypeParmPackType( + NewReplaced, T->getIndex(), T->getFinal(), T->getArgumentPack()); + SubstTemplateTypeParmPackTypeLoc NewTL = + TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); - return TL.getType(); + return Result; } - TemplateArgument Arg = TL.getTypePtr()->getArgumentPack(); - Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); - QualType Result = Arg.getAsType(); - - Result = getSema().Context.getSubstTemplateTypeParmType( - TL.getTypePtr()->getReplacedParameter(), - Result); - SubstTemplateTypeParmTypeLoc NewTL - = TLB.push<SubstTemplateTypeParmTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - return Result; + TemplateArgument Pack = T->getArgumentPack(); + TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack); + return BuildSubstTemplateTypeParmType( + TLB, SuppressObjCLifetime, T->getFinal(), NewReplaced, T->getIndex(), + getPackIndex(Pack), Arg, TL.getNameLoc()); } template<typename EntityPrinter> @@ -1914,6 +2198,37 @@ createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) { StringRef(MessageBuf, Message.size())}; } +ExprResult TemplateInstantiator::TransformRequiresTypeParams( + SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE, + RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params, + SmallVectorImpl<QualType> &PTypes, + SmallVectorImpl<ParmVarDecl *> &TransParams, + Sema::ExtParameterInfoBuilder &PInfos) { + + TemplateDeductionInfo Info(KWLoc); + Sema::InstantiatingTemplate TypeInst(SemaRef, KWLoc, + RE, Info, + SourceRange{KWLoc, RBraceLoc}); + Sema::SFINAETrap Trap(SemaRef); + + unsigned ErrorIdx; + if (getDerived().TransformFunctionTypeParams( + KWLoc, Params, /*ParamTypes=*/nullptr, /*ParamInfos=*/nullptr, PTypes, + &TransParams, PInfos, &ErrorIdx) || + Trap.hasErrorOccurred()) { + SmallVector<concepts::Requirement *, 4> TransReqs; + ParmVarDecl *FailedDecl = Params[ErrorIdx]; + // Add a 'failed' Requirement to contain the error that caused the failure + // here. + TransReqs.push_back(RebuildTypeRequirement(createSubstDiag( + SemaRef, Info, [&](llvm::raw_ostream &OS) { OS << *FailedDecl; }))); + return getDerived().RebuildRequiresExpr(KWLoc, Body, TransParams, TransReqs, + RBraceLoc); + } + + return ExprResult{}; +} + concepts::TypeRequirement * TemplateInstantiator::TransformTypeRequirement(concepts::TypeRequirement *Req) { if (!Req->isDependent() && !AlwaysRebuild()) @@ -1971,7 +2286,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { TransExpr = TransExprRes.get(); } - llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq; + std::optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq; const auto &RetReq = Req->getReturnTypeRequirement(); if (RetReq.isEmpty()) TransRetReq.emplace(); @@ -1985,8 +2300,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { Req, Info, OrigTPL->getSourceRange()); if (TPLInst.isInvalid()) return nullptr; - TemplateParameterList *TPL = - TransformTemplateParameterList(OrigTPL); + TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL); if (!TPL) TransRetReq.emplace(createSubstDiag(SemaRef, Info, [&] (llvm::raw_ostream& OS) { @@ -2012,10 +2326,10 @@ TemplateInstantiator::TransformNestedRequirement( concepts::NestedRequirement *Req) { if (!Req->isDependent() && !AlwaysRebuild()) return Req; - if (Req->isSubstitutionFailure()) { + if (Req->hasInvalidConstraint()) { if (AlwaysRebuild()) - return RebuildNestedRequirement( - Req->getSubstitutionDiagnostic()); + return RebuildNestedRequirement(Req->getInvalidConstraintEntity(), + Req->getConstraintSatisfaction()); return Req; } Sema::InstantiatingTemplate ReqInst(SemaRef, @@ -2035,36 +2349,30 @@ TemplateInstantiator::TransformNestedRequirement( Req->getConstraintExpr()->getSourceRange()); if (ConstrInst.isInvalid()) return nullptr; - TransConstraint = TransformExpr(Req->getConstraintExpr()); - if (!TransConstraint.isInvalid()) { - bool CheckSucceeded = - SemaRef.CheckConstraintExpression(TransConstraint.get()); - (void)CheckSucceeded; - assert((CheckSucceeded || Trap.hasErrorOccurred()) && - "CheckConstraintExpression failed, but " - "did not produce a SFINAE error"); - } - // Use version of CheckConstraintSatisfaction that does no substitutions. - if (!TransConstraint.isInvalid() && - !TransConstraint.get()->isInstantiationDependent() && - !Trap.hasErrorOccurred()) { - bool CheckFailed = SemaRef.CheckConstraintSatisfaction( - TransConstraint.get(), Satisfaction); - (void)CheckFailed; - assert((!CheckFailed || Trap.hasErrorOccurred()) && - "CheckConstraintSatisfaction failed, " - "but did not produce a SFINAE error"); - } - if (TransConstraint.isInvalid() || Trap.hasErrorOccurred()) - return RebuildNestedRequirement(createSubstDiag(SemaRef, Info, - [&] (llvm::raw_ostream& OS) { - Req->getConstraintExpr()->printPretty(OS, nullptr, - SemaRef.getPrintingPolicy()); - })); + llvm::SmallVector<Expr *> Result; + if (!SemaRef.CheckConstraintSatisfaction( + nullptr, {Req->getConstraintExpr()}, Result, TemplateArgs, + Req->getConstraintExpr()->getSourceRange(), Satisfaction) && + !Result.empty()) + TransConstraint = Result[0]; + assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled " + "by CheckConstraintSatisfaction."); } - if (TransConstraint.get()->isInstantiationDependent()) + if (TransConstraint.isUsable() && + TransConstraint.get()->isInstantiationDependent()) return new (SemaRef.Context) concepts::NestedRequirement(TransConstraint.get()); + if (TransConstraint.isInvalid() || !TransConstraint.get() || + Satisfaction.HasSubstitutionFailure()) { + SmallString<128> Entity; + llvm::raw_svector_ostream OS(Entity); + Req->getConstraintExpr()->printPretty(OS, nullptr, + SemaRef.getPrintingPolicy()); + char *EntityBuf = new (SemaRef.Context) char[Entity.size()]; + std::copy(Entity.begin(), Entity.end(), EntityBuf); + return new (SemaRef.Context) concepts::NestedRequirement( + SemaRef.Context, StringRef(EntityBuf, Entity.size()), Satisfaction); + } return new (SemaRef.Context) concepts::NestedRequirement( SemaRef.Context, TransConstraint.get(), Satisfaction); } @@ -2196,7 +2504,8 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext, - Qualifiers ThisTypeQuals) { + Qualifiers ThisTypeQuals, + bool EvaluateConstraints) { assert(!CodeSynthesisContexts.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); @@ -2205,6 +2514,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, return T; TemplateInstantiator Instantiator(*this, Args, Loc, Entity); + Instantiator.setEvaluateConstraints(EvaluateConstraints); TypeLocBuilder TLB; @@ -2349,9 +2659,19 @@ namespace { bool Sema::SubstTypeConstraint( TemplateTypeParmDecl *Inst, const TypeConstraint *TC, - const MultiLevelTemplateArgumentList &TemplateArgs) { + const MultiLevelTemplateArgumentList &TemplateArgs, + bool EvaluateConstraints) { const ASTTemplateArgumentListInfo *TemplArgInfo = TC->getTemplateArgsAsWritten(); + + if (!EvaluateConstraints) { + Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(), + TC->getConceptNameInfo(), TC->getNamedConcept(), + TC->getNamedConcept(), TemplArgInfo, + TC->getImmediatelyDeclaredConstraint()); + return false; + } + TemplateArgumentListInfo InstArgs; if (TemplArgInfo) { @@ -2370,11 +2690,10 @@ bool Sema::SubstTypeConstraint( : SourceLocation()); } -ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, - const MultiLevelTemplateArgumentList &TemplateArgs, - int indexAdjustment, - Optional<unsigned> NumExpansions, - bool ExpectParameterPack) { +ParmVarDecl *Sema::SubstParmVarDecl( + ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs, + int indexAdjustment, std::optional<unsigned> NumExpansions, + bool ExpectParameterPack, bool EvaluateConstraint) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); TypeSourceInfo *NewDI = nullptr; @@ -2432,9 +2751,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, // template's described function, but we might also get here later. // Make sure we do not instantiate the TypeConstraint more than once. if (Inst && !Inst->getTypeConstraint()) { - // TODO: Concepts: do not instantiate the constraint (delayed constraint - // substitution) - if (SubstTypeConstraint(Inst, TC, TemplateArgs)) + if (SubstTypeConstraint(Inst, TC, TemplateArgs, EvaluateConstraint)) return nullptr; } } @@ -2457,29 +2774,17 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, NewParm->setUnparsedDefaultArg(); UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm); } else if (Expr *Arg = OldParm->getDefaultArg()) { - FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext()); - if (OwningFunc->isInLocalScopeForInstantiation()) { - // Instantiate default arguments for methods of local classes (DR1484) - // and non-defining declarations. - Sema::ContextRAII SavedContext(*this, OwningFunc); - LocalInstantiationScope Local(*this, true); - ExprResult NewArg = SubstExpr(Arg, TemplateArgs); - if (NewArg.isUsable()) { - // It would be nice if we still had this. - SourceLocation EqualLoc = NewArg.get()->getBeginLoc(); - ExprResult Result = - ConvertParamDefaultArgument(NewParm, NewArg.get(), EqualLoc); - if (Result.isInvalid()) - return nullptr; - - SetParamDefaultArgument(NewParm, Result.getAs<Expr>(), EqualLoc); - } - } else { - // FIXME: if we non-lazily instantiated non-dependent default args for - // non-dependent parameter types we could remove a bunch of duplicate - // conversion warnings for such arguments. - NewParm->setUninstantiatedDefaultArg(Arg); - } + // Default arguments cannot be substituted until the declaration context + // for the associated function or lambda capture class is available. + // This is necessary for cases like the following where construction of + // the lambda capture class for the outer lambda is dependent on the + // parameter types but where the default argument is dependent on the + // outer lambda's declaration context. + // template <typename T> + // auto f() { + // return [](T = []{ return T{}; }()) { return 0; }; + // } + NewParm->setUninstantiatedDefaultArg(Arg); } NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg()); @@ -2524,6 +2829,88 @@ bool Sema::SubstParmTypes( Loc, Params, nullptr, ExtParamInfos, ParamTypes, OutParams, ParamInfos); } +/// Substitute the given template arguments into the default argument. +bool Sema::SubstDefaultArgument( + SourceLocation Loc, + ParmVarDecl *Param, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool ForCallExpr) { + FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext()); + Expr *PatternExpr = Param->getUninstantiatedDefaultArg(); + + EnterExpressionEvaluationContext EvalContext( + *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); + + InstantiatingTemplate Inst(*this, Loc, Param, TemplateArgs.getInnermost()); + if (Inst.isInvalid()) + return true; + if (Inst.isAlreadyInstantiating()) { + Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; + Param->setInvalidDecl(); + return true; + } + + ExprResult Result; + { + // C++ [dcl.fct.default]p5: + // The names in the [default argument] expression are bound, and + // the semantic constraints are checked, at the point where the + // default argument expression appears. + ContextRAII SavedContext(*this, FD); + std::unique_ptr<LocalInstantiationScope> LIS; + + if (ForCallExpr) { + // When instantiating a default argument due to use in a call expression, + // an instantiation scope that includes the parameters of the callee is + // required to satisfy references from the default argument. For example: + // template<typename T> void f(T a, int = decltype(a)()); + // void g() { f(0); } + LIS = std::make_unique<LocalInstantiationScope>(*this); + FunctionDecl *PatternFD = FD->getTemplateInstantiationPattern( + /*ForDefinition*/ false); + if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs)) + return true; + } + + runWithSufficientStackSpace(Loc, [&] { + Result = SubstInitializer(PatternExpr, TemplateArgs, + /*DirectInit*/false); + }); + } + if (Result.isInvalid()) + return true; + + if (ForCallExpr) { + // Check the expression as an initializer for the parameter. + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Context, Param); + InitializationKind Kind = InitializationKind::CreateCopy( + Param->getLocation(), + /*FIXME:EqualLoc*/ PatternExpr->getBeginLoc()); + Expr *ResultE = Result.getAs<Expr>(); + + InitializationSequence InitSeq(*this, Entity, Kind, ResultE); + Result = InitSeq.Perform(*this, Entity, Kind, ResultE); + if (Result.isInvalid()) + return true; + + Result = + ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(), + /*DiscardedValue*/ false); + } else { + // FIXME: Obtain the source location for the '=' token. + SourceLocation EqualLoc = PatternExpr->getBeginLoc(); + Result = ConvertParamDefaultArgument(Param, Result.getAs<Expr>(), EqualLoc); + } + if (Result.isInvalid()) + return true; + + // Remember the instantiated default argument. + Param->setDefaultArg(Result.getAs<Expr>()); + + return false; +} + /// Perform substitution on the base class specifiers of the /// given class template specialization. /// @@ -2556,7 +2943,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, Unexpanded); bool ShouldExpand = false; bool RetainExpansion = false; - Optional<unsigned> NumExpansions; + std::optional<unsigned> NumExpansions; if (CheckParameterPacksForExpansion(Base.getEllipsisLoc(), Base.getSourceRange(), Unexpanded, @@ -2743,6 +3130,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Instantiation->setInvalidDecl(); TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); + Instantiator.setEvaluateConstraints(false); SmallVector<Decl*, 4> Fields; // Delay instantiation of late parsed attributes. LateInstantiatedAttrVec LateAttrs; @@ -3033,6 +3421,8 @@ bool Sema::InstantiateInClassInitializer( ContextRAII SavedContext(*this, Instantiation->getParent()); EnterExpressionEvaluationContext EvalContext( *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); + ExprEvalContexts.back().DelayedDefaultInitializationContext = { + PointOfInstantiation, Instantiation, CurContext}; LocalInstantiationScope Scope(*this, true); @@ -3130,7 +3520,7 @@ getPatternForClassTemplateSpecialization( } else { Matched.push_back(PartialSpecMatchResult()); Matched.back().Partial = Partial; - Matched.back().Args = Info.take(); + Matched.back().Args = Info.takeCanonical(); } } @@ -3521,11 +3911,9 @@ bool Sema::SubstTemplateArguments( ArrayRef<TemplateArgumentLoc> Args, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateArgumentListInfo &Out) { - TemplateInstantiator Instantiator(*this, TemplateArgs, - SourceLocation(), + TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), DeclarationName()); - return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), - Out); + return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out); } ExprResult @@ -3539,11 +3927,23 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) { return Instantiator.TransformExpr(E); } +ExprResult +Sema::SubstConstraintExpr(Expr *E, + const MultiLevelTemplateArgumentList &TemplateArgs) { + if (!E) + return E; + + // This is where we need to make sure we 'know' constraint checking needs to + // happen. + TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), + DeclarationName()); + return Instantiator.TransformExpr(E); +} + ExprResult Sema::SubstInitializer(Expr *Init, const MultiLevelTemplateArgumentList &TemplateArgs, bool CXXDirectInit) { - TemplateInstantiator Instantiator(*this, TemplateArgs, - SourceLocation(), + TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), DeclarationName()); return Instantiator.TransformInitializer(Init, CXXDirectInit); } |