summaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaCast.cpp18
-rw-r--r--clang/lib/Sema/SemaConcept.cpp70
-rw-r--r--clang/lib/Sema/SemaDecl.cpp1
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp54
-rw-r--r--clang/lib/Sema/SemaExpr.cpp49
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp3
-rw-r--r--clang/lib/Sema/SemaOverload.cpp88
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp6
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp40
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp186
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp98
11 files changed, 458 insertions, 155 deletions
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index a905ebc67305..7a8cbca1e3f1 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -2311,6 +2311,24 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return SuccessResult;
}
+ // Diagnose address space conversion in nested pointers.
+ QualType DestPtee = DestType->getPointeeType().isNull()
+ ? DestType->getPointeeType()
+ : DestType->getPointeeType()->getPointeeType();
+ QualType SrcPtee = SrcType->getPointeeType().isNull()
+ ? SrcType->getPointeeType()
+ : SrcType->getPointeeType()->getPointeeType();
+ while (!DestPtee.isNull() && !SrcPtee.isNull()) {
+ if (DestPtee.getAddressSpace() != SrcPtee.getAddressSpace()) {
+ Self.Diag(OpRange.getBegin(),
+ diag::warn_bad_cxx_cast_nested_pointer_addr_space)
+ << CStyle << SrcType << DestType << SrcExpr.get()->getSourceRange();
+ break;
+ }
+ DestPtee = DestPtee->getPointeeType();
+ SrcPtee = SrcPtee->getPointeeType();
+ }
+
// C++ 5.2.10p7: A pointer to an object can be explicitly converted to
// a pointer to an object of different type.
// Void pointers are not specified, but supported by every compiler out there.
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 81601b09ce0d..290e4cbff4fd 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -167,9 +167,8 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
return false;
}
-template <typename TemplateDeclT>
static bool calculateConstraintSatisfaction(
- Sema &S, TemplateDeclT *Template, ArrayRef<TemplateArgument> TemplateArgs,
+ Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL,
const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) {
return calculateConstraintSatisfaction(
@@ -182,8 +181,9 @@ static bool calculateConstraintSatisfaction(
{
TemplateDeductionInfo Info(TemplateNameLoc);
Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(),
- Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template,
- Info, AtomicExpr->getSourceRange());
+ Sema::InstantiatingTemplate::ConstraintSubstitution{},
+ const_cast<NamedDecl *>(Template), Info,
+ AtomicExpr->getSourceRange());
if (Inst.isInvalid())
return ExprError();
// We do not want error diagnostics escaping here.
@@ -230,8 +230,7 @@ static bool calculateConstraintSatisfaction(
});
}
-template<typename TemplateDeclT>
-static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
+static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template,
ArrayRef<const Expr *> ConstraintExprs,
ArrayRef<TemplateArgument> TemplateArgs,
SourceRange TemplateIDRange,
@@ -249,8 +248,8 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
}
Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
- Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs,
- TemplateIDRange);
+ Sema::InstantiatingTemplate::ConstraintsCheck{},
+ const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
if (Inst.isInvalid())
return true;
@@ -273,7 +272,7 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
}
bool Sema::CheckConstraintSatisfaction(
- NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+ const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange,
ConstraintSatisfaction &OutSatisfaction) {
if (ConstraintExprs.empty()) {
@@ -284,7 +283,8 @@ bool Sema::CheckConstraintSatisfaction(
llvm::FoldingSetNodeID ID;
void *InsertPos;
ConstraintSatisfaction *Satisfaction = nullptr;
- if (LangOpts.ConceptSatisfactionCaching) {
+ bool ShouldCache = LangOpts.ConceptSatisfactionCaching && Template;
+ if (ShouldCache) {
ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs);
Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos);
if (Satisfaction) {
@@ -295,27 +295,15 @@ bool Sema::CheckConstraintSatisfaction(
} else {
Satisfaction = &OutSatisfaction;
}
- bool Failed;
- if (auto *T = dyn_cast<TemplateDecl>(Template))
- Failed = ::CheckConstraintSatisfaction(*this, T, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- *Satisfaction);
- else if (auto *P =
- dyn_cast<ClassTemplatePartialSpecializationDecl>(Template))
- Failed = ::CheckConstraintSatisfaction(*this, P, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- *Satisfaction);
- else
- Failed = ::CheckConstraintSatisfaction(
- *this, cast<VarTemplatePartialSpecializationDecl>(Template),
- ConstraintExprs, TemplateArgs, TemplateIDRange, *Satisfaction);
- if (Failed) {
- if (LangOpts.ConceptSatisfactionCaching)
+ if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
+ TemplateArgs, TemplateIDRange,
+ *Satisfaction)) {
+ if (ShouldCache)
delete Satisfaction;
return true;
}
- if (LangOpts.ConceptSatisfactionCaching) {
+ if (ShouldCache) {
// We cannot use InsertNode here because CheckConstraintSatisfaction might
// have invalidated it.
SatisfactionCache.InsertNode(Satisfaction);
@@ -333,6 +321,30 @@ bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
});
}
+bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
+ ConstraintSatisfaction &Satisfaction,
+ SourceLocation UsageLoc) {
+ const Expr *RC = FD->getTrailingRequiresClause();
+ if (RC->isInstantiationDependent()) {
+ Satisfaction.IsSatisfied = true;
+ return false;
+ }
+ Qualifiers ThisQuals;
+ CXXRecordDecl *Record = nullptr;
+ if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
+ ThisQuals = Method->getMethodQualifiers();
+ Record = const_cast<CXXRecordDecl *>(Method->getParent());
+ }
+ CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
+ // We substitute with empty arguments in order to rebuild the atomic
+ // constraint in a constant-evaluated context.
+ // FIXME: Should this be a dedicated TreeTransform?
+ return CheckConstraintSatisfaction(
+ FD, {RC}, /*TemplateArgs=*/{},
+ SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
+ Satisfaction);
+}
+
bool Sema::EnsureTemplateArgumentListConstraints(
TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs,
SourceRange TemplateIDRange) {
@@ -671,6 +683,10 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
ArgsAsWritten->arguments().back().getSourceRange().getEnd()));
if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
return true;
+ Atomic.ParameterMapping.emplace(
+ MutableArrayRef<TemplateArgumentLoc>(
+ new (S.Context) TemplateArgumentLoc[SubstArgs.size()],
+ SubstArgs.size()));
std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
N.getAtomicConstraint()->ParameterMapping->begin());
return false;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 0bf490336537..64146f4a912f 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12526,6 +12526,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
var->getDeclContext()->getRedeclContext()->isFileContext() &&
var->isExternallyVisible() && var->hasLinkage() &&
!var->isInline() && !var->getDescribedVarTemplate() &&
+ !isa<VarTemplatePartialSpecializationDecl>(var) &&
!isTemplateInstantiation(var->getTemplateSpecializationKind()) &&
!getDiagnostics().isIgnored(diag::warn_missing_variable_declarations,
var->getLocation())) {
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 9fa5691983a1..831e55046e80 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -7373,7 +7373,14 @@ private:
/// resolution [...]
CandidateSet.exclude(FD);
- S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args);
+ if (Args[0]->getType()->isOverloadableType())
+ S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args);
+ else {
+ // FIXME: We determine whether this is a valid expression by checking to
+ // see if there's a viable builtin operator candidate for it. That isn't
+ // really what the rules ask us to do, but should give the right results.
+ S.AddBuiltinOperatorCandidates(OO, FD->getLocation(), Args, CandidateSet);
+ }
Result R;
@@ -7438,6 +7445,31 @@ private:
if (OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType()) {
if (auto *BestFD = Best->Function) {
+ // If any callee has an undeduced return type, deduce it now.
+ // FIXME: It's not clear how a failure here should be handled. For
+ // now, we produce an eager diagnostic, because that is forward
+ // compatible with most (all?) other reasonable options.
+ if (BestFD->getReturnType()->isUndeducedType() &&
+ S.DeduceReturnType(BestFD, FD->getLocation(),
+ /*Diagnose=*/false)) {
+ // Don't produce a duplicate error when asked to explain why the
+ // comparison is deleted: we diagnosed that when initially checking
+ // the defaulted operator.
+ if (Diagnose == NoDiagnostics) {
+ S.Diag(
+ FD->getLocation(),
+ diag::err_defaulted_comparison_cannot_deduce_undeduced_auto)
+ << Subobj.Kind << Subobj.Decl;
+ S.Diag(
+ Subobj.Loc,
+ diag::note_defaulted_comparison_cannot_deduce_undeduced_auto)
+ << Subobj.Kind << Subobj.Decl;
+ S.Diag(BestFD->getLocation(),
+ diag::note_defaulted_comparison_cannot_deduce_callee)
+ << Subobj.Kind << Subobj.Decl;
+ }
+ return Result::deleted();
+ }
if (auto *Info = S.Context.CompCategories.lookupInfoForType(
BestFD->getCallResultType())) {
R.Category = Info->Kind;
@@ -7826,10 +7858,14 @@ private:
return StmtError();
OverloadedOperatorKind OO = FD->getOverloadedOperator();
- ExprResult Op = S.CreateOverloadedBinOp(
- Loc, BinaryOperator::getOverloadedOpcode(OO), Fns,
- Obj.first.get(), Obj.second.get(), /*PerformADL=*/true,
- /*AllowRewrittenCandidates=*/true, FD);
+ BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(OO);
+ ExprResult Op;
+ if (Type->isOverloadableType())
+ Op = S.CreateOverloadedBinOp(Loc, Opc, Fns, Obj.first.get(),
+ Obj.second.get(), /*PerformADL=*/true,
+ /*AllowRewrittenCandidates=*/true, FD);
+ else
+ Op = S.CreateBuiltinBinOp(Loc, Opc, Obj.first.get(), Obj.second.get());
if (Op.isInvalid())
return StmtError();
@@ -7869,8 +7905,12 @@ private:
llvm::APInt ZeroVal(S.Context.getIntWidth(S.Context.IntTy), 0);
Expr *Zero =
IntegerLiteral::Create(S.Context, ZeroVal, S.Context.IntTy, Loc);
- ExprResult Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(),
- Zero, true, true, FD);
+ ExprResult Comp;
+ if (VDRef.get()->getType()->isOverloadableType())
+ Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(), Zero, true,
+ true, FD);
+ else
+ Comp = S.CreateBuiltinBinOp(Loc, BO_NE, VDRef.get(), Zero);
if (Comp.isInvalid())
return StmtError();
Sema::ConditionResult Cond = S.ActOnCondition(
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ea4b93ee6a5a..29562615e588 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -245,8 +245,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
return true;
}
- // See if this is a deleted function.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // See if this is a deleted function.
if (FD->isDeleted()) {
auto *Ctor = dyn_cast<CXXConstructorDecl>(FD);
if (Ctor && Ctor->isInheritingConstructor())
@@ -259,6 +259,29 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
return true;
}
+ // [expr.prim.id]p4
+ // A program that refers explicitly or implicitly to a function with a
+ // trailing requires-clause whose constraint-expression is not satisfied,
+ // other than to declare it, is ill-formed. [...]
+ //
+ // See if this is a function with constraints that need to be satisfied.
+ // Check this before deducing the return type, as it might instantiate the
+ // definition.
+ if (FD->getTrailingRequiresClause()) {
+ ConstraintSatisfaction Satisfaction;
+ if (CheckFunctionConstraints(FD, Satisfaction, Loc))
+ // A diagnostic will have already been generated (non-constant
+ // constraint expression, for example)
+ return true;
+ if (!Satisfaction.IsSatisfied) {
+ Diag(Loc,
+ diag::err_reference_to_function_with_unsatisfied_constraints)
+ << D;
+ DiagnoseUnsatisfiedConstraint(Satisfaction);
+ return true;
+ }
+ }
+
// If the function has a deduced return type, and we can't deduce it,
// then we can't use it either.
if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() &&
@@ -326,30 +349,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
- // [expr.prim.id]p4
- // A program that refers explicitly or implicitly to a function with a
- // trailing requires-clause whose constraint-expression is not satisfied,
- // other than to declare it, is ill-formed. [...]
- //
- // See if this is a function with constraints that need to be satisfied.
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- if (Expr *RC = FD->getTrailingRequiresClause()) {
- ConstraintSatisfaction Satisfaction;
- bool Failed = CheckConstraintSatisfaction(RC, Satisfaction);
- if (Failed)
- // A diagnostic will have already been generated (non-constant
- // constraint expression, for example)
- return true;
- if (!Satisfaction.IsSatisfied) {
- Diag(Loc,
- diag::err_reference_to_function_with_unsatisfied_constraints)
- << D;
- DiagnoseUnsatisfiedConstraint(Satisfaction);
- return true;
- }
- }
- }
-
if (isa<ParmVarDecl>(D) && isa<RequiresExprBodyDecl>(D->getDeclContext()) &&
!isUnevaluatedContext()) {
// C++ [expr.prim.req.nested] p3
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 192c237b6c1c..98af7fb73eca 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8487,7 +8487,8 @@ concepts::NestedRequirement *
Sema::BuildNestedRequirement(Expr *Constraint) {
ConstraintSatisfaction Satisfaction;
if (!Constraint->isInstantiationDependent() &&
- CheckConstraintSatisfaction(Constraint, Satisfaction))
+ CheckConstraintSatisfaction(nullptr, {Constraint}, /*TemplateArgs=*/{},
+ Constraint->getSourceRange(), Satisfaction))
return nullptr;
return new (Context) concepts::NestedRequirement(Context, Constraint,
Satisfaction);
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 0fd932fac970..db1884acd349 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -3176,7 +3176,7 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
/// FromType and \p ToType is permissible, given knowledge about whether every
/// outer layer is const-qualified.
static bool isQualificationConversionStep(QualType FromType, QualType ToType,
- bool CStyle,
+ bool CStyle, bool IsTopLevel,
bool &PreviousToQualsIncludeConst,
bool &ObjCLifetimeConversion) {
Qualifiers FromQuals = FromType.getQualifiers();
@@ -3213,11 +3213,15 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType,
if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
return false;
- // For a C-style cast, just require the address spaces to overlap.
- // FIXME: Does "superset" also imply the representation of a pointer is the
- // same? We're assuming that it does here and in compatiblyIncludes.
- if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
- !FromQuals.isAddressSpaceSupersetOf(ToQuals))
+ // If address spaces mismatch:
+ // - in top level it is only valid to convert to addr space that is a
+ // superset in all cases apart from C-style casts where we allow
+ // conversions between overlapping address spaces.
+ // - in non-top levels it is not a valid conversion.
+ if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() &&
+ (!IsTopLevel ||
+ !(ToQuals.isAddressSpaceSupersetOf(FromQuals) ||
+ (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals)))))
return false;
// -- if the cv 1,j and cv 2,j are different, then const is in
@@ -3258,9 +3262,9 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
bool PreviousToQualsIncludeConst = true;
bool UnwrappedAnyPointer = false;
while (Context.UnwrapSimilarTypes(FromType, ToType)) {
- if (!isQualificationConversionStep(FromType, ToType, CStyle,
- PreviousToQualsIncludeConst,
- ObjCLifetimeConversion))
+ if (!isQualificationConversionStep(
+ FromType, ToType, CStyle, !UnwrappedAnyPointer,
+ PreviousToQualsIncludeConst, ObjCLifetimeConversion))
return false;
UnwrappedAnyPointer = true;
}
@@ -4499,7 +4503,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
// If we find a qualifier mismatch, the types are not reference-compatible,
// but are still be reference-related if they're similar.
bool ObjCLifetimeConversion = false;
- if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false,
+ if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, TopLevel,
PreviousToQualsIncludeConst,
ObjCLifetimeConversion))
return (ConvertedReferent || Context.hasSimilarType(T1, T2))
@@ -6291,9 +6295,9 @@ void Sema::AddOverloadCandidate(
return;
}
- if (Expr *RequiresClause = Function->getTrailingRequiresClause()) {
+ if (Function->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ if (CheckFunctionConstraints(Function, Satisfaction) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -6808,9 +6812,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
return;
}
- if (Expr *RequiresClause = Method->getTrailingRequiresClause()) {
+ if (Method->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ if (CheckFunctionConstraints(Method, Satisfaction) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -7204,10 +7208,9 @@ void Sema::AddConversionCandidate(
return;
}
- Expr *RequiresClause = Conversion->getTrailingRequiresClause();
- if (RequiresClause) {
+ if (Conversion->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ if (CheckFunctionConstraints(Conversion, Satisfaction) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -9270,17 +9273,31 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
if (ExplicitTemplateArgs)
continue;
- AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet,
- /*SuppressUserConversions=*/false, PartialOverloading,
- /*AllowExplicit*/ true,
- /*AllowExplicitConversions*/ false,
- ADLCallKind::UsesADL);
+ AddOverloadCandidate(
+ FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false,
+ PartialOverloading, /*AllowExplicit=*/true,
+ /*AllowExplicitConversions=*/false, ADLCallKind::UsesADL);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) {
+ AddOverloadCandidate(
+ FD, FoundDecl, {Args[1], Args[0]}, CandidateSet,
+ /*SuppressUserConversions=*/false, PartialOverloading,
+ /*AllowExplicit=*/true, /*AllowExplicitConversions=*/false,
+ ADLCallKind::UsesADL, None, OverloadCandidateParamOrder::Reversed);
+ }
} else {
+ auto *FTD = cast<FunctionTemplateDecl>(*I);
AddTemplateOverloadCandidate(
- cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, Args,
- CandidateSet,
+ FTD, FoundDecl, ExplicitTemplateArgs, Args, CandidateSet,
/*SuppressUserConversions=*/false, PartialOverloading,
- /*AllowExplicit*/true, ADLCallKind::UsesADL);
+ /*AllowExplicit=*/true, ADLCallKind::UsesADL);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(
+ Context, FTD->getTemplatedDecl())) {
+ AddTemplateOverloadCandidate(
+ FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]},
+ CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading,
+ /*AllowExplicit=*/true, ADLCallKind::UsesADL,
+ OverloadCandidateParamOrder::Reversed);
+ }
}
}
}
@@ -9566,17 +9583,15 @@ bool clang::isBetterOverloadCandidate(
if (RC1 && RC2) {
bool AtLeastAsConstrained1, AtLeastAsConstrained2;
if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function,
- {RC2}, AtLeastAsConstrained1))
- return false;
- if (!AtLeastAsConstrained1)
- return false;
- if (S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function,
+ {RC2}, AtLeastAsConstrained1) ||
+ S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function,
{RC1}, AtLeastAsConstrained2))
return false;
- if (!AtLeastAsConstrained2)
- return true;
- } else if (RC1 || RC2)
+ if (AtLeastAsConstrained1 != AtLeastAsConstrained2)
+ return AtLeastAsConstrained1;
+ } else if (RC1 || RC2) {
return RC1 != nullptr;
+ }
}
}
@@ -9947,9 +9962,9 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD,
return false;
}
- if (const Expr *RC = FD->getTrailingRequiresClause()) {
+ if (FD->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (S.CheckConstraintSatisfaction(RC, Satisfaction))
+ if (S.CheckFunctionConstraints(FD, Satisfaction, Loc))
return false;
if (!Satisfaction.IsSatisfied) {
if (Complain) {
@@ -10974,8 +10989,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
<< (unsigned)FnKindPair.first << (unsigned)ocs_non_template
<< FnDesc /* Ignored */;
ConstraintSatisfaction Satisfaction;
- if (S.CheckConstraintSatisfaction(Fn->getTrailingRequiresClause(),
- Satisfaction))
+ if (S.CheckFunctionConstraints(Fn, Satisfaction))
break;
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index f961244da072..ad4ea2d2593d 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2047,12 +2047,14 @@ private:
if (const auto *TC = TTP->getTypeConstraint()) {
TemplateArgumentListInfo TransformedArgs;
const auto *ArgsAsWritten = TC->getTemplateArgsAsWritten();
- if (SemaRef.Subst(ArgsAsWritten->getTemplateArgs(),
+ if (!ArgsAsWritten ||
+ SemaRef.Subst(ArgsAsWritten->getTemplateArgs(),
ArgsAsWritten->NumTemplateArgs, TransformedArgs,
Args))
SemaRef.AttachTypeConstraint(
TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
- TC->getNamedConcept(), &TransformedArgs, NewTTP,
+ TC->getNamedConcept(), ArgsAsWritten ? &TransformedArgs : nullptr,
+ NewTTP,
NewTTP->isParameterPack()
? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
->getEllipsisLoc()
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 394c81c82794..6b865a601f9d 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2488,7 +2488,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion: {
NestedNameSpecifierLocBuilder Builder;
- TemplateName Template = Arg.getAsTemplate();
+ TemplateName Template = Arg.getAsTemplateOrTemplatePattern();
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
else if (QualifiedTemplateName *QTN =
@@ -2514,27 +2514,10 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
}
TemplateArgumentLoc
-Sema::getIdentityTemplateArgumentLoc(Decl *TemplateParm,
+Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm,
SourceLocation Location) {
- if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParm))
- return getTrivialTemplateArgumentLoc(
- TemplateArgument(
- Context.getTemplateTypeParmType(TTP->getDepth(), TTP->getIndex(),
- TTP->isParameterPack(), TTP)),
- QualType(), Location.isValid() ? Location : TTP->getLocation());
- else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParm))
- return getTrivialTemplateArgumentLoc(TemplateArgument(TemplateName(TTP)),
- QualType(),
- Location.isValid() ? Location :
- TTP->getLocation());
- auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParm);
- CXXScopeSpec SS;
- DeclarationNameInfo Info(NTTP->getDeclName(),
- Location.isValid() ? Location : NTTP->getLocation());
- Expr *E = BuildDeclarationNameExpr(SS, Info, NTTP).get();
- return getTrivialTemplateArgumentLoc(TemplateArgument(E), NTTP->getType(),
- Location.isValid() ? Location :
- NTTP->getLocation());
+ return getTrivialTemplateArgumentLoc(
+ Context.getInjectedTemplateArg(TemplateParm), QualType(), Location);
}
/// Convert the given deduced template argument and add it to the set of
@@ -3456,13 +3439,16 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// ([temp.constr.decl]), those constraints are checked for satisfaction
// ([temp.constr.constr]). If the constraints are not satisfied, type
// deduction fails.
- if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(),
- Specialization, Builder, Info.AssociatedConstraintsSatisfaction))
- return TDK_MiscellaneousDeductionFailure;
+ if (!PartialOverloading ||
+ (Builder.size() == FunctionTemplate->getTemplateParameters()->size())) {
+ if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(),
+ Specialization, Builder, Info.AssociatedConstraintsSatisfaction))
+ return TDK_MiscellaneousDeductionFailure;
- if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
- Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
- return TDK_ConstraintsNotSatisfied;
+ if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
+ Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
+ return TDK_ConstraintsNotSatisfied;
+ }
}
if (OriginalCallArgs) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 39bc28d62305..568f5404dc0b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyDeclStackTrace.h"
+#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Stack.h"
#include "clang/Sema/DeclSpec.h"
@@ -763,21 +764,30 @@ void Sema::PrintInstantiationStack() {
case CodeSynthesisContext::ConstraintsCheck: {
unsigned DiagID = 0;
+ if (!Active->Entity) {
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_nested_requirement_here)
+ << Active->InstantiationRange;
+ break;
+ }
if (isa<ConceptDecl>(Active->Entity))
DiagID = diag::note_concept_specialization_here;
else if (isa<TemplateDecl>(Active->Entity))
DiagID = diag::note_checking_constraints_for_template_id_here;
else if (isa<VarTemplatePartialSpecializationDecl>(Active->Entity))
DiagID = diag::note_checking_constraints_for_var_spec_id_here;
- else {
- assert(isa<ClassTemplatePartialSpecializationDecl>(Active->Entity));
+ else if (isa<ClassTemplatePartialSpecializationDecl>(Active->Entity))
DiagID = diag::note_checking_constraints_for_class_spec_id_here;
+ else {
+ assert(isa<FunctionDecl>(Active->Entity));
+ DiagID = diag::note_checking_constraints_for_function_here;
}
SmallVector<char, 128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
cast<NamedDecl>(Active->Entity)->printName(OS);
- printTemplateArgumentList(OS, Active->template_arguments(),
- getPrintingPolicy());
+ if (!isa<FunctionDecl>(Active->Entity))
+ printTemplateArgumentList(OS, Active->template_arguments(),
+ getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str()
<< Active->InstantiationRange;
break;
@@ -1048,6 +1058,8 @@ namespace {
NonTypeTemplateParmDecl *D);
ExprResult TransformSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E);
+ ExprResult TransformSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E);
/// Rebuild a DeclRefExpr for a VarDecl reference.
ExprResult RebuildVarDeclRefExpr(VarDecl *PD, SourceLocation Loc);
@@ -1526,6 +1538,44 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
Arg);
}
+ExprResult
+TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E) {
+ ExprResult SubstReplacement = TransformExpr(E->getReplacement());
+ if (SubstReplacement.isInvalid())
+ return true;
+ QualType SubstType = TransformType(E->getType());
+ if (SubstType.isNull())
+ return true;
+ // The type may have been previously dependent and not now, which means we
+ // might have to implicit cast the argument to the new type, for example:
+ // template<auto T, decltype(T) U>
+ // concept C = sizeof(U) == 4;
+ // void foo() requires C<2, 'a'> { }
+ // When normalizing foo(), we first form the normalized constraints of C:
+ // AtomicExpr(sizeof(U) == 4,
+ // U=SubstNonTypeTemplateParmExpr(Param=U,
+ // Expr=DeclRef(U),
+ // Type=decltype(T)))
+ // Then we substitute T = 2, U = 'a' into the parameter mapping, and need to
+ // produce:
+ // AtomicExpr(sizeof(U) == 4,
+ // U=SubstNonTypeTemplateParmExpr(Param=U,
+ // Expr=ImpCast(
+ // decltype(2),
+ // SubstNTTPE(Param=U, Expr='a',
+ // 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())
+ return true;
+ return transformNonTypeTemplateParmRef(E->getParameter(),
+ E->getExprLoc(), Converted);
+}
+
ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD,
SourceLocation Loc) {
DeclarationNameInfo NameInfo(PD->getDeclName(), Loc);
@@ -2096,6 +2146,94 @@ void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
UpdateExceptionSpec(New, ESI);
}
+namespace {
+
+ struct GetContainedInventedTypeParmVisitor :
+ public TypeVisitor<GetContainedInventedTypeParmVisitor,
+ TemplateTypeParmDecl *> {
+ using TypeVisitor<GetContainedInventedTypeParmVisitor,
+ TemplateTypeParmDecl *>::Visit;
+
+ TemplateTypeParmDecl *Visit(QualType T) {
+ if (T.isNull())
+ return nullptr;
+ return Visit(T.getTypePtr());
+ }
+ // The deduced type itself.
+ TemplateTypeParmDecl *VisitTemplateTypeParmType(
+ const TemplateTypeParmType *T) {
+ if (!T->getDecl()->isImplicit())
+ return nullptr;
+ return T->getDecl();
+ }
+
+ // Only these types can contain 'auto' types, and subsequently be replaced
+ // by references to invented parameters.
+
+ TemplateTypeParmDecl *VisitElaboratedType(const ElaboratedType *T) {
+ return Visit(T->getNamedType());
+ }
+
+ TemplateTypeParmDecl *VisitPointerType(const PointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+
+ TemplateTypeParmDecl *VisitBlockPointerType(const BlockPointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+
+ TemplateTypeParmDecl *VisitReferenceType(const ReferenceType *T) {
+ return Visit(T->getPointeeTypeAsWritten());
+ }
+
+ TemplateTypeParmDecl *VisitMemberPointerType(const MemberPointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+
+ TemplateTypeParmDecl *VisitArrayType(const ArrayType *T) {
+ return Visit(T->getElementType());
+ }
+
+ TemplateTypeParmDecl *VisitDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *T) {
+ return Visit(T->getElementType());
+ }
+
+ TemplateTypeParmDecl *VisitVectorType(const VectorType *T) {
+ return Visit(T->getElementType());
+ }
+
+ TemplateTypeParmDecl *VisitFunctionProtoType(const FunctionProtoType *T) {
+ return VisitFunctionType(T);
+ }
+
+ TemplateTypeParmDecl *VisitFunctionType(const FunctionType *T) {
+ return Visit(T->getReturnType());
+ }
+
+ TemplateTypeParmDecl *VisitParenType(const ParenType *T) {
+ return Visit(T->getInnerType());
+ }
+
+ TemplateTypeParmDecl *VisitAttributedType(const AttributedType *T) {
+ return Visit(T->getModifiedType());
+ }
+
+ TemplateTypeParmDecl *VisitMacroQualifiedType(const MacroQualifiedType *T) {
+ return Visit(T->getUnderlyingType());
+ }
+
+ TemplateTypeParmDecl *VisitAdjustedType(const AdjustedType *T) {
+ return Visit(T->getOriginalType());
+ }
+
+ TemplateTypeParmDecl *VisitPackExpansionType(const PackExpansionType *T) {
+ return Visit(T->getPattern());
+ }
+ };
+
+} // namespace
+
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
@@ -2143,6 +2281,46 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
return nullptr;
}
+ // In abbreviated templates, TemplateTypeParmDecls with possible
+ // TypeConstraints are created when the parameter list is originally parsed.
+ // The TypeConstraints can therefore reference other functions parameters in
+ // the abbreviated function template, which is why we must instantiate them
+ // here, when the instantiated versions of those referenced parameters are in
+ // scope.
+ if (TemplateTypeParmDecl *TTP =
+ GetContainedInventedTypeParmVisitor().Visit(OldDI->getType())) {
+ if (const TypeConstraint *TC = TTP->getTypeConstraint()) {
+ auto *Inst = cast_or_null<TemplateTypeParmDecl>(
+ FindInstantiatedDecl(TTP->getLocation(), TTP, TemplateArgs));
+ // We will first get here when instantiating the abbreviated function
+ // 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)
+ const ASTTemplateArgumentListInfo *TemplArgInfo
+ = TC->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo InstArgs;
+
+ if (TemplArgInfo) {
+ InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
+ InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
+ if (Subst(TemplArgInfo->getTemplateArgs(),
+ TemplArgInfo->NumTemplateArgs, InstArgs, TemplateArgs))
+ return nullptr;
+ }
+ if (AttachTypeConstraint(
+ TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
+ TC->getNamedConcept(), &InstArgs, Inst,
+ TTP->isParameterPack()
+ ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc()
+ : SourceLocation()))
+ return nullptr;
+ }
+ }
+ }
+
ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(),
OldParm->getInnerLocStart(),
OldParm->getLocation(),
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index fbbab8f00703..37dace3bee7f 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1837,6 +1837,23 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
return nullptr;
QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
+ if (TemplateParams && TemplateParams->size()) {
+ auto *LastParam =
+ dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
+ if (LastParam && LastParam->isImplicit() &&
+ LastParam->hasTypeConstraint()) {
+ // In abbreviated templates, the type-constraints of invented template
+ // type parameters are instantiated with the function type, invalidating
+ // the TemplateParameterList which relied on the template type parameter
+ // not having a type constraint. Recreate the TemplateParameterList with
+ // the updated parameter list.
+ TemplateParams = TemplateParameterList::Create(
+ SemaRef.Context, TemplateParams->getTemplateLoc(),
+ TemplateParams->getLAngleLoc(), TemplateParams->asArray(),
+ TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause());
+ }
+ }
+
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
if (QualifierLoc) {
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
@@ -2177,6 +2194,23 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
return nullptr;
QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
+ if (TemplateParams && TemplateParams->size()) {
+ auto *LastParam =
+ dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
+ if (LastParam && LastParam->isImplicit() &&
+ LastParam->hasTypeConstraint()) {
+ // In abbreviated templates, the type-constraints of invented template
+ // type parameters are instantiated with the function type, invalidating
+ // the TemplateParameterList which relied on the template type parameter
+ // not having a type constraint. Recreate the TemplateParameterList with
+ // the updated parameter list.
+ TemplateParams = TemplateParameterList::Create(
+ SemaRef.Context, TemplateParams->getTemplateLoc(),
+ TemplateParams->getLAngleLoc(), TemplateParams->asArray(),
+ TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause());
+ }
+ }
+
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
if (QualifierLoc) {
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
@@ -2190,6 +2224,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (TrailingRequiresClause) {
EnterExpressionEvaluationContext ConstantEvaluated(
SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+ auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
+ Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext,
+ D->getMethodQualifiers(), ThisContext);
ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
TemplateArgs);
if (SubstRC.isInvalid())
@@ -2522,28 +2559,34 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
Inst->setAccess(AS_public);
Inst->setImplicit(D->isImplicit());
if (auto *TC = D->getTypeConstraint()) {
- // TODO: Concepts: do not instantiate the constraint (delayed constraint
- // substitution)
- const ASTTemplateArgumentListInfo *TemplArgInfo
- = TC->getTemplateArgsAsWritten();
- TemplateArgumentListInfo InstArgs;
-
- if (TemplArgInfo) {
- InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
- InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
- if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
- TemplArgInfo->NumTemplateArgs,
- InstArgs, TemplateArgs))
+ if (!D->isImplicit()) {
+ // Invented template parameter type constraints will be instantiated with
+ // the corresponding auto-typed parameter as it might reference other
+ // parameters.
+
+ // TODO: Concepts: do not instantiate the constraint (delayed constraint
+ // substitution)
+ const ASTTemplateArgumentListInfo *TemplArgInfo
+ = TC->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo InstArgs;
+
+ if (TemplArgInfo) {
+ InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
+ InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
+ if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
+ TemplArgInfo->NumTemplateArgs,
+ InstArgs, TemplateArgs))
+ return nullptr;
+ }
+ if (SemaRef.AttachTypeConstraint(
+ TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
+ TC->getNamedConcept(), &InstArgs, Inst,
+ D->isParameterPack()
+ ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc()
+ : SourceLocation()))
return nullptr;
}
- if (SemaRef.AttachTypeConstraint(
- TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
- TC->getNamedConcept(), &InstArgs, Inst,
- D->isParameterPack()
- ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
- ->getEllipsisLoc()
- : SourceLocation()))
- return nullptr;
}
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
TypeSourceInfo *InstantiatedDefaultArg =
@@ -4246,24 +4289,29 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);
- MultiLevelTemplateArgumentList MLTAL =
- getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
-
// If this is not an explicit specialization - we need to get the instantiated
// version of the template arguments and add them to scope for the
// substitution.
if (Decl->isTemplateInstantiation()) {
InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(),
InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(),
- MLTAL.getInnermost(), SourceRange());
+ TemplateArgs, SourceRange());
if (Inst.isInvalid())
return true;
+ MultiLevelTemplateArgumentList MLTAL(
+ *Decl->getTemplateSpecializationArgs());
if (addInstantiatedParametersToScope(
*this, Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(),
Scope, MLTAL))
return true;
}
-
+ Qualifiers ThisQuals;
+ CXXRecordDecl *Record = nullptr;
+ if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
+ ThisQuals = Method->getMethodQualifiers();
+ Record = Method->getParent();
+ }
+ CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs,
PointOfInstantiation, Satisfaction);
}