aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp542
1 files changed, 339 insertions, 203 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp
index e12186d7d82f..c2e8ed0c602e 100644
--- a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -20,7 +20,9 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/PrettyDeclStackTrace.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Stack.h"
@@ -35,6 +37,7 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TimeProfiler.h"
@@ -79,6 +82,94 @@ struct Response {
return R;
}
};
+
+// Retrieve the primary template for a lambda call operator. It's
+// unfortunate that we only have the mappings of call operators rather
+// than lambda classes.
+const FunctionDecl *
+getPrimaryTemplateOfGenericLambda(const FunctionDecl *LambdaCallOperator) {
+ if (!isLambdaCallOperator(LambdaCallOperator))
+ return LambdaCallOperator;
+ while (true) {
+ if (auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(
+ LambdaCallOperator->getDescribedTemplate());
+ FTD && FTD->getInstantiatedFromMemberTemplate()) {
+ LambdaCallOperator =
+ FTD->getInstantiatedFromMemberTemplate()->getTemplatedDecl();
+ } else if (LambdaCallOperator->getPrimaryTemplate()) {
+ // Cases where the lambda operator is instantiated in
+ // TemplateDeclInstantiator::VisitCXXMethodDecl.
+ LambdaCallOperator =
+ LambdaCallOperator->getPrimaryTemplate()->getTemplatedDecl();
+ } else if (auto *Prev = cast<CXXMethodDecl>(LambdaCallOperator)
+ ->getInstantiatedFromMemberFunction())
+ LambdaCallOperator = Prev;
+ else
+ break;
+ }
+ return LambdaCallOperator;
+}
+
+struct EnclosingTypeAliasTemplateDetails {
+ TypeAliasTemplateDecl *Template = nullptr;
+ TypeAliasTemplateDecl *PrimaryTypeAliasDecl = nullptr;
+ ArrayRef<TemplateArgument> AssociatedTemplateArguments;
+
+ explicit operator bool() noexcept { return Template; }
+};
+
+// Find the enclosing type alias template Decl from CodeSynthesisContexts, as
+// well as its primary template and instantiating template arguments.
+EnclosingTypeAliasTemplateDetails
+getEnclosingTypeAliasTemplateDecl(Sema &SemaRef) {
+ for (auto &CSC : llvm::reverse(SemaRef.CodeSynthesisContexts)) {
+ if (CSC.Kind != Sema::CodeSynthesisContext::SynthesisKind::
+ TypeAliasTemplateInstantiation)
+ continue;
+ EnclosingTypeAliasTemplateDetails Result;
+ auto *TATD = cast<TypeAliasTemplateDecl>(CSC.Entity),
+ *Next = TATD->getInstantiatedFromMemberTemplate();
+ Result = {
+ /*Template=*/TATD,
+ /*PrimaryTypeAliasDecl=*/TATD,
+ /*AssociatedTemplateArguments=*/CSC.template_arguments(),
+ };
+ while (Next) {
+ Result.PrimaryTypeAliasDecl = Next;
+ Next = Next->getInstantiatedFromMemberTemplate();
+ }
+ return Result;
+ }
+ return {};
+}
+
+// Check if we are currently inside of a lambda expression that is
+// surrounded by a using alias declaration. e.g.
+// template <class> using type = decltype([](auto) { ^ }());
+// We have to do so since a TypeAliasTemplateDecl (or a TypeAliasDecl) is never
+// a DeclContext, nor does it have an associated specialization Decl from which
+// we could collect these template arguments.
+bool isLambdaEnclosedByTypeAliasDecl(
+ const FunctionDecl *LambdaCallOperator,
+ const TypeAliasTemplateDecl *PrimaryTypeAliasDecl) {
+ struct Visitor : RecursiveASTVisitor<Visitor> {
+ Visitor(const FunctionDecl *CallOperator) : CallOperator(CallOperator) {}
+ bool VisitLambdaExpr(const LambdaExpr *LE) {
+ // Return true to bail out of the traversal, implying the Decl contains
+ // the lambda.
+ return getPrimaryTemplateOfGenericLambda(LE->getCallOperator()) !=
+ CallOperator;
+ }
+ const FunctionDecl *CallOperator;
+ };
+
+ QualType Underlying =
+ PrimaryTypeAliasDecl->getTemplatedDecl()->getUnderlyingType();
+
+ return !Visitor(getPrimaryTemplateOfGenericLambda(LambdaCallOperator))
+ .TraverseType(Underlying);
+}
+
// Add template arguments from a variable template instantiation.
Response
HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec,
@@ -175,10 +266,11 @@ HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
return Response::UseNextDecl(ClassTemplSpec);
}
-Response HandleFunction(const FunctionDecl *Function,
+Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
MultiLevelTemplateArgumentList &Result,
const FunctionDecl *Pattern, bool RelativeToPrimary,
- bool ForConstraintInstantiation) {
+ bool ForConstraintInstantiation,
+ bool ForDefaultArgumentSubstitution) {
// Add template arguments from a function template specialization.
if (!RelativeToPrimary &&
Function->getTemplateSpecializationKindForInstantiation() ==
@@ -198,10 +290,18 @@ Response HandleFunction(const FunctionDecl *Function,
TemplateArgs->asArray(),
/*Final=*/false);
+ if (RelativeToPrimary &&
+ (Function->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization ||
+ (Function->getFriendObjectKind() &&
+ !Function->getPrimaryTemplate()->getFriendObjectKind())))
+ return Response::UseNextDecl(Function);
+
// 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())
+ if (!ForDefaultArgumentSubstitution &&
+ Function->getPrimaryTemplate()->isMemberSpecialization())
return Response::Done();
// If this function is a generic lambda specialization, we are done.
@@ -241,10 +341,38 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) {
if (NNS->isInstantiationDependent()) {
- if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>())
+ if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>()) {
+ ArrayRef<TemplateArgument> Arguments = TSTy->template_arguments();
+ // Prefer template arguments from the injected-class-type if possible.
+ // For example,
+ // ```cpp
+ // template <class... Pack> struct S {
+ // template <class T> void foo();
+ // };
+ // template <class... Pack> template <class T>
+ // ^^^^^^^^^^^^^ InjectedTemplateArgs
+ // They're of kind TemplateArgument::Pack, not of
+ // TemplateArgument::Type.
+ // void S<Pack...>::foo() {}
+ // ^^^^^^^
+ // TSTy->template_arguments() (which are of PackExpansionType)
+ // ```
+ // This meets the contract in
+ // TreeTransform::TryExpandParameterPacks that the template arguments
+ // for unexpanded parameters should be of a Pack kind.
+ if (TSTy->isCurrentInstantiation()) {
+ auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl();
+ if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
+ Arguments = CTD->getInjectedTemplateArgs();
+ else if (auto *Specialization =
+ dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ Arguments =
+ Specialization->getTemplateInstantiationArgs().asArray();
+ }
Result.addOuterTemplateArguments(
- const_cast<FunctionTemplateDecl *>(FTD), TSTy->template_arguments(),
+ const_cast<FunctionTemplateDecl *>(FTD), Arguments,
/*Final=*/false);
+ }
}
NNS = NNS->getPrefix();
@@ -254,7 +382,7 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
return Response::ChangeDecl(FTD->getLexicalDeclContext());
}
-Response HandleRecordDecl(const CXXRecordDecl *Rec,
+Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
MultiLevelTemplateArgumentList &Result,
ASTContext &Context,
bool ForConstraintInstantiation) {
@@ -283,11 +411,38 @@ Response HandleRecordDecl(const CXXRecordDecl *Rec,
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())
+ // This is to make sure we pick up the VarTemplateSpecializationDecl or the
+ // TypeAliasTemplateDecl that this lambda is defined inside of.
+ if (Rec->isLambda()) {
if (const Decl *LCD = Rec->getLambdaContextDecl())
return Response::ChangeDecl(LCD);
+ // Retrieve the template arguments for a using alias declaration.
+ // This is necessary for constraint checking, since we always keep
+ // constraints relative to the primary template.
+ if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef);
+ ForConstraintInstantiation && TypeAlias) {
+ if (isLambdaEnclosedByTypeAliasDecl(Rec->getLambdaCallOperator(),
+ TypeAlias.PrimaryTypeAliasDecl)) {
+ Result.addOuterTemplateArguments(TypeAlias.Template,
+ TypeAlias.AssociatedTemplateArguments,
+ /*Final=*/false);
+ // Visit the parent of the current type alias declaration rather than
+ // the lambda thereof.
+ // E.g., in the following example:
+ // struct S {
+ // template <class> using T = decltype([]<Concept> {} ());
+ // };
+ // void foo() {
+ // S::T var;
+ // }
+ // The instantiated lambda expression (which we're visiting at 'var')
+ // has a function DeclContext 'foo' rather than the Record DeclContext
+ // S. This seems to be an oversight to me that we may want to set a
+ // Sema Context from the CXXScopeSpec before substituting into T.
+ return Response::ChangeDecl(TypeAlias.Template->getDeclContext());
+ }
+ }
+ }
return Response::UseNextDecl(Rec);
}
@@ -308,39 +463,11 @@ Response HandleGenericDeclContext(const Decl *CurDecl) {
} // namespace TemplateInstArgsHelpers
} // namespace
-/// Retrieve the template argument list(s) that should be used to
-/// instantiate the definition of the given declaration.
-///
-/// \param ND the declaration for which we are computing template instantiation
-/// arguments.
-///
-/// \param DC In the event we don't HAVE a declaration yet, we instead provide
-/// the decl context where it will be created. In this case, the `Innermost`
-/// should likely be provided. If ND is non-null, this is ignored.
-///
-/// \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
-/// dealing with a specialization. This is only relevant for function
-/// template specializations.
-///
-/// \param Pattern If non-NULL, indicates the pattern from which we will be
-/// 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 *ND, const DeclContext *DC, bool Final,
- const TemplateArgumentList *Innermost, bool RelativeToPrimary,
+ std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
const FunctionDecl *Pattern, bool ForConstraintInstantiation,
- bool SkipForSpecialization) {
+ bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
@@ -352,8 +479,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
CurDecl = Decl::castFromDeclContext(DC);
if (Innermost) {
- Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND),
- Innermost->asArray(), Final);
+ Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost,
+ Final);
// Populate placeholder template arguments for TemplateTemplateParmDecls.
// This is essential for the case e.g.
//
@@ -381,10 +508,12 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
R = HandleClassTemplateSpec(ClassTemplSpec, Result,
SkipForSpecialization);
} else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
- R = HandleFunction(Function, Result, Pattern, RelativeToPrimary,
- ForConstraintInstantiation);
+ R = HandleFunction(*this, Function, Result, Pattern, RelativeToPrimary,
+ ForConstraintInstantiation,
+ ForDefaultArgumentSubstitution);
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
- R = HandleRecordDecl(Rec, Result, Context, ForConstraintInstantiation);
+ R = HandleRecordDecl(*this, Rec, Result, Context,
+ ForConstraintInstantiation);
} else if (const auto *CSD =
dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
R = HandleImplicitConceptSpecializationDecl(CSD, Result);
@@ -441,6 +570,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case BuildingBuiltinDumpStructCall:
case LambdaExpressionSubstitution:
case BuildingDeductionGuides:
+ case TypeAliasTemplateInstantiation:
return false;
// This function should never be called when Kind's value is Memoization.
@@ -519,9 +649,9 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
: InstantiatingTemplate(SemaRef, Kind, PointOfInstantiation,
InstantiationRange, FunctionTemplate, nullptr,
TemplateArgs, &DeductionInfo) {
- assert(
- Kind == CodeSynthesisContext::ExplicitTemplateArgumentSubstitution ||
- Kind == CodeSynthesisContext::DeducedTemplateArgumentSubstitution);
+ assert(Kind == CodeSynthesisContext::ExplicitTemplateArgumentSubstitution ||
+ Kind == CodeSynthesisContext::DeducedTemplateArgumentSubstitution ||
+ Kind == CodeSynthesisContext::BuildingDeductionGuides);
}
Sema::InstantiatingTemplate::InstantiatingTemplate(
@@ -587,6 +717,15 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
TemplateArgs) {}
Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TypeAliasTemplateDecl *Entity, ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::TypeAliasTemplateInstantiation,
+ PointOfInstantiation, InstantiationRange, /*Entity=*/Entity,
+ /*Template=*/nullptr, TemplateArgs) {}
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template,
NamedDecl *Param, ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange)
@@ -758,8 +897,6 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
return true;
}
-/// Prints the current instantiation stack through a series of
-/// notes.
void Sema::PrintInstantiationStack() {
// Determine which template instantiations to skip, if any.
unsigned SkipStart = CodeSynthesisContexts.size(), SkipEnd = SkipStart;
@@ -825,11 +962,6 @@ void Sema::PrintInstantiationStack() {
Diags.Report(Active->PointOfInstantiation,
diag::note_template_class_instantiation_here)
<< CTD << Active->InstantiationRange;
- } else {
- Diags.Report(Active->PointOfInstantiation,
- diag::note_template_type_alias_instantiation_here)
- << cast<TypeAliasTemplateDecl>(D)
- << Active->InstantiationRange;
}
break;
}
@@ -989,7 +1121,8 @@ void Sema::PrintInstantiationStack() {
case CodeSynthesisContext::DeclaringSpecialMember:
Diags.Report(Active->PointOfInstantiation,
diag::note_in_declaration_of_implicit_special_member)
- << cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember;
+ << cast<CXXRecordDecl>(Active->Entity)
+ << llvm::to_underlying(Active->SpecialMember);
break;
case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
@@ -1007,7 +1140,8 @@ void Sema::PrintInstantiationStack() {
auto *MD = cast<CXXMethodDecl>(FD);
Diags.Report(Active->PointOfInstantiation,
diag::note_member_synthesized_at)
- << MD->isExplicitlyDefaulted() << DFK.asSpecialMember()
+ << MD->isExplicitlyDefaulted()
+ << llvm::to_underlying(DFK.asSpecialMember())
<< Context.getTagDeclType(MD->getParent());
} else if (DFK.isComparison()) {
QualType RecordType = FD->getParamDecl(0)
@@ -1103,6 +1237,12 @@ void Sema::PrintInstantiationStack() {
Diags.Report(Active->PointOfInstantiation,
diag::note_building_deduction_guide_here);
break;
+ case CodeSynthesisContext::TypeAliasTemplateInstantiation:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_template_type_alias_instantiation_here)
+ << cast<TypeAliasTemplateDecl>(Active->Entity)
+ << Active->InstantiationRange;
+ break;
}
}
}
@@ -1118,12 +1258,13 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
++Active)
{
switch (Active->Kind) {
- case CodeSynthesisContext::TemplateInstantiation:
+ case CodeSynthesisContext::TypeAliasTemplateInstantiation:
// An instantiation of an alias template may or may not be a SFINAE
// context, depending on what else is on the stack.
if (isa<TypeAliasTemplateDecl>(Active->Entity))
break;
[[fallthrough]];
+ case CodeSynthesisContext::TemplateInstantiation:
case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
case CodeSynthesisContext::ExceptionSpecInstantiation:
case CodeSynthesisContext::ConstraintsCheck:
@@ -1382,6 +1523,7 @@ namespace {
NamedDecl *FirstQualifierInScope = nullptr,
bool AllowInjectedClassName = false);
+ const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH);
const NoInlineAttr *TransformStmtNoInlineAttr(const Stmt *OrigS,
const Stmt *InstS,
@@ -1418,6 +1560,54 @@ namespace {
return inherited::TransformFunctionProtoType(TLB, TL);
}
+ QualType TransformInjectedClassNameType(TypeLocBuilder &TLB,
+ InjectedClassNameTypeLoc TL) {
+ auto Type = inherited::TransformInjectedClassNameType(TLB, TL);
+ // Special case for transforming a deduction guide, we return a
+ // transformed TemplateSpecializationType.
+ if (Type.isNull() &&
+ SemaRef.CodeSynthesisContexts.back().Kind ==
+ Sema::CodeSynthesisContext::BuildingDeductionGuides) {
+ // Return a TemplateSpecializationType for transforming a deduction
+ // guide.
+ if (auto *ICT = TL.getType()->getAs<InjectedClassNameType>()) {
+ auto Type =
+ inherited::TransformType(ICT->getInjectedSpecializationType());
+ TLB.pushTrivial(SemaRef.Context, Type, TL.getNameLoc());
+ return Type;
+ }
+ }
+ return Type;
+ }
+ // Override the default version to handle a rewrite-template-arg-pack case
+ // for building a deduction guide.
+ bool TransformTemplateArgument(const TemplateArgumentLoc &Input,
+ TemplateArgumentLoc &Output,
+ bool Uneval = false) {
+ const TemplateArgument &Arg = Input.getArgument();
+ std::vector<TemplateArgument> TArgs;
+ switch (Arg.getKind()) {
+ case TemplateArgument::Pack:
+ // Literally rewrite the template argument pack, instead of unpacking
+ // it.
+ for (auto &pack : Arg.getPackAsArray()) {
+ TemplateArgumentLoc Input = SemaRef.getTrivialTemplateArgumentLoc(
+ pack, QualType(), SourceLocation{});
+ TemplateArgumentLoc Output;
+ if (SemaRef.SubstTemplateArgument(Input, TemplateArgs, Output))
+ return true; // fails
+ TArgs.push_back(Output.getArgument());
+ }
+ Output = SemaRef.getTrivialTemplateArgumentLoc(
+ TemplateArgument(llvm::ArrayRef(TArgs).copy(SemaRef.Context)),
+ QualType(), SourceLocation{});
+ return false;
+ default:
+ break;
+ }
+ return inherited::TransformTemplateArgument(Input, Output, Uneval);
+ }
+
template<typename Fn>
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL,
@@ -1451,6 +1641,23 @@ namespace {
SubstTemplateTypeParmPackTypeLoc TL,
bool SuppressObjCLifetime);
+ CXXRecordDecl::LambdaDependencyKind
+ ComputeLambdaDependency(LambdaScopeInfo *LSI) {
+ if (auto TypeAlias =
+ TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
+ getSema());
+ TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
+ LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
+ unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
+ if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
+ return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
+ for (const TemplateArgument &TA : TypeAlias.AssociatedTemplateArguments)
+ if (TA.isDependent())
+ return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
+ }
+ return inherited::ComputeLambdaDependency(LSI);
+ }
+
ExprResult TransformLambdaExpr(LambdaExpr *E) {
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
@@ -1625,7 +1832,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
- TemplateName Template = Arg.getAsTemplate().getNameToSubstitute();
+ TemplateName Template = Arg.getAsTemplate();
assert(!Template.isNull() && Template.getAsTemplateDecl() &&
"Wrong kind of template template argument");
return Template.getAsTemplateDecl();
@@ -1798,10 +2005,8 @@ TemplateName TemplateInstantiator::TransformTemplateName(
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
- TemplateName Template = Arg.getAsTemplate().getNameToSubstitute();
+ TemplateName Template = Arg.getAsTemplate();
assert(!Template.isNull() && "Null template template argument");
- assert(!Template.getAsQualifiedTemplateName() &&
- "template decl to substitute is qualified?");
if (Final)
return Template;
@@ -1821,8 +2026,8 @@ TemplateName TemplateInstantiator::TransformTemplateName(
if (SubstPack->getFinal())
return Template;
return getSema().Context.getSubstTemplateTemplateParm(
- Template.getNameToSubstitute(), SubstPack->getAssociatedDecl(),
- SubstPack->getIndex(), getPackIndex(Pack));
+ Template, SubstPack->getAssociatedDecl(), SubstPack->getIndex(),
+ getPackIndex(Pack));
}
return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
@@ -1898,6 +2103,21 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
Arg, PackIndex);
}
+const CXXAssumeAttr *
+TemplateInstantiator::TransformCXXAssumeAttr(const CXXAssumeAttr *AA) {
+ ExprResult Res = getDerived().TransformExpr(AA->getAssumption());
+ if (!Res.isUsable())
+ return AA;
+
+ Res = getSema().BuildCXXAssumeExpr(Res.get(), AA->getAttrName(),
+ AA->getRange());
+ if (!Res.isUsable())
+ return AA;
+
+ return CXXAssumeAttr::CreateImplicit(getSema().Context, Res.get(),
+ AA->getRange());
+}
+
const LoopHintAttr *
TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
Expr *TransformedExpr = getDerived().TransformExpr(LH->getValue()).get();
@@ -1906,13 +2126,26 @@ TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
return LH;
// Generate error if there is a problem with the value.
- if (getSema().CheckLoopHintExpr(TransformedExpr, LH->getLocation()))
+ if (getSema().CheckLoopHintExpr(TransformedExpr, LH->getLocation(),
+ LH->getSemanticSpelling() ==
+ LoopHintAttr::Pragma_unroll))
return LH;
+ LoopHintAttr::OptionType Option = LH->getOption();
+ LoopHintAttr::LoopHintState State = LH->getState();
+
+ llvm::APSInt ValueAPS =
+ TransformedExpr->EvaluateKnownConstInt(getSema().getASTContext());
+ // The values of 0 and 1 block any unrolling of the loop.
+ if (ValueAPS.isZero() || ValueAPS.isOne()) {
+ Option = LoopHintAttr::Unroll;
+ State = LoopHintAttr::Disable;
+ }
+
// Create new LoopHintValueAttr with integral expression in place of the
// non-type template parameter.
- return LoopHintAttr::CreateImplicit(getSema().Context, LH->getOption(),
- LH->getState(), TransformedExpr, *LH);
+ return LoopHintAttr::CreateImplicit(getSema().Context, Option, State,
+ TransformedExpr, *LH);
}
const NoInlineAttr *TemplateInstantiator::TransformStmtNoInlineAttr(
const Stmt *OrigS, const Stmt *InstS, const NoInlineAttr *A) {
@@ -2257,10 +2490,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
assert(Arg.getKind() == TemplateArgument::Type &&
"unexpected nontype template argument kind in template rewrite");
QualType NewT = Arg.getAsType();
- assert(isa<TemplateTypeParmType>(NewT) &&
- "type parm not rewritten to type parm");
- auto NewTL = TLB.push<TemplateTypeParmTypeLoc>(NewT);
- NewTL.setNameLoc(TL.getNameLoc());
+ TLB.pushTrivial(SemaRef.Context, NewT, TL.getNameLoc());
return NewT;
}
@@ -2352,16 +2582,12 @@ createSubstDiag(Sema &S, TemplateDeductionInfo &Info,
} else {
ErrorLoc = Info.getLocation();
}
- char *MessageBuf = new (S.Context) char[Message.size()];
- std::copy(Message.begin(), Message.end(), MessageBuf);
SmallString<128> Entity;
llvm::raw_svector_ostream OS(Entity);
Printer(OS);
- char *EntityBuf = new (S.Context) char[Entity.size()];
- std::copy(Entity.begin(), Entity.end(), EntityBuf);
- return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
- StringRef(EntityBuf, Entity.size()), ErrorLoc,
- StringRef(MessageBuf, Message.size())};
+ const ASTContext &C = S.Context;
+ return new (C) concepts::Requirement::SubstitutionDiagnostic{
+ C.backupStr(Entity), ErrorLoc, C.backupStr(Message)};
}
concepts::Requirement::SubstitutionDiagnostic *
@@ -2370,10 +2596,9 @@ concepts::createSubstDiagAt(Sema &S, SourceLocation Location,
SmallString<128> Entity;
llvm::raw_svector_ostream OS(Entity);
Printer(OS);
- char *EntityBuf = new (S.Context) char[Entity.size()];
- llvm::copy(Entity, EntityBuf);
- return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
- /*SubstitutedEntity=*/StringRef(EntityBuf, Entity.size()),
+ const ASTContext &C = S.Context;
+ return new (C) concepts::Requirement::SubstitutionDiagnostic{
+ /*SubstitutedEntity=*/C.backupStr(Entity),
/*DiagLoc=*/Location, /*DiagMessage=*/StringRef()};
}
@@ -2481,7 +2706,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
if (TPLInst.isInvalid())
return nullptr;
TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL);
- if (!TPL)
+ if (!TPL || Trap.hasErrorOccurred())
TransRetReq.emplace(createSubstDiag(SemaRef, Info,
[&] (llvm::raw_ostream& OS) {
RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint()
@@ -2549,56 +2774,23 @@ TemplateInstantiator::TransformNestedRequirement(
assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled "
"by CheckConstraintSatisfaction.");
}
+ ASTContext &C = SemaRef.Context;
if (TransConstraint.isUsable() &&
TransConstraint.get()->isInstantiationDependent())
- return new (SemaRef.Context)
- concepts::NestedRequirement(TransConstraint.get());
+ return new (C) 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 (C) concepts::NestedRequirement(
+ SemaRef.Context, C.backupStr(Entity), Satisfaction);
}
- return new (SemaRef.Context) concepts::NestedRequirement(
- SemaRef.Context, TransConstraint.get(), Satisfaction);
+ return new (C)
+ concepts::NestedRequirement(C, TransConstraint.get(), Satisfaction);
}
-
-/// Perform substitution on the type T with a given set of template
-/// arguments.
-///
-/// This routine substitutes the given template arguments into the
-/// type T and produces the instantiated type.
-///
-/// \param T the type into which the template arguments will be
-/// substituted. If this type is not dependent, it will be returned
-/// immediately.
-///
-/// \param Args the template arguments that will be
-/// substituted for the top-level template parameters within T.
-///
-/// \param Loc the location in the source code where this substitution
-/// is being performed. It will typically be the location of the
-/// declarator (if we're instantiating the type of some declaration)
-/// or the location of the type in the source code (if, e.g., we're
-/// instantiating the type of a cast expression).
-///
-/// \param Entity the name of the entity associated with a declaration
-/// being instantiated (if any). May be empty to indicate that there
-/// is no such entity (if, e.g., this is a type that occurs as part of
-/// a cast expression) or that the entity has no name (e.g., an
-/// unnamed function parameter).
-///
-/// \param AllowDeducedTST Whether a DeducedTemplateSpecializationType is
-/// acceptable as the top level type of the result.
-///
-/// \returns If the instantiation succeeds, the instantiated
-/// type. Otherwise, produces diagnostics and returns a NULL type.
TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &Args,
SourceLocation Loc,
@@ -2686,10 +2878,6 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
return false;
}
-/// A form of SubstType intended specifically for instantiating the
-/// type of a FunctionDecl. Its purpose is solely to force the
-/// instantiation of default-argument expressions and to avoid
-/// instantiating an exception-specification.
TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &Args,
SourceLocation Loc,
@@ -2872,7 +3060,8 @@ bool Sema::SubstTypeConstraint(
}
return AttachTypeConstraint(
TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
- TC->getNamedConcept(), &InstArgs, Inst,
+ TC->getNamedConcept(),
+ /*FoundDecl=*/TC->getConceptReference()->getFoundDecl(), &InstArgs, Inst,
Inst->isParameterPack()
? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
->getEllipsisLoc()
@@ -3000,9 +3189,6 @@ ParmVarDecl *Sema::SubstParmVarDecl(
return NewParm;
}
-/// Substitute the given template arguments into the given set of
-/// parameters, producing the set of parameter types that would be generated
-/// from such a substitution.
bool Sema::SubstParmTypes(
SourceLocation Loc, ArrayRef<ParmVarDecl *> Params,
const FunctionProtoType::ExtParameterInfo *ExtParamInfos,
@@ -3020,7 +3206,6 @@ 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,
@@ -3065,7 +3250,7 @@ bool Sema::SubstDefaultArgument(
runWithSufficientStackSpace(Loc, [&] {
Result = SubstInitializer(PatternExpr, TemplateArgs,
- /*DirectInit*/false);
+ /*DirectInit*/ false);
});
}
if (Result.isInvalid())
@@ -3102,12 +3287,6 @@ bool Sema::SubstDefaultArgument(
return false;
}
-/// Perform substitution on the base class specifiers of the
-/// given class template specialization.
-///
-/// Produces a diagnostic and returns true on error, returns false and
-/// attaches the instantiated base classes to the class template
-/// specialization if successful.
bool
Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
CXXRecordDecl *Pattern,
@@ -3222,28 +3401,6 @@ namespace clang {
}
}
-/// Instantiate the definition of a class from a given pattern.
-///
-/// \param PointOfInstantiation The point of instantiation within the
-/// source code.
-///
-/// \param Instantiation is the declaration whose definition is being
-/// instantiated. This will be either a class template specialization
-/// or a member class of a class template specialization.
-///
-/// \param Pattern is the pattern from which the instantiation
-/// occurs. This will be either the declaration of a class template or
-/// the declaration of a member class of a class template.
-///
-/// \param TemplateArgs The template arguments to be substituted into
-/// the pattern.
-///
-/// \param TSK the kind of implicit or explicit instantiation to perform.
-///
-/// \param Complain whether to complain if the class cannot be instantiated due
-/// to the lack of a definition.
-///
-/// \returns true if an error occurred, false otherwise.
bool
Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
@@ -3258,11 +3415,16 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
return true;
llvm::TimeTraceScope TimeScope("InstantiateClass", [&]() {
- std::string Name;
- llvm::raw_string_ostream OS(Name);
+ llvm::TimeTraceMetadata M;
+ llvm::raw_string_ostream OS(M.Detail);
Instantiation->getNameForDiagnostic(OS, getPrintingPolicy(),
/*Qualified=*/true);
- return Name;
+ if (llvm::isTimeTraceVerbose()) {
+ auto Loc = SourceMgr.getExpansionLoc(Instantiation->getLocation());
+ M.File = SourceMgr.getFilename(Loc);
+ M.Line = SourceMgr.getExpansionLineNumber(Loc);
+ }
+ return M;
});
Pattern = PatternDef;
@@ -3489,21 +3651,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
return Instantiation->isInvalidDecl();
}
-/// Instantiate the definition of an enum from a given pattern.
-///
-/// \param PointOfInstantiation The point of instantiation within the
-/// source code.
-/// \param Instantiation is the declaration whose definition is being
-/// instantiated. This will be a member enumeration of a class
-/// temploid specialization, or a local enumeration within a
-/// function temploid specialization.
-/// \param Pattern The templated declaration from which the instantiation
-/// occurs.
-/// \param TemplateArgs The template arguments to be substituted into
-/// the pattern.
-/// \param TSK The kind of implicit or explicit instantiation to perform.
-///
-/// \return \c true if an error occurred, \c false otherwise.
bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
EnumDecl *Instantiation, EnumDecl *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -3554,21 +3701,6 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
return Instantiation->isInvalidDecl();
}
-
-/// Instantiate the definition of a field from the given pattern.
-///
-/// \param PointOfInstantiation The point of instantiation within the
-/// source code.
-/// \param Instantiation is the declaration whose definition is being
-/// instantiated. This will be a class of a class temploid
-/// specialization, or a local enumeration within a function temploid
-/// specialization.
-/// \param Pattern The templated declaration from which the instantiation
-/// occurs.
-/// \param TemplateArgs The template arguments to be substituted into
-/// the pattern.
-///
-/// \return \c true if an error occurred, \c false otherwise.
bool Sema::InstantiateInClassInitializer(
SourceLocation PointOfInstantiation, FieldDecl *Instantiation,
FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs) {
@@ -3655,8 +3787,9 @@ bool Sema::usesPartialOrExplicitSpecialization(
->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
TemplateDeductionInfo Info(Loc);
- if (!DeduceTemplateArguments(PartialSpecs[I],
- ClassTemplateSpec->getTemplateArgs(), Info))
+ if (DeduceTemplateArguments(PartialSpecs[I],
+ ClassTemplateSpec->getTemplateArgs().asArray(),
+ Info) == TemplateDeductionResult::Success)
return true;
}
@@ -3700,8 +3833,9 @@ getPatternForClassTemplateSpecialization(
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
TemplateDeductionInfo Info(FailedCandidates.getLocation());
- if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments(
- Partial, ClassTemplateSpec->getTemplateArgs(), Info)) {
+ if (TemplateDeductionResult Result = S.DeduceTemplateArguments(
+ Partial, ClassTemplateSpec->getTemplateArgs().asArray(), Info);
+ Result != TemplateDeductionResult::Success) {
// Store the failed-deduction information for use in diagnostics, later.
// TODO: Actually use the failed-deduction info?
FailedCandidates.addCandidate().set(
@@ -3834,9 +3968,6 @@ bool Sema::InstantiateClassTemplateSpecialization(
getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain);
}
-/// Instantiates the definitions of all of the member
-/// of the given class, which is an instantiation of a class template
-/// or a member class of a template.
void
Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
@@ -4066,9 +4197,6 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
}
}
-/// Instantiate the definitions of all of the members of the
-/// given class template specialization, which was named as part of an
-/// explicit instantiation.
void
Sema::InstantiateClassTemplateSpecializationMembers(
SourceLocation PointOfInstantiation,
@@ -4098,6 +4226,15 @@ Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) {
return Instantiator.TransformStmt(S);
}
+bool Sema::SubstTemplateArgument(
+ const TemplateArgumentLoc &Input,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateArgumentLoc &Output, SourceLocation Loc,
+ const DeclarationName &Entity) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity);
+ return Instantiator.TransformTemplateArgument(Input, Output);
+}
+
bool Sema::SubstTemplateArguments(
ArrayRef<TemplateArgumentLoc> Args,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -4169,7 +4306,6 @@ Sema::SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
return Instantiator.TransformNestedNameSpecifierLoc(NNS);
}
-/// Do template substitution on declaration name info.
DeclarationNameInfo
Sema::SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo,
const MultiLevelTemplateArgumentList &TemplateArgs) {