#include "clang/Sema/TemplateDeduction.h"
#include "TreeTransform.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclAccessPair.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <cassert>
#include <tuple>
#include <utility>
namespace clang {
enum TemplateDeductionFlags {
TDF_None = 0,
TDF_ParamWithReferenceType = 0x1,
TDF_IgnoreQualifiers = 0x02,
TDF_DerivedClass = 0x04,
TDF_SkipNonDependent = 0x08,
TDF_TopLevelParameterTypeList = 0x10,
TDF_AllowCompatibleFunctionType = 0x20,
TDF_ArgWithReferenceType = 0x40,
};
}
using namespace clang;
using namespace sema;
static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) {
if (Y.getBitWidth() > X.getBitWidth())
X = X.extend(Y.getBitWidth());
else if (Y.getBitWidth() < X.getBitWidth())
Y = Y.extend(X.getBitWidth());
if (X.isSigned() != Y.isSigned()) {
if ((Y.isSigned() && Y.isNegative()) || (X.isSigned() && X.isNegative()))
return false;
Y.setIsSigned(true);
X.setIsSigned(true);
}
return X == Y;
}
static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
Sema &S, TemplateParameterList *TemplateParams, QualType Param,
QualType Arg, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF,
bool PartialOrdering = false, bool DeducedFromArrayBound = false);
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
ArrayRef<TemplateArgument> Ps,
ArrayRef<TemplateArgument> As,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch);
static void MarkUsedTemplateParameters(ASTContext &Ctx,
const TemplateArgument &TemplateArg,
bool OnlyDeduced, unsigned Depth,
llvm::SmallBitVector &Used);
static void MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced, unsigned Level,
llvm::SmallBitVector &Deduced);
static const NonTypeTemplateParmDecl *
getDeducedParameterFromExpr(const Expr *E, unsigned Depth) {
while (true) {
if (const auto *IC = dyn_cast<ImplicitCastExpr>(E))
E = IC->getSubExpr();
else if (const auto *CE = dyn_cast<ConstantExpr>(E))
E = CE->getSubExpr();
else if (const auto *Subst = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
E = Subst->getReplacement();
else if (const auto *CCE = dyn_cast<CXXConstructExpr>(E)) {
if (CCE->getParenOrBraceRange().isValid())
break;
assert(CCE->getNumArgs() >= 1 && "implicit construct expr should have 1 arg");
E = CCE->getArg(0);
} else
break;
}
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()))
if (NTTP->getDepth() == Depth)
return NTTP;
return nullptr;
}
static const NonTypeTemplateParmDecl *
getDeducedParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) {
return getDeducedParameterFromExpr(E, Info.getDeducedDepth());
}
static bool isSameDeclaration(Decl *X, Decl *Y) {
if (NamedDecl *NX = dyn_cast<NamedDecl>(X))
X = NX->getUnderlyingDecl();
if (NamedDecl *NY = dyn_cast<NamedDecl>(Y))
Y = NY->getUnderlyingDecl();
return X->getCanonicalDecl() == Y->getCanonicalDecl();
}
static DeducedTemplateArgument
checkDeducedTemplateArguments(ASTContext &Context,
const DeducedTemplateArgument &X,
const DeducedTemplateArgument &Y) {
if (X.isNull())
return Y;
if (Y.isNull())
return X;
if (!X.wasDeducedFromArrayBound() && !Y.wasDeducedFromArrayBound()) {
QualType XType = X.getNonTypeTemplateArgumentType();
if (!XType.isNull()) {
QualType YType = Y.getNonTypeTemplateArgumentType();
if (YType.isNull() || !Context.hasSameType(XType, YType))
return DeducedTemplateArgument();
}
}
switch (X.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Non-deduced template arguments handled above");
case TemplateArgument::Type:
if (Y.getKind() == TemplateArgument::Type &&
Context.hasSameType(X.getAsType(), Y.getAsType()))
return X;
if (X.wasDeducedFromArrayBound() != Y.wasDeducedFromArrayBound())
return X.wasDeducedFromArrayBound() ? Y : X;
return DeducedTemplateArgument();
case TemplateArgument::Integral:
if (Y.getKind() == TemplateArgument::Expression ||
Y.getKind() == TemplateArgument::Declaration ||
(Y.getKind() == TemplateArgument::Integral &&
hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral())))
return X.wasDeducedFromArrayBound() ? Y : X;
return DeducedTemplateArgument();
case TemplateArgument::Template:
if (Y.getKind() == TemplateArgument::Template &&
Context.hasSameTemplateName(X.getAsTemplate(), Y.getAsTemplate()))
return X;
return DeducedTemplateArgument();
case TemplateArgument::TemplateExpansion:
if (Y.getKind() == TemplateArgument::TemplateExpansion &&
Context.hasSameTemplateName(X.getAsTemplateOrTemplatePattern(),
Y.getAsTemplateOrTemplatePattern()))
return X;
return DeducedTemplateArgument();
case TemplateArgument::Expression: {
if (Y.getKind() != TemplateArgument::Expression)
return checkDeducedTemplateArguments(Context, Y, X);
llvm::FoldingSetNodeID ID1, ID2;
X.getAsExpr()->Profile(ID1, Context, true);
Y.getAsExpr()->Profile(ID2, Context, true);
if (ID1 == ID2)
return X.wasDeducedFromArrayBound() ? Y : X;
return DeducedTemplateArgument();
}
case TemplateArgument::Declaration:
assert(!X.wasDeducedFromArrayBound());
if (Y.getKind() == TemplateArgument::Expression)
return X;
if (Y.getKind() == TemplateArgument::Integral) {
if (Y.wasDeducedFromArrayBound())
return TemplateArgument(Context, Y.getAsIntegral(),
X.getParamTypeForDecl());
return Y;
}
if (Y.getKind() == TemplateArgument::Declaration &&
isSameDeclaration(X.getAsDecl(), Y.getAsDecl()))
return X;
return DeducedTemplateArgument();
case TemplateArgument::NullPtr:
if (Y.getKind() == TemplateArgument::Expression)
return X;
if (Y.getKind() == TemplateArgument::Integral)
return Y;
if (Y.getKind() == TemplateArgument::NullPtr)
return X;
return DeducedTemplateArgument();
case TemplateArgument::Pack: {
if (Y.getKind() != TemplateArgument::Pack ||
X.pack_size() != Y.pack_size())
return DeducedTemplateArgument();
llvm::SmallVector<TemplateArgument, 8> NewPack;
for (TemplateArgument::pack_iterator XA = X.pack_begin(),
XAEnd = X.pack_end(),
YA = Y.pack_begin();
XA != XAEnd; ++XA, ++YA) {
TemplateArgument Merged = checkDeducedTemplateArguments(
Context, DeducedTemplateArgument(*XA, X.wasDeducedFromArrayBound()),
DeducedTemplateArgument(*YA, Y.wasDeducedFromArrayBound()));
if (Merged.isNull() && !(XA->isNull() && YA->isNull()))
return DeducedTemplateArgument();
NewPack.push_back(Merged);
}
return DeducedTemplateArgument(
TemplateArgument::CreatePackCopy(Context, NewPack),
X.wasDeducedFromArrayBound() && Y.wasDeducedFromArrayBound());
}
}
llvm_unreachable("Invalid TemplateArgument Kind!");
}
static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
Sema &S, TemplateParameterList *TemplateParams,
const NonTypeTemplateParmDecl *NTTP, const DeducedTemplateArgument &NewDeduced,
QualType ValueType, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == Info.getDeducedDepth() &&
"deducing non-type template argument with wrong depth");
DeducedTemplateArgument Result = checkDeducedTemplateArguments(
S.Context, Deduced[NTTP->getIndex()], NewDeduced);
if (Result.isNull()) {
Info.Param = const_cast<NonTypeTemplateParmDecl*>(NTTP);
Info.FirstArg = Deduced[NTTP->getIndex()];
Info.SecondArg = NewDeduced;
return Sema::TDK_Inconsistent;
}
Deduced[NTTP->getIndex()] = Result;
if (!S.getLangOpts().CPlusPlus17)
return Sema::TDK_Success;
if (NTTP->isExpandedParameterPack())
return Sema::TDK_Success;
QualType ParamType = S.Context.getAdjustedParameterType(NTTP->getType());
if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType))
ParamType = Expansion->getPattern();
ValueType = ValueType.getNonReferenceType();
if (ParamType->isReferenceType())
ParamType = ParamType.getNonReferenceType();
else
ValueType = ValueType.getUnqualifiedType();
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, ParamType, ValueType, Info, Deduced,
TDF_SkipNonDependent, false,
NewDeduced.wasDeducedFromArrayBound());
}
static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
Sema &S, TemplateParameterList *TemplateParams,
const NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value,
QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP,
DeducedTemplateArgument(S.Context, Value, ValueType,
DeducedFromArrayBound),
ValueType, Info, Deduced);
}
static Sema::TemplateDeductionResult DeduceNullPtrTemplateArgument(
Sema &S, TemplateParameterList *TemplateParams,
const NonTypeTemplateParmDecl *NTTP, QualType NullPtrType,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
Expr *Value = S.ImpCastExprToType(
new (S.Context) CXXNullPtrLiteralExpr(S.Context.NullPtrTy,
NTTP->getLocation()),
NullPtrType,
NullPtrType->isMemberPointerType() ? CK_NullToMemberPointer
: CK_NullToPointer)
.get();
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
DeducedTemplateArgument(Value),
Value->getType(), Info, Deduced);
}
static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
Sema &S, TemplateParameterList *TemplateParams,
const NonTypeTemplateParmDecl *NTTP, Expr *Value, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
DeducedTemplateArgument(Value),
Value->getType(), Info, Deduced);
}
static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
Sema &S, TemplateParameterList *TemplateParams,
const NonTypeTemplateParmDecl *NTTP, ValueDecl *D, QualType T,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
TemplateArgument New(D, T);
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, DeducedTemplateArgument(New), T, Info, Deduced);
}
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
TemplateName Param,
TemplateName Arg,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
if (!ParamDecl) {
return Sema::TDK_Success;
}
if (TemplateTemplateParmDecl *TempParam
= dyn_cast<TemplateTemplateParmDecl>(ParamDecl)) {
if (TempParam->getDepth() != Info.getDeducedDepth())
return Sema::TDK_Success;
DeducedTemplateArgument NewDeduced(S.Context.getCanonicalTemplateName(Arg));
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[TempParam->getIndex()],
NewDeduced);
if (Result.isNull()) {
Info.Param = TempParam;
Info.FirstArg = Deduced[TempParam->getIndex()];
Info.SecondArg = NewDeduced;
return Sema::TDK_Inconsistent;
}
Deduced[TempParam->getIndex()] = Result;
return Sema::TDK_Success;
}
if (S.Context.hasSameTemplateName(Param, Arg))
return Sema::TDK_Success;
Info.FirstArg = TemplateArgument(Param);
Info.SecondArg = TemplateArgument(Arg);
return Sema::TDK_NonDeducedMismatch;
}
static Sema::TemplateDeductionResult
DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
const QualType P, QualType A,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
QualType UP = P;
if (const auto *IP = P->getAs<InjectedClassNameType>())
UP = IP->getInjectedSpecializationType();
const auto *TP = UP.getCanonicalType()->castAs<TemplateSpecializationType>();
ArrayRef<TemplateArgument> PResolved = TP->template_arguments();
QualType UA = A;
if (const auto *Injected = A->getAs<InjectedClassNameType>())
UA = Injected->getInjectedSpecializationType();
if (const auto *SA =
dyn_cast<TemplateSpecializationType>(UA.getCanonicalType())) {
if (auto Result =
DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(),
SA->getTemplateName(), Info, Deduced))
return Result;
return DeduceTemplateArguments(S, TemplateParams, PResolved,
SA->template_arguments(), Info, Deduced,
false);
}
const auto *RA = UA->getAs<RecordType>();
const auto *SA =
RA ? dyn_cast<ClassTemplateSpecializationDecl>(RA->getDecl()) : nullptr;
if (!SA) {
Info.FirstArg = TemplateArgument(P);
Info.SecondArg = TemplateArgument(A);
return Sema::TDK_NonDeducedMismatch;
}
if (auto Result = DeduceTemplateArguments(
S, TemplateParams, TP->getTemplateName(),
TemplateName(SA->getSpecializedTemplate()), Info, Deduced))
return Result;
return DeduceTemplateArguments(S, TemplateParams, PResolved,
SA->getTemplateArgs().asArray(), Info, Deduced,
true);
}
static bool IsPossiblyOpaquelyQualifiedTypeInternal(const Type *T) {
assert(T->isCanonicalUnqualified());
switch (T->getTypeClass()) {
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::DependentName:
case Type::Decltype:
case Type::UnresolvedUsing:
case Type::TemplateTypeParm:
return true;
case Type::ConstantArray:
case Type::IncompleteArray:
case Type::VariableArray:
case Type::DependentSizedArray:
return IsPossiblyOpaquelyQualifiedTypeInternal(
cast<ArrayType>(T)->getElementType().getTypePtr());
default:
return false;
}
}
static bool IsPossiblyOpaquelyQualifiedType(QualType T) {
return IsPossiblyOpaquelyQualifiedTypeInternal(
T->getCanonicalTypeInternal().getTypePtr());
}
static TemplateParameter makeTemplateParameter(Decl *D) {
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D))
return TemplateParameter(TTP);
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
return TemplateParameter(NTTP);
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
}
struct clang::DeducedPack {
unsigned Index;
DeducedTemplateArgument Saved;
DeducedTemplateArgument DeferredDeduction;
SmallVector<DeducedTemplateArgument, 4> New;
DeducedPack *Outer = nullptr;
DeducedPack(unsigned Index) : Index(Index) {}
};
namespace {
class PackDeductionScope {
public:
PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info, TemplateArgument Pattern)
: S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) {
unsigned NumNamedPacks = addPacks(Pattern);
finishConstruction(NumNamedPacks);
}
PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info, unsigned Index)
: S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) {
addPack(Index);
finishConstruction(1);
}
private:
void addPack(unsigned Index) {
DeducedPack Pack(Index);
Pack.Saved = Deduced[Index];
Deduced[Index] = TemplateArgument();
if (Optional<unsigned> ExpandedPackExpansions =
getExpandedPackSize(TemplateParams->getParam(Index)))
FixedNumExpansions = ExpandedPackExpansions;
Packs.push_back(Pack);
}
unsigned addPacks(TemplateArgument Pattern) {
llvm::SmallBitVector SawIndices(TemplateParams->size());
llvm::SmallVector<TemplateArgument, 4> ExtraDeductions;
auto AddPack = [&](unsigned Index) {
if (SawIndices[Index])
return;
SawIndices[Index] = true;
addPack(Index);
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(
TemplateParams->getParam(Index))) {
if (!NTTP->isExpandedParameterPack())
if (auto *Expansion = dyn_cast<PackExpansionType>(NTTP->getType()))
ExtraDeductions.push_back(Expansion->getPattern());
}
};
auto Collect = [&](TemplateArgument Pattern) {
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
unsigned Depth, Index;
std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
if (Depth == Info.getDeducedDepth())
AddPack(Index);
}
};
Collect(Pattern);
assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
unsigned NumNamedPacks = Packs.size();
while (!ExtraDeductions.empty())
Collect(ExtraDeductions.pop_back_val());
return NumNamedPacks;
}
void finishConstruction(unsigned NumNamedPacks) {
const TemplateArgument *PartialPackArgs = nullptr;
unsigned NumPartialPackArgs = 0;
std::pair<unsigned, unsigned> PartialPackDepthIndex(-1u, -1u);
if (auto *Scope = S.CurrentInstantiationScope)
if (auto *Partial = Scope->getPartiallySubstitutedPack(
&PartialPackArgs, &NumPartialPackArgs))
PartialPackDepthIndex = getDepthAndIndex(Partial);
bool IsExpanded = true;
for (unsigned I = 0; I != NumNamedPacks; ++I) {
if (Packs[I].Index >= Info.getNumExplicitArgs()) {
IsExpanded = false;
IsPartiallyExpanded = false;
break;
}
if (PartialPackDepthIndex ==
std::make_pair(Info.getDeducedDepth(), Packs[I].Index)) {
IsPartiallyExpanded = true;
}
}
if (IsPartiallyExpanded)
PackElements += NumPartialPackArgs;
else if (IsExpanded)
PackElements += *FixedNumExpansions;
for (auto &Pack : Packs) {
if (Info.PendingDeducedPacks.size() > Pack.Index)
Pack.Outer = Info.PendingDeducedPacks[Pack.Index];
else
Info.PendingDeducedPacks.resize(Pack.Index + 1);
Info.PendingDeducedPacks[Pack.Index] = &Pack;
if (PartialPackDepthIndex ==
std::make_pair(Info.getDeducedDepth(), Pack.Index)) {
Pack.New.append(PartialPackArgs, PartialPackArgs + NumPartialPackArgs);
if (!IsPartiallyExpanded)
Deduced[Pack.Index] = Pack.New[PackElements];
}
}
}
public:
~PackDeductionScope() {
for (auto &Pack : Packs)
Info.PendingDeducedPacks[Pack.Index] = Pack.Outer;
}
bool isPartiallyExpanded() { return IsPartiallyExpanded; }
bool hasFixedArity() { return FixedNumExpansions.has_value(); }
bool hasNextElement() {
return !FixedNumExpansions || *FixedNumExpansions > PackElements;
}
void nextPackElement() {
for (auto &Pack : Packs) {
DeducedTemplateArgument &DeducedArg = Deduced[Pack.Index];
if (!Pack.New.empty() || !DeducedArg.isNull()) {
while (Pack.New.size() < PackElements)
Pack.New.push_back(DeducedTemplateArgument());
if (Pack.New.size() == PackElements)
Pack.New.push_back(DeducedArg);
else
Pack.New[PackElements] = DeducedArg;
DeducedArg = Pack.New.size() > PackElements + 1
? Pack.New[PackElements + 1]
: DeducedTemplateArgument();
}
}
++PackElements;
}
Sema::TemplateDeductionResult finish() {
for (auto &Pack : Packs) {
Deduced[Pack.Index] = Pack.Saved;
Pack.New.resize(PackElements);
DeducedTemplateArgument NewPack;
if (Pack.New.empty()) {
NewPack = DeducedTemplateArgument(TemplateArgument::getEmptyPack());
} else {
TemplateArgument *ArgumentPack =
new (S.Context) TemplateArgument[Pack.New.size()];
std::copy(Pack.New.begin(), Pack.New.end(), ArgumentPack);
NewPack = DeducedTemplateArgument(
TemplateArgument(llvm::makeArrayRef(ArgumentPack, Pack.New.size())),
Pack.New[0].wasDeducedFromArrayBound());
}
DeducedTemplateArgument *Loc;
if (Pack.Outer) {
if (Pack.Outer->DeferredDeduction.isNull()) {
Pack.Outer->DeferredDeduction = NewPack;
continue;
}
Loc = &Pack.Outer->DeferredDeduction;
} else {
Loc = &Deduced[Pack.Index];
}
DeducedTemplateArgument OldPack = *Loc;
DeducedTemplateArgument Result =
checkDeducedTemplateArguments(S.Context, OldPack, NewPack);
if (!Result.isNull() && !Pack.DeferredDeduction.isNull()) {
OldPack = Result;
NewPack = Pack.DeferredDeduction;
Result = checkDeducedTemplateArguments(S.Context, OldPack, NewPack);
}
NamedDecl *Param = TemplateParams->getParam(Pack.Index);
if (Result.isNull()) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = OldPack;
Info.SecondArg = NewPack;
return Sema::TDK_Inconsistent;
}
if (Optional<unsigned> Expansions = getExpandedPackSize(Param)) {
if (*Expansions != PackElements) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = Result;
return Sema::TDK_IncompletePack;
}
}
*Loc = Result;
}
return Sema::TDK_Success;
}
private:
Sema &S;
TemplateParameterList *TemplateParams;
SmallVectorImpl<DeducedTemplateArgument> &Deduced;
TemplateDeductionInfo &Info;
unsigned PackElements = 0;
bool IsPartiallyExpanded = false;
Optional<unsigned> FixedNumExpansions;
SmallVector<DeducedPack, 2> Packs;
};
}
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
const QualType *Params, unsigned NumParams,
const QualType *Args, unsigned NumArgs,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF,
bool PartialOrdering = false) {
unsigned ArgIdx = 0, ParamIdx = 0;
for (; ParamIdx != NumParams; ++ParamIdx) {
const PackExpansionType *Expansion
= dyn_cast<PackExpansionType>(Params[ParamIdx]);
if (!Expansion) {
if (ArgIdx >= NumArgs)
return Sema::TDK_MiscellaneousDeductionFailure;
if (isa<PackExpansionType>(Args[ArgIdx])) {
return Sema::TDK_MiscellaneousDeductionFailure;
}
if (Sema::TemplateDeductionResult Result =
DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, Params[ParamIdx].getUnqualifiedType(),
Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF,
PartialOrdering,
false))
return Result;
++ArgIdx;
continue;
}
QualType Pattern = Expansion->getPattern();
PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern);
if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) {
for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) {
if (Sema::TemplateDeductionResult Result =
DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, Pattern.getUnqualifiedType(),
Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF,
PartialOrdering, false))
return Result;
PackScope.nextPackElement();
}
} else {
Optional<unsigned> NumExpansions = Expansion->getNumExpansions();
if (NumExpansions && !PackScope.isPartiallyExpanded()) {
for (unsigned I = 0; I != *NumExpansions && ArgIdx < NumArgs;
++I, ++ArgIdx)
PackScope.nextPackElement();
}
}
if (auto Result = PackScope.finish())
return Result;
}
if (ArgIdx < NumArgs)
return Sema::TDK_MiscellaneousDeductionFailure;
return Sema::TDK_Success;
}
static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType,
QualType ArgType) {
Qualifiers ParamQs = ParamType.getQualifiers();
Qualifiers ArgQs = ArgType.getQualifiers();
if (ParamQs == ArgQs)
return false;
if (ParamQs.getObjCGCAttr() != ArgQs.getObjCGCAttr() &&
ParamQs.hasObjCGCAttr())
return true;
if (ParamQs.getAddressSpace() != ArgQs.getAddressSpace() &&
ParamQs.hasAddressSpace())
return true;
if (ParamQs.getObjCLifetime() != ArgQs.getObjCLifetime() &&
ParamQs.hasObjCLifetime())
return true;
return (ParamQs.getCVRQualifiers() & ~ArgQs.getCVRQualifiers()) != 0;
}
bool Sema::isSameOrCompatibleFunctionType(QualType P, QualType A) {
const FunctionType *PF = P->getAs<FunctionType>(),
*AF = A->getAs<FunctionType>();
if (!PF || !AF)
return Context.hasSameType(P, A);
QualType AdjustedParam;
if (IsFunctionConversion(P, A, AdjustedParam))
return Context.hasSameType(AdjustedParam, A);
return Context.hasSameType(P, A);
}
static unsigned getFirstInnerIndex(FunctionTemplateDecl *FTD) {
auto *Guide = dyn_cast<CXXDeductionGuideDecl>(FTD->getTemplatedDecl());
if (!Guide || !Guide->isImplicit())
return 0;
return Guide->getDeducedTemplate()->getTemplateParameters()->size();
}
static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) {
if (auto *ParamRef = Param->getAs<RValueReferenceType>()) {
if (ParamRef->getPointeeType().getQualifiers())
return false;
auto *TypeParm = ParamRef->getPointeeType()->getAs<TemplateTypeParmType>();
return TypeParm && TypeParm->getIndex() >= FirstInnerIndex;
}
return false;
}
static CXXRecordDecl *getCanonicalRD(QualType T) {
return cast<CXXRecordDecl>(
T->castAs<RecordType>()->getDecl()->getCanonicalDecl());
}
static Sema::TemplateDeductionResult
DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
TemplateParameterList *TemplateParams, QualType P,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
llvm::SmallPtrSet<const CXXRecordDecl *, 8> Visited;
SmallVector<QualType, 8> ToVisit;
llvm::MapVector<const CXXRecordDecl *,
SmallVector<DeducedTemplateArgument, 8>>
Matches;
auto AddBases = [&Visited, &ToVisit](const CXXRecordDecl *RD) {
for (const auto &Base : RD->bases()) {
QualType T = Base.getType();
assert(T->isRecordType() && "Base class that isn't a record?");
if (Visited.insert(::getCanonicalRD(T)).second)
ToVisit.push_back(T);
}
};
AddBases(RD);
while (!ToVisit.empty()) {
QualType NextT = ToVisit.pop_back_val();
SmallVector<DeducedTemplateArgument, 8> DeducedCopy(Deduced.begin(),
Deduced.end());
TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info);
Sema::TemplateDeductionResult BaseResult = DeduceTemplateSpecArguments(
S, TemplateParams, P, NextT, BaseInfo, DeducedCopy);
const CXXRecordDecl *RD = ::getCanonicalRD(NextT);
if (BaseResult == Sema::TDK_Success)
Matches.insert({RD, DeducedCopy});
else
AddBases(RD);
}
if (Matches.size() > 1) {
Visited.clear();
for (const auto &Match : Matches)
AddBases(Match.first);
while (Matches.size() > 1 && !ToVisit.empty()) {
const CXXRecordDecl *RD = ::getCanonicalRD(ToVisit.pop_back_val());
Matches.erase(RD);
AddBases(RD);
}
}
if (Matches.empty())
return Sema::TDK_Invalid;
if (Matches.size() > 1)
return Sema::TDK_MiscellaneousDeductionFailure;
std::swap(Matches.front().second, Deduced);
return Sema::TDK_Success;
}
static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
Sema &S, TemplateParameterList *TemplateParams, QualType P, QualType A,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF,
bool PartialOrdering, bool DeducedFromArrayBound) {
if (const auto *AExp = dyn_cast<PackExpansionType>(A))
A = AExp->getPattern();
assert(!isa<PackExpansionType>(A.getCanonicalType()));
if (PartialOrdering) {
const ReferenceType *PRef = P->getAs<ReferenceType>();
if (PRef)
P = PRef->getPointeeType();
const ReferenceType *ARef = A->getAs<ReferenceType>();
if (ARef)
A = A->getPointeeType();
if (PRef && ARef && S.Context.hasSameUnqualifiedType(P, A)) {
Qualifiers PQuals = P.getQualifiers(), AQuals = A.getQualifiers();
if ((PRef->isLValueReferenceType() && !ARef->isLValueReferenceType()) ||
PQuals.isStrictSupersetOf(AQuals) ||
(PQuals.hasNonTrivialObjCLifetime() &&
AQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone &&
PQuals.withoutObjCLifetime() == AQuals.withoutObjCLifetime())) {
Info.FirstArg = TemplateArgument(P);
Info.SecondArg = TemplateArgument(A);
return Sema::TDK_NonDeducedMismatch;
}
}
Qualifiers DiscardedQuals;
P = S.Context.getUnqualifiedArrayType(P, DiscardedQuals);
A = S.Context.getUnqualifiedArrayType(A, DiscardedQuals);
} else {
if (TDF & TDF_ParamWithReferenceType) {
Qualifiers Quals;
QualType UnqualP = S.Context.getUnqualifiedArrayType(P, Quals);
Quals.setCVRQualifiers(Quals.getCVRQualifiers() & A.getCVRQualifiers());
P = S.Context.getQualifiedType(UnqualP, Quals);
}
if ((TDF & TDF_TopLevelParameterTypeList) && !P->isFunctionType()) {
TDF &= ~TDF_TopLevelParameterTypeList;
if (isForwardingReference(P, 0) &&
A->isLValueReferenceType())
P = P->getPointeeType();
}
}
if (const auto *TTP = P->getAs<TemplateTypeParmType>()) {
if (A->isPlaceholderType() || Info.getDeducedDepth() != TTP->getDepth())
return Sema::TDK_Success;
unsigned Index = TTP->getIndex();
if (A->isArrayType()) {
Qualifiers Quals;
A = S.Context.getUnqualifiedArrayType(A, Quals);
if (Quals)
A = S.Context.getQualifiedType(A, Quals);
}
if (!(TDF & TDF_IgnoreQualifiers) &&
hasInconsistentOrSupersetQualifiersOf(P, A)) {
Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
Info.FirstArg = TemplateArgument(P);
Info.SecondArg = TemplateArgument(A);
return Sema::TDK_Underqualified;
}
if (A->isFunctionType() && P.hasQualifiers())
return Sema::TDK_NonDeducedMismatch;
assert(TTP->getDepth() == Info.getDeducedDepth() &&
"saw template type parameter with wrong depth");
assert(A->getCanonicalTypeInternal() != S.Context.OverloadTy &&
"Unresolved overloaded function");
QualType DeducedType = A;
Qualifiers DeducedQs = DeducedType.getQualifiers();
Qualifiers ParamQs = P.getQualifiers();
DeducedQs.removeCVRQualifiers(ParamQs.getCVRQualifiers());
if (ParamQs.hasObjCGCAttr())
DeducedQs.removeObjCGCAttr();
if (ParamQs.hasAddressSpace())
DeducedQs.removeAddressSpace();
if (ParamQs.hasObjCLifetime())
DeducedQs.removeObjCLifetime();
if (ParamQs.hasObjCLifetime() && !DeducedType->isObjCLifetimeType() &&
!DeducedType->isDependentType()) {
Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
Info.FirstArg = TemplateArgument(P);
Info.SecondArg = TemplateArgument(A);
return Sema::TDK_Underqualified;
}
if (S.getLangOpts().ObjCAutoRefCount && DeducedType->isObjCLifetimeType() &&
!DeducedQs.hasObjCLifetime())
DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong);
DeducedType =
S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), DeducedQs);
DeducedTemplateArgument NewDeduced(DeducedType, DeducedFromArrayBound);
DeducedTemplateArgument Result =
checkDeducedTemplateArguments(S.Context, Deduced[Index], NewDeduced);
if (Result.isNull()) {
Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
Info.FirstArg = Deduced[Index];
Info.SecondArg = NewDeduced;
return Sema::TDK_Inconsistent;
}
Deduced[Index] = Result;
return Sema::TDK_Success;
}
Info.FirstArg = TemplateArgument(P);
Info.SecondArg = TemplateArgument(A);
if (P->getAs<SubstTemplateTypeParmPackType>())
return Sema::TDK_Success;
if (!(TDF & TDF_IgnoreQualifiers)) {
if (TDF & TDF_ParamWithReferenceType) {
if (hasInconsistentOrSupersetQualifiersOf(P, A))
return Sema::TDK_NonDeducedMismatch;
} else if (TDF & TDF_ArgWithReferenceType) {
if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers()))
return Sema::TDK_NonDeducedMismatch;
Qualifiers Quals;
A = S.Context.getUnqualifiedArrayType(A, Quals);
A = S.Context.getQualifiedType(A, P.getQualifiers());
} else if (!IsPossiblyOpaquelyQualifiedType(P)) {
if (P.getCVRQualifiers() != A.getCVRQualifiers())
return Sema::TDK_NonDeducedMismatch;
}
}
if (!P->isDependentType()) {
if (TDF & TDF_SkipNonDependent)
return Sema::TDK_Success;
if ((TDF & TDF_IgnoreQualifiers) ? S.Context.hasSameUnqualifiedType(P, A)
: S.Context.hasSameType(P, A))
return Sema::TDK_Success;
if (TDF & TDF_AllowCompatibleFunctionType &&
S.isSameOrCompatibleFunctionType(P, A))
return Sema::TDK_Success;
if (!(TDF & TDF_IgnoreQualifiers))
return Sema::TDK_NonDeducedMismatch;
}
switch (P.getCanonicalType()->getTypeClass()) {
#define NON_CANONICAL_TYPE(Class, Base) \
case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class);
#define TYPE(Class, Base)
#include "clang/AST/TypeNodes.inc"
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
llvm_unreachable("Type nodes handled above");
case Type::Auto:
if (P->isDependentType())
return Sema::TDK_Success;
LLVM_FALLTHROUGH;
case Type::Builtin:
case Type::VariableArray:
case Type::Vector:
case Type::FunctionNoProto:
case Type::Record:
case Type::Enum:
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
case Type::BitInt:
return (TDF & TDF_SkipNonDependent) ||
((TDF & TDF_IgnoreQualifiers)
? S.Context.hasSameUnqualifiedType(P, A)
: S.Context.hasSameType(P, A))
? Sema::TDK_Success
: Sema::TDK_NonDeducedMismatch;
case Type::Complex: {
const auto *CP = P->castAs<ComplexType>(), *CA = A->getAs<ComplexType>();
if (!CA)
return Sema::TDK_NonDeducedMismatch;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, CP->getElementType(), CA->getElementType(), Info,
Deduced, TDF);
}
case Type::Atomic: {
const auto *PA = P->castAs<AtomicType>(), *AA = A->getAs<AtomicType>();
if (!AA)
return Sema::TDK_NonDeducedMismatch;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, PA->getValueType(), AA->getValueType(), Info,
Deduced, TDF);
}
case Type::Pointer: {
QualType PointeeType;
if (const auto *PA = A->getAs<PointerType>()) {
PointeeType = PA->getPointeeType();
} else if (const auto *PA = A->getAs<ObjCObjectPointerType>()) {
PointeeType = PA->getPointeeType();
} else {
return Sema::TDK_NonDeducedMismatch;
}
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, P->castAs<PointerType>()->getPointeeType(),
PointeeType, Info, Deduced,
TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass));
}
case Type::LValueReference: {
const auto *RP = P->castAs<LValueReferenceType>(),
*RA = A->getAs<LValueReferenceType>();
if (!RA)
return Sema::TDK_NonDeducedMismatch;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info,
Deduced, 0);
}
case Type::RValueReference: {
const auto *RP = P->castAs<RValueReferenceType>(),
*RA = A->getAs<RValueReferenceType>();
if (!RA)
return Sema::TDK_NonDeducedMismatch;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info,
Deduced, 0);
}
case Type::IncompleteArray: {
const auto *IAA = S.Context.getAsIncompleteArrayType(A);
if (!IAA)
return Sema::TDK_NonDeducedMismatch;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams,
S.Context.getAsIncompleteArrayType(P)->getElementType(),
IAA->getElementType(), Info, Deduced, TDF & TDF_IgnoreQualifiers);
}
case Type::ConstantArray: {
const auto *CAA = S.Context.getAsConstantArrayType(A),
*CAP = S.Context.getAsConstantArrayType(P);
assert(CAP);
if (!CAA || CAA->getSize() != CAP->getSize())
return Sema::TDK_NonDeducedMismatch;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, CAP->getElementType(), CAA->getElementType(), Info,
Deduced, TDF & TDF_IgnoreQualifiers);
}
case Type::DependentSizedArray: {
const auto *AA = S.Context.getAsArrayType(A);
if (!AA)
return Sema::TDK_NonDeducedMismatch;
const auto *DAP = S.Context.getAsDependentSizedArrayType(P);
assert(DAP);
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, DAP->getElementType(), AA->getElementType(),
Info, Deduced, TDF & TDF_IgnoreQualifiers))
return Result;
const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, DAP->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
assert(NTTP->getDepth() == Info.getDeducedDepth() &&
"saw non-type template parameter with wrong depth");
if (const auto *CAA = dyn_cast<ConstantArrayType>(AA)) {
llvm::APSInt Size(CAA->getSize());
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, Size, S.Context.getSizeType(),
true, Info, Deduced);
}
if (const auto *DAA = dyn_cast<DependentSizedArrayType>(AA))
if (DAA->getSizeExpr())
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, DAA->getSizeExpr(), Info, Deduced);
return Sema::TDK_NonDeducedMismatch;
}
case Type::FunctionProto: {
const auto *FPP = P->castAs<FunctionProtoType>(),
*FPA = A->getAs<FunctionProtoType>();
if (!FPA)
return Sema::TDK_NonDeducedMismatch;
if (FPP->getMethodQuals() != FPA->getMethodQuals() ||
FPP->getRefQualifier() != FPA->getRefQualifier() ||
FPP->isVariadic() != FPA->isVariadic())
return Sema::TDK_NonDeducedMismatch;
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, FPP->getReturnType(), FPA->getReturnType(),
Info, Deduced, 0,
false,
false))
return Result;
if (auto Result = DeduceTemplateArguments(
S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(),
FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced,
TDF & TDF_TopLevelParameterTypeList))
return Result;
if (TDF & TDF_AllowCompatibleFunctionType)
return Sema::TDK_Success;
Expr *NoexceptExpr = FPP->getNoexceptExpr();
if (const NonTypeTemplateParmDecl *NTTP =
NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr)
: nullptr) {
assert(NTTP->getDepth() == Info.getDeducedDepth() &&
"saw non-type template parameter with wrong depth");
llvm::APSInt Noexcept(1);
switch (FPA->canThrow()) {
case CT_Cannot:
Noexcept = 1;
LLVM_FALLTHROUGH;
case CT_Can:
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy,
true, Info, Deduced);
case CT_Dependent:
if (Expr *ArgNoexceptExpr = FPA->getNoexceptExpr())
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, ArgNoexceptExpr, Info, Deduced);
break;
}
}
return Sema::TDK_Success;
}
case Type::InjectedClassName:
case Type::TemplateSpecialization: {
if (!(TDF & TDF_DerivedClass) || !A->isRecordType())
return DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info,
Deduced);
SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(),
Deduced.end());
auto Result =
DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, Deduced);
if (Result == Sema::TDK_Success)
return Result;
if (!S.isCompleteType(Info.getLocation(), A))
return Result;
Deduced = DeducedOrig;
auto BaseResult = DeduceTemplateBases(S, getCanonicalRD(A),
TemplateParams, P, Info, Deduced);
return BaseResult != Sema::TDK_Invalid ? BaseResult : Result;
}
case Type::MemberPointer: {
const auto *MPP = P->castAs<MemberPointerType>(),
*MPA = A->getAs<MemberPointerType>();
if (!MPA)
return Sema::TDK_NonDeducedMismatch;
QualType PPT = MPP->getPointeeType();
if (PPT->isFunctionType())
S.adjustMemberFunctionCC(PPT, true,
false, Info.getLocation());
QualType APT = MPA->getPointeeType();
if (APT->isFunctionType())
S.adjustMemberFunctionCC(APT, true,
false, Info.getLocation());
unsigned SubTDF = TDF & TDF_IgnoreQualifiers;
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, PPT, APT, Info, Deduced, SubTDF))
return Result;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, QualType(MPP->getClass(), 0),
QualType(MPA->getClass(), 0), Info, Deduced, SubTDF);
}
case Type::BlockPointer: {
const auto *BPP = P->castAs<BlockPointerType>(),
*BPA = A->getAs<BlockPointerType>();
if (!BPA)
return Sema::TDK_NonDeducedMismatch;
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, BPP->getPointeeType(), BPA->getPointeeType(), Info,
Deduced, 0);
}
case Type::ExtVector: {
const auto *VP = P->castAs<ExtVectorType>();
QualType ElementType;
if (const auto *VA = A->getAs<ExtVectorType>()) {
if (VP->getNumElements() != VA->getNumElements())
return Sema::TDK_NonDeducedMismatch;
ElementType = VA->getElementType();
} else if (const auto *VA = A->getAs<DependentSizedExtVectorType>()) {
ElementType = VA->getElementType();
} else {
return Sema::TDK_NonDeducedMismatch;
}
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, VP->getElementType(), ElementType, Info, Deduced,
TDF);
}
case Type::DependentVector: {
const auto *VP = P->castAs<DependentVectorType>();
if (const auto *VA = A->getAs<VectorType>()) {
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, VP->getElementType(), VA->getElementType(),
Info, Deduced, TDF))
return Result;
const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
ArgSize = VA->getNumElements();
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
S.Context.UnsignedIntTy, true,
Info, Deduced);
}
if (const auto *VA = A->getAs<DependentVectorType>()) {
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, VP->getElementType(), VA->getElementType(),
Info, Deduced, TDF))
return Result;
const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
VA->getSizeExpr(), Info, Deduced);
}
return Sema::TDK_NonDeducedMismatch;
}
case Type::DependentSizedExtVector: {
const auto *VP = P->castAs<DependentSizedExtVectorType>();
if (const auto *VA = A->getAs<ExtVectorType>()) {
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, VP->getElementType(), VA->getElementType(),
Info, Deduced, TDF))
return Result;
const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
ArgSize = VA->getNumElements();
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
S.Context.IntTy, true, Info,
Deduced);
}
if (const auto *VA = A->getAs<DependentSizedExtVectorType>()) {
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, VP->getElementType(), VA->getElementType(),
Info, Deduced, TDF))
return Result;
const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return Sema::TDK_Success;
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
VA->getSizeExpr(), Info, Deduced);
}
return Sema::TDK_NonDeducedMismatch;
}
case Type::ConstantMatrix: {
const auto *MP = P->castAs<ConstantMatrixType>(),
*MA = A->getAs<ConstantMatrixType>();
if (!MA)
return Sema::TDK_NonDeducedMismatch;
if (MP->getNumRows() != MA->getNumRows() ||
MP->getNumColumns() != MA->getNumColumns()) {
return Sema::TDK_NonDeducedMismatch;
}
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, MP->getElementType(), MA->getElementType(), Info,
Deduced, TDF);
}
case Type::DependentSizedMatrix: {
const auto *MP = P->castAs<DependentSizedMatrixType>();
const auto *MA = A->getAs<MatrixType>();
if (!MA)
return Sema::TDK_NonDeducedMismatch;
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, MP->getElementType(), MA->getElementType(),
Info, Deduced, TDF))
return Result;
auto DeduceMatrixArg =
[&S, &Info, &Deduced, &TemplateParams](
Expr *ParamExpr, const MatrixType *A,
unsigned (ConstantMatrixType::*GetArgDimension)() const,
Expr *(DependentSizedMatrixType::*GetArgDimensionExpr)() const) {
const auto *ACM = dyn_cast<ConstantMatrixType>(A);
const auto *ADM = dyn_cast<DependentSizedMatrixType>(A);
if (!ParamExpr->isValueDependent()) {
Optional<llvm::APSInt> ParamConst =
ParamExpr->getIntegerConstantExpr(S.Context);
if (!ParamConst)
return Sema::TDK_NonDeducedMismatch;
if (ACM) {
if ((ACM->*GetArgDimension)() == *ParamConst)
return Sema::TDK_Success;
return Sema::TDK_NonDeducedMismatch;
}
Expr *ArgExpr = (ADM->*GetArgDimensionExpr)();
if (Optional<llvm::APSInt> ArgConst =
ArgExpr->getIntegerConstantExpr(S.Context))
if (*ArgConst == *ParamConst)
return Sema::TDK_Success;
return Sema::TDK_NonDeducedMismatch;
}
const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, ParamExpr);
if (!NTTP)
return Sema::TDK_Success;
if (ACM) {
llvm::APSInt ArgConst(
S.Context.getTypeSize(S.Context.getSizeType()));
ArgConst = (ACM->*GetArgDimension)();
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, ArgConst, S.Context.getSizeType(),
true, Info, Deduced);
}
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
(ADM->*GetArgDimensionExpr)(),
Info, Deduced);
};
if (auto Result = DeduceMatrixArg(MP->getRowExpr(), MA,
&ConstantMatrixType::getNumRows,
&DependentSizedMatrixType::getRowExpr))
return Result;
return DeduceMatrixArg(MP->getColumnExpr(), MA,
&ConstantMatrixType::getNumColumns,
&DependentSizedMatrixType::getColumnExpr);
}
case Type::DependentAddressSpace: {
const auto *ASP = P->castAs<DependentAddressSpaceType>();
if (const auto *ASA = A->getAs<DependentAddressSpaceType>()) {
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, ASP->getPointeeType(), ASA->getPointeeType(),
Info, Deduced, TDF))
return Result;
const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr());
if (!NTTP)
return Sema::TDK_Success;
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, ASA->getAddrSpaceExpr(), Info, Deduced);
}
if (isTargetAddressSpace(A.getAddressSpace())) {
llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy),
false);
ArgAddressSpace = toTargetAddressSpace(A.getAddressSpace());
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, ASP->getPointeeType(),
S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF))
return Result;
const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr());
if (!NTTP)
return Sema::TDK_Success;
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
ArgAddressSpace, S.Context.IntTy,
true, Info, Deduced);
}
return Sema::TDK_NonDeducedMismatch;
}
case Type::DependentBitInt: {
const auto *IP = P->castAs<DependentBitIntType>();
if (const auto *IA = A->getAs<BitIntType>()) {
if (IP->isUnsigned() != IA->isUnsigned())
return Sema::TDK_NonDeducedMismatch;
const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, IP->getNumBitsExpr());
if (!NTTP)
return Sema::TDK_Success;
llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
ArgSize = IA->getNumBits();
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize,
S.Context.IntTy, true, Info,
Deduced);
}
if (const auto *IA = A->getAs<DependentBitIntType>()) {
if (IP->isUnsigned() != IA->isUnsigned())
return Sema::TDK_NonDeducedMismatch;
return Sema::TDK_Success;
}
return Sema::TDK_NonDeducedMismatch;
}
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::DependentName:
case Type::UnresolvedUsing:
case Type::Decltype:
case Type::UnaryTransform:
case Type::DeducedTemplateSpecialization:
case Type::DependentTemplateSpecialization:
case Type::PackExpansion:
case Type::Pipe:
return Sema::TDK_Success;
}
llvm_unreachable("Invalid Type Class!");
}
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
const TemplateArgument &P, TemplateArgument A,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
if (A.isPackExpansion())
A = A.getPackExpansionPattern();
switch (P.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Null template argument in parameter list");
case TemplateArgument::Type:
if (A.getKind() == TemplateArgument::Type)
return DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, P.getAsType(), A.getAsType(), Info, Deduced, 0);
Info.FirstArg = P;
Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::Template:
if (A.getKind() == TemplateArgument::Template)
return DeduceTemplateArguments(S, TemplateParams, P.getAsTemplate(),
A.getAsTemplate(), Info, Deduced);
Info.FirstArg = P;
Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::TemplateExpansion:
llvm_unreachable("caller should handle pack expansions");
case TemplateArgument::Declaration:
if (A.getKind() == TemplateArgument::Declaration &&
isSameDeclaration(P.getAsDecl(), A.getAsDecl()))
return Sema::TDK_Success;
Info.FirstArg = P;
Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::NullPtr:
if (A.getKind() == TemplateArgument::NullPtr &&
S.Context.hasSameType(P.getNullPtrType(), A.getNullPtrType()))
return Sema::TDK_Success;
Info.FirstArg = P;
Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::Integral:
if (A.getKind() == TemplateArgument::Integral) {
if (hasSameExtendedValue(P.getAsIntegral(), A.getAsIntegral()))
return Sema::TDK_Success;
}
Info.FirstArg = P;
Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::Expression:
if (const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, P.getAsExpr())) {
if (A.getKind() == TemplateArgument::Integral)
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, A.getAsIntegral(), A.getIntegralType(),
false, Info, Deduced);
if (A.getKind() == TemplateArgument::NullPtr)
return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP,
A.getNullPtrType(), Info, Deduced);
if (A.getKind() == TemplateArgument::Expression)
return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
A.getAsExpr(), Info, Deduced);
if (A.getKind() == TemplateArgument::Declaration)
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, A.getAsDecl(), A.getParamTypeForDecl(),
Info, Deduced);
Info.FirstArg = P;
Info.SecondArg = A;
return Sema::TDK_NonDeducedMismatch;
}
return Sema::TDK_Success;
case TemplateArgument::Pack:
llvm_unreachable("Argument packs should be expanded by the caller!");
}
llvm_unreachable("Invalid TemplateArgument Kind!");
}
static bool hasTemplateArgumentForDeduction(ArrayRef<TemplateArgument> &Args,
unsigned &ArgIdx) {
if (ArgIdx == Args.size())
return false;
const TemplateArgument &Arg = Args[ArgIdx];
if (Arg.getKind() != TemplateArgument::Pack)
return true;
assert(ArgIdx == Args.size() - 1 && "Pack not at the end of argument list?");
Args = Arg.pack_elements();
ArgIdx = 0;
return ArgIdx < Args.size();
}
static bool hasPackExpansionBeforeEnd(ArrayRef<TemplateArgument> Args) {
bool FoundPackExpansion = false;
for (const auto &A : Args) {
if (FoundPackExpansion)
return true;
if (A.getKind() == TemplateArgument::Pack)
return hasPackExpansionBeforeEnd(A.pack_elements());
if (A.isPackExpansion())
FoundPackExpansion = true;
}
return false;
}
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
ArrayRef<TemplateArgument> Ps,
ArrayRef<TemplateArgument> As,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch) {
if (hasPackExpansionBeforeEnd(Ps))
return Sema::TDK_Success;
unsigned ArgIdx = 0, ParamIdx = 0;
for (; hasTemplateArgumentForDeduction(Ps, ParamIdx); ++ParamIdx) {
const TemplateArgument &P = Ps[ParamIdx];
if (!P.isPackExpansion()) {
if (!hasTemplateArgumentForDeduction(As, ArgIdx))
return NumberOfArgumentsMustMatch
? Sema::TDK_MiscellaneousDeductionFailure
: Sema::TDK_Success;
if (As[ArgIdx].isPackExpansion())
return Sema::TDK_MiscellaneousDeductionFailure;
if (auto Result = DeduceTemplateArguments(S, TemplateParams, P,
As[ArgIdx], Info, Deduced))
return Result;
++ArgIdx;
continue;
}
TemplateArgument Pattern = P.getPackExpansionPattern();
PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern);
for (; hasTemplateArgumentForDeduction(As, ArgIdx) &&
PackScope.hasNextElement();
++ArgIdx) {
if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pattern,
As[ArgIdx], Info, Deduced))
return Result;
PackScope.nextPackElement();
}
if (auto Result = PackScope.finish())
return Result;
}
return Sema::TDK_Success;
}
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
return DeduceTemplateArguments(S, TemplateParams, ParamList.asArray(),
ArgList.asArray(), Info, Deduced,
false);
}
static bool isSameTemplateArg(ASTContext &Context,
TemplateArgument X,
const TemplateArgument &Y,
bool PackExpansionMatchesPack = false) {
if (PackExpansionMatchesPack && X.isPackExpansion() && !Y.isPackExpansion())
X = X.getPackExpansionPattern();
if (X.getKind() != Y.getKind())
return false;
switch (X.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Comparing NULL template argument");
case TemplateArgument::Type:
return Context.getCanonicalType(X.getAsType()) ==
Context.getCanonicalType(Y.getAsType());
case TemplateArgument::Declaration:
return isSameDeclaration(X.getAsDecl(), Y.getAsDecl());
case TemplateArgument::NullPtr:
return Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType());
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
return Context.getCanonicalTemplateName(
X.getAsTemplateOrTemplatePattern()).getAsVoidPointer() ==
Context.getCanonicalTemplateName(
Y.getAsTemplateOrTemplatePattern()).getAsVoidPointer();
case TemplateArgument::Integral:
return hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral());
case TemplateArgument::Expression: {
llvm::FoldingSetNodeID XID, YID;
X.getAsExpr()->Profile(XID, Context, true);
Y.getAsExpr()->Profile(YID, Context, true);
return XID == YID;
}
case TemplateArgument::Pack:
if (X.pack_size() != Y.pack_size())
return false;
for (TemplateArgument::pack_iterator XP = X.pack_begin(),
XPEnd = X.pack_end(),
YP = Y.pack_begin();
XP != XPEnd; ++XP, ++YP)
if (!isSameTemplateArg(Context, *XP, *YP, PackExpansionMatchesPack))
return false;
return true;
}
llvm_unreachable("Invalid TemplateArgument Kind!");
}
TemplateArgumentLoc
Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
QualType NTTPType, SourceLocation Loc) {
switch (Arg.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Can't get a NULL template argument here");
case TemplateArgument::Type:
return TemplateArgumentLoc(
Arg, Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
case TemplateArgument::Declaration: {
if (NTTPType.isNull())
NTTPType = Arg.getParamTypeForDecl();
Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
.getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(E), E);
}
case TemplateArgument::NullPtr: {
if (NTTPType.isNull())
NTTPType = Arg.getNullPtrType();
Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
.getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(NTTPType, true),
E);
}
case TemplateArgument::Integral: {
Expr *E =
BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(E), E);
}
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion: {
NestedNameSpecifierLocBuilder Builder;
TemplateName Template = Arg.getAsTemplateOrTemplatePattern();
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
else if (QualifiedTemplateName *QTN =
Template.getAsQualifiedTemplateName())
Builder.MakeTrivial(Context, QTN->getQualifier(), Loc);
if (Arg.getKind() == TemplateArgument::Template)
return TemplateArgumentLoc(Context, Arg,
Builder.getWithLocInContext(Context), Loc);
return TemplateArgumentLoc(
Context, Arg, Builder.getWithLocInContext(Context), Loc, Loc);
}
case TemplateArgument::Expression:
return TemplateArgumentLoc(Arg, Arg.getAsExpr());
case TemplateArgument::Pack:
return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo());
}
llvm_unreachable("Invalid TemplateArgument Kind!");
}
TemplateArgumentLoc
Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm,
SourceLocation Location) {
return getTrivialTemplateArgumentLoc(
Context.getInjectedTemplateArg(TemplateParm), QualType(), Location);
}
static bool
ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
DeducedTemplateArgument Arg,
NamedDecl *Template,
TemplateDeductionInfo &Info,
bool IsDeduced,
SmallVectorImpl<TemplateArgument> &Output) {
auto ConvertArg = [&](DeducedTemplateArgument Arg,
unsigned ArgumentPackIndex) {
TemplateArgumentLoc ArgLoc =
S.getTrivialTemplateArgumentLoc(Arg, QualType(), Info.getLocation());
return S.CheckTemplateArgument(
Param, ArgLoc, Template, Template->getLocation(),
Template->getSourceRange().getEnd(), ArgumentPackIndex, Output,
IsDeduced
? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound
: Sema::CTAK_Deduced)
: Sema::CTAK_Specified);
};
if (Arg.getKind() == TemplateArgument::Pack) {
SmallVector<TemplateArgument, 2> PackedArgsBuilder;
for (const auto &P : Arg.pack_elements()) {
DeducedTemplateArgument InnerArg(P);
InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound());
assert(InnerArg.getKind() != TemplateArgument::Pack &&
"deduced nested pack");
if (P.isNull()) {
S.Diag(Param->getLocation(),
diag::err_template_arg_deduced_incomplete_pack)
<< Arg << Param;
return true;
}
if (ConvertArg(InnerArg, PackedArgsBuilder.size()))
return true;
PackedArgsBuilder.push_back(Output.pop_back_val());
}
if (PackedArgsBuilder.empty()) {
LocalInstantiationScope Scope(S);
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Output);
MultiLevelTemplateArgumentList Args(TemplateArgs);
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
NTTP, Output,
Template->getSourceRange());
if (Inst.isInvalid() ||
S.SubstType(NTTP->getType(), Args, NTTP->getLocation(),
NTTP->getDeclName()).isNull())
return true;
} else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) {
Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
TTP, Output,
Template->getSourceRange());
if (Inst.isInvalid() || !S.SubstDecl(TTP, S.CurContext, Args))
return true;
}
}
Output.push_back(
TemplateArgument::CreatePackCopy(S.Context, PackedArgsBuilder));
return false;
}
return ConvertArg(Arg, 0);
}
template<typename TemplateDeclT>
static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
Sema &S, TemplateDeclT *Template, bool IsDeduced,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info, SmallVectorImpl<TemplateArgument> &Builder,
LocalInstantiationScope *CurrentInstantiationScope = nullptr,
unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) {
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
NamedDecl *Param = TemplateParams->getParam(I);
if (Deduced[I].isNull() && Param->isTemplateParameterPack()) {
if (auto Result =
PackDeductionScope(S, TemplateParams, Deduced, Info, I).finish())
return Result;
}
if (!Deduced[I].isNull()) {
if (I < NumAlreadyConverted) {
if (Param->isParameterPack() && CurrentInstantiationScope &&
CurrentInstantiationScope->getPartiallySubstitutedPack() == Param) {
CurrentInstantiationScope->ResetPartiallySubstitutedPack();
} else {
Builder.push_back(Deduced[I]);
continue;
}
}
if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info,
IsDeduced, Builder)) {
Info.Param = makeTemplateParameter(Param);
Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
return Sema::TDK_SubstitutionFailure;
}
continue;
}
bool HasDefaultArg = false;
TemplateDecl *TD = dyn_cast<TemplateDecl>(Template);
if (!TD) {
assert(isa<ClassTemplatePartialSpecializationDecl>(Template) ||
isa<VarTemplatePartialSpecializationDecl>(Template));
return Sema::TDK_Incomplete;
}
TemplateArgumentLoc DefArg;
{
Qualifiers ThisTypeQuals;
CXXRecordDecl *ThisContext = nullptr;
if (auto *Rec = dyn_cast<CXXRecordDecl>(TD->getDeclContext()))
if (Rec->isLambda())
if (auto *Method = dyn_cast<CXXMethodDecl>(Rec->getDeclContext())) {
ThisContext = Method->getParent();
ThisTypeQuals = Method->getMethodQualifiers();
}
Sema::CXXThisScopeRAII ThisScope(S, ThisContext, ThisTypeQuals,
S.getLangOpts().CPlusPlus17);
DefArg = S.SubstDefaultTemplateArgumentIfAvailable(
TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder,
HasDefaultArg);
}
if (DefArg.getArgument().isNull()) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
if (PartialOverloading) break;
return HasDefaultArg ? Sema::TDK_SubstitutionFailure
: Sema::TDK_Incomplete;
}
if (S.CheckTemplateArgument(Param, DefArg, TD, TD->getLocation(),
TD->getSourceRange().getEnd(), 0, Builder,
Sema::CTAK_Specified)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
return Sema::TDK_SubstitutionFailure;
}
}
return Sema::TDK_Success;
}
static DeclContext *getAsDeclContextOrEnclosing(Decl *D) {
if (auto *DC = dyn_cast<DeclContext>(D))
return DC;
return D->getDeclContext();
}
template<typename T> struct IsPartialSpecialization {
static constexpr bool value = false;
};
template<>
struct IsPartialSpecialization<ClassTemplatePartialSpecializationDecl> {
static constexpr bool value = true;
};
template<>
struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
static constexpr bool value = true;
};
template<typename TemplateDeclT>
static Sema::TemplateDeductionResult
CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
ArrayRef<TemplateArgument> DeducedArgs,
TemplateDeductionInfo& Info) {
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
Template->getAssociatedConstraints(AssociatedConstraints);
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
DeducedArgs, Info.getLocation(),
Info.AssociatedConstraintsSatisfaction) ||
!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
return Sema::TDK_ConstraintsNotSatisfied;
}
return Sema::TDK_Success;
}
template <typename T>
static std::enable_if_t<IsPartialSpecialization<T>::value,
Sema::TemplateDeductionResult>
FinishTemplateArgumentDeduction(
Sema &S, T *Partial, bool IsPartialOrdering,
const TemplateArgumentList &TemplateArgs,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info) {
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::Unevaluated);
Sema::SFINAETrap Trap(S);
Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Partial));
SmallVector<TemplateArgument, 4> Builder;
if (auto Result = ConvertDeducedTemplateArguments(
S, Partial, IsPartialOrdering, Deduced, Info, Builder))
return Result;
TemplateArgumentList *DeducedArgumentList
= TemplateArgumentList::CreateCopy(S.Context, Builder);
Info.reset(DeducedArgumentList);
LocalInstantiationScope InstScope(S);
auto *Template = Partial->getSpecializedTemplate();
const ASTTemplateArgumentListInfo *PartialTemplArgInfo =
Partial->getTemplateArgsAsWritten();
TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc,
PartialTemplArgInfo->RAngleLoc);
if (S.SubstTemplateArguments(
PartialTemplArgInfo->arguments(),
MultiLevelTemplateArgumentList(*DeducedArgumentList), InstArgs)) {
unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx;
if (ParamIdx >= Partial->getTemplateParameters()->size())
ParamIdx = Partial->getTemplateParameters()->size() - 1;
Decl *Param = const_cast<NamedDecl *>(
Partial->getTemplateParameters()->getParam(ParamIdx));
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = (*PartialTemplArgInfo)[ArgIdx].getArgument();
return Sema::TDK_SubstitutionFailure;
}
bool ConstraintsNotSatisfied;
SmallVector<TemplateArgument, 4> ConvertedInstArgs;
if (S.CheckTemplateArgumentList(Template, Partial->getLocation(), InstArgs,
false, ConvertedInstArgs,
true,
&ConstraintsNotSatisfied))
return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied :
Sema::TDK_SubstitutionFailure;
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
TemplateArgument InstArg = ConvertedInstArgs.data()[I];
if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) {
Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
Info.FirstArg = TemplateArgs[I];
Info.SecondArg = InstArg;
return Sema::TDK_NonDeducedMismatch;
}
}
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
if (auto Result = CheckDeducedArgumentConstraints(S, Partial, Builder, Info))
return Result;
return Sema::TDK_Success;
}
static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
Sema &S, TemplateDecl *Template, bool PartialOrdering,
const TemplateArgumentList &TemplateArgs,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
TemplateDeductionInfo &Info) {
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::Unevaluated);
Sema::SFINAETrap Trap(S);
Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Template));
SmallVector<TemplateArgument, 4> Builder;
if (auto Result = ConvertDeducedTemplateArguments(
S, Template, PartialOrdering, Deduced, Info, Builder))
return Result;
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
TemplateArgument InstArg = Builder[I];
if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg,
true)) {
Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
Info.FirstArg = TemplateArgs[I];
Info.SecondArg = InstArg;
return Sema::TDK_NonDeducedMismatch;
}
}
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
if (auto Result = CheckDeducedArgumentConstraints(S, Template, Builder,
Info))
return Result;
return Sema::TDK_Success;
}
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
TemplateDeductionInfo &Info) {
if (Partial->isInvalidDecl())
return TDK_Invalid;
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
LocalInstantiationScope InstantiationScope(*this);
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result
= ::DeduceTemplateArguments(*this,
Partial->getTemplateParameters(),
Partial->getTemplateArgs(),
TemplateArgs, Info, Deduced))
return Result;
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
InstantiatingTemplate Inst(*this, Info.getLocation(), Partial, DeducedArgs,
Info);
if (Inst.isInvalid())
return TDK_InstantiationDepth;
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
TemplateDeductionResult Result;
runWithSufficientStackSpace(Info.getLocation(), [&] {
Result = ::FinishTemplateArgumentDeduction(*this, Partial,
false,
TemplateArgs, Deduced, Info);
});
return Result;
}
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
TemplateDeductionInfo &Info) {
if (Partial->isInvalidDecl())
return TDK_Invalid;
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
LocalInstantiationScope InstantiationScope(*this);
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result = ::DeduceTemplateArguments(
*this, Partial->getTemplateParameters(), Partial->getTemplateArgs(),
TemplateArgs, Info, Deduced))
return Result;
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
InstantiatingTemplate Inst(*this, Info.getLocation(), Partial, DeducedArgs,
Info);
if (Inst.isInvalid())
return TDK_InstantiationDepth;
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
TemplateDeductionResult Result;
runWithSufficientStackSpace(Info.getLocation(), [&] {
Result = ::FinishTemplateArgumentDeduction(*this, Partial,
false,
TemplateArgs, Deduced, Info);
});
return Result;
}
static bool isSimpleTemplateIdType(QualType T) {
if (const TemplateSpecializationType *Spec
= T->getAs<TemplateSpecializationType>())
return Spec->getTemplateName().getAsTemplateDecl() != nullptr;
if (T->getAs<InjectedClassNameType>())
return true;
return false;
}
Sema::TemplateDeductionResult
Sema::SubstituteExplicitTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo &ExplicitTemplateArgs,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
SmallVectorImpl<QualType> &ParamTypes,
QualType *FunctionType,
TemplateDeductionInfo &Info) {
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
if (ExplicitTemplateArgs.size() == 0) {
for (auto P : Function->parameters())
ParamTypes.push_back(P->getType());
if (FunctionType)
*FunctionType = Function->getType();
return TDK_Success;
}
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
SmallVector<TemplateArgument, 4> Builder;
SmallVector<TemplateArgument, 4> DeducedArgs;
InstantiatingTemplate Inst(
*this, Info.getLocation(), FunctionTemplate, DeducedArgs,
CodeSynthesisContext::ExplicitTemplateArgumentSubstitution, Info);
if (Inst.isInvalid())
return TDK_InstantiationDepth;
if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(),
ExplicitTemplateArgs, true, Builder, false) ||
Trap.hasErrorOccurred()) {
unsigned Index = Builder.size();
if (Index >= TemplateParams->size())
return TDK_SubstitutionFailure;
Info.Param = makeTemplateParameter(TemplateParams->getParam(Index));
return TDK_InvalidExplicitArguments;
}
TemplateArgumentList *ExplicitArgumentList
= TemplateArgumentList::CreateCopy(Context, Builder);
Info.setExplicitArgs(ExplicitArgumentList);
ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl());
unsigned PartiallySubstitutedPackIndex = -1u;
if (!Builder.empty()) {
const TemplateArgument &Arg = Builder.back();
if (Arg.getKind() == TemplateArgument::Pack) {
auto *Param = TemplateParams->getParam(Builder.size() - 1);
Optional<unsigned> Expansions = getExpandedPackSize(Param);
if (!Expansions || Arg.pack_size() < *Expansions) {
PartiallySubstitutedPackIndex = Builder.size() - 1;
CurrentInstantiationScope->SetPartiallySubstitutedPack(
Param, Arg.pack_begin(), Arg.pack_size());
}
}
}
const FunctionProtoType *Proto
= Function->getType()->getAs<FunctionProtoType>();
assert(Proto && "Function template does not have a prototype?");
LocalInstantiationScope InstScope(*this, true);
ExtParameterInfoBuilder ExtParamInfos;
if (Proto->hasTrailingReturn()) {
if (SubstParmTypes(Function->getLocation(), Function->parameters(),
Proto->getExtParameterInfosOrNull(),
MultiLevelTemplateArgumentList(*ExplicitArgumentList),
ParamTypes, nullptr, ExtParamInfos))
return TDK_SubstitutionFailure;
}
QualType ResultType;
{
Qualifiers ThisTypeQuals;
CXXRecordDecl *ThisContext = nullptr;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
ThisContext = Method->getParent();
ThisTypeQuals = Method->getMethodQualifiers();
}
CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals,
getLangOpts().CPlusPlus11);
ResultType =
SubstType(Proto->getReturnType(),
MultiLevelTemplateArgumentList(*ExplicitArgumentList),
Function->getTypeSpecStartLoc(), Function->getDeclName());
if (ResultType.isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
if (getLangOpts().CUDA)
if (Function->hasAttr<CUDAGlobalAttr>() && !ResultType->isVoidType()) {
Diag(Function->getLocation(), diag::err_kern_type_not_void_return)
<< Function->getType() << Function->getSourceRange();
return TDK_SubstitutionFailure;
}
}
if (!Proto->hasTrailingReturn() &&
SubstParmTypes(Function->getLocation(), Function->parameters(),
Proto->getExtParameterInfosOrNull(),
MultiLevelTemplateArgumentList(*ExplicitArgumentList),
ParamTypes, nullptr, ExtParamInfos))
return TDK_SubstitutionFailure;
if (FunctionType) {
auto EPI = Proto->getExtProtoInfo();
EPI.ExtParameterInfos = ExtParamInfos.getPointerOrNull(ParamTypes.size());
SmallVector<QualType, 4> ExceptionStorage;
if (getLangOpts().CPlusPlus17 &&
SubstExceptionSpec(
Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage,
MultiLevelTemplateArgumentList(*ExplicitArgumentList)))
return TDK_SubstitutionFailure;
*FunctionType = BuildFunctionType(ResultType, ParamTypes,
Function->getLocation(),
Function->getDeclName(),
EPI);
if (FunctionType->isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
}
Deduced.reserve(TemplateParams->size());
for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) {
const TemplateArgument &Arg = ExplicitArgumentList->get(I);
if (I == PartiallySubstitutedPackIndex)
Deduced.push_back(DeducedTemplateArgument());
else
Deduced.push_back(Arg);
}
return TDK_Success;
}
static Sema::TemplateDeductionResult
CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info,
Sema::OriginalCallArg OriginalArg,
QualType DeducedA) {
ASTContext &Context = S.Context;
auto Failed = [&]() -> Sema::TemplateDeductionResult {
Info.FirstArg = TemplateArgument(DeducedA);
Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType);
Info.CallArgIndex = OriginalArg.ArgIdx;
return OriginalArg.DecomposedParam ? Sema::TDK_DeducedMismatchNested
: Sema::TDK_DeducedMismatch;
};
QualType A = OriginalArg.OriginalArgType;
QualType OriginalParamType = OriginalArg.OriginalParamType;
if (Context.hasSameUnqualifiedType(A, DeducedA))
return Sema::TDK_Success;
if (const ReferenceType *DeducedARef = DeducedA->getAs<ReferenceType>())
DeducedA = DeducedARef->getPointeeType();
if (const ReferenceType *ARef = A->getAs<ReferenceType>())
A = ARef->getPointeeType();
if (const ReferenceType *OriginalParamRef
= OriginalParamType->getAs<ReferenceType>()) {
OriginalParamType = OriginalParamRef->getPointeeType();
QualType Tmp;
if (A->isFunctionType() && S.IsFunctionConversion(A, DeducedA, Tmp))
return Sema::TDK_Success;
Qualifiers AQuals = A.getQualifiers();
Qualifiers DeducedAQuals = DeducedA.getQualifiers();
if (S.getLangOpts().ObjCAutoRefCount &&
((DeducedAQuals.getObjCLifetime() == Qualifiers::OCL_Strong &&
AQuals.getObjCLifetime() == Qualifiers::OCL_None) ||
(DeducedAQuals.hasConst() &&
DeducedAQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone))) {
AQuals.setObjCLifetime(DeducedAQuals.getObjCLifetime());
}
if (AQuals == DeducedAQuals) {
} else if (!DeducedAQuals.compatiblyIncludes(AQuals)) {
return Failed();
} else {
A = Context.getQualifiedType(A.getUnqualifiedType(), DeducedAQuals);
}
}
bool ObjCLifetimeConversion = false;
QualType ResultTy;
if ((A->isAnyPointerType() || A->isMemberPointerType()) &&
(S.IsQualificationConversion(A, DeducedA, false,
ObjCLifetimeConversion) ||
S.IsFunctionConversion(A, DeducedA, ResultTy)))
return Sema::TDK_Success;
if (const PointerType *OriginalParamPtr
= OriginalParamType->getAs<PointerType>()) {
if (const PointerType *DeducedAPtr = DeducedA->getAs<PointerType>()) {
if (const PointerType *APtr = A->getAs<PointerType>()) {
if (A->getPointeeType()->isRecordType()) {
OriginalParamType = OriginalParamPtr->getPointeeType();
DeducedA = DeducedAPtr->getPointeeType();
A = APtr->getPointeeType();
}
}
}
}
if (Context.hasSameUnqualifiedType(A, DeducedA))
return Sema::TDK_Success;
if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) &&
S.IsDerivedFrom(Info.getLocation(), A, DeducedA))
return Sema::TDK_Success;
return Failed();
}
static unsigned getPackIndexForParam(Sema &S,
FunctionTemplateDecl *FunctionTemplate,
const MultiLevelTemplateArgumentList &Args,
unsigned ParamIdx) {
unsigned Idx = 0;
for (auto *PD : FunctionTemplate->getTemplatedDecl()->parameters()) {
if (PD->isParameterPack()) {
unsigned NumExpansions =
S.getNumArgumentsInExpansion(PD->getType(), Args).value_or(1);
if (Idx + NumExpansions > ParamIdx)
return ParamIdx - Idx;
Idx += NumExpansions;
} else {
if (Idx == ParamIdx)
return -1; ++Idx;
}
}
llvm_unreachable("parameter index would not be produced from template");
}
Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
FunctionTemplateDecl *FunctionTemplate,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned NumExplicitlySpecified, FunctionDecl *&Specialization,
TemplateDeductionInfo &Info,
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
bool PartialOverloading, llvm::function_ref<bool()> CheckNonDependent) {
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end());
InstantiatingTemplate Inst(
*this, Info.getLocation(), FunctionTemplate, DeducedArgs,
CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
if (Inst.isInvalid())
return TDK_InstantiationDepth;
ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl());
SmallVector<TemplateArgument, 4> Builder;
if (auto Result = ConvertDeducedTemplateArguments(
*this, FunctionTemplate, true, Deduced, Info, Builder,
CurrentInstantiationScope, NumExplicitlySpecified,
PartialOverloading))
return Result;
if (CheckNonDependent())
return TDK_NonDependentConversionFailure;
TemplateArgumentList *DeducedArgumentList
= TemplateArgumentList::CreateCopy(Context, Builder);
Info.reset(DeducedArgumentList);
DeclContext *Owner = FunctionTemplate->getDeclContext();
if (FunctionTemplate->getFriendObjectKind())
Owner = FunctionTemplate->getLexicalDeclContext();
MultiLevelTemplateArgumentList SubstArgs(*DeducedArgumentList);
Specialization = cast_or_null<FunctionDecl>(
SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs));
if (!Specialization || Specialization->isInvalidDecl())
return TDK_SubstitutionFailure;
assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() ==
FunctionTemplate->getCanonicalDecl());
if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList &&
!Trap.hasErrorOccurred())
Info.take();
if (Trap.hasErrorOccurred()) {
Specialization->setInvalidDecl(true);
return TDK_SubstitutionFailure;
}
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 (OriginalCallArgs) {
llvm::SmallDenseMap<std::pair<unsigned, QualType>, QualType> DeducedATypes;
for (unsigned I = 0, N = OriginalCallArgs->size(); I != N; ++I) {
OriginalCallArg OriginalArg = (*OriginalCallArgs)[I];
auto ParamIdx = OriginalArg.ArgIdx;
if (ParamIdx >= Specialization->getNumParams())
continue;
QualType DeducedA;
if (!OriginalArg.DecomposedParam) {
DeducedA = Specialization->getParamDecl(ParamIdx)->getType();
} else {
QualType &CacheEntry =
DeducedATypes[{ParamIdx, OriginalArg.OriginalParamType}];
if (CacheEntry.isNull()) {
ArgumentPackSubstitutionIndexRAII PackIndex(
*this, getPackIndexForParam(*this, FunctionTemplate, SubstArgs,
ParamIdx));
CacheEntry =
SubstType(OriginalArg.OriginalParamType, SubstArgs,
Specialization->getTypeSpecStartLoc(),
Specialization->getDeclName());
}
DeducedA = CacheEntry;
}
if (auto TDK =
CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA))
return TDK;
}
}
if (Info.diag_begin() != Info.diag_end()) {
SuppressedDiagnosticsMap::iterator
Pos = SuppressedDiagnostics.find(Specialization->getCanonicalDecl());
if (Pos == SuppressedDiagnostics.end())
SuppressedDiagnostics[Specialization->getCanonicalDecl()]
.append(Info.diag_begin(), Info.diag_end());
}
return TDK_Success;
}
static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R,
FunctionDecl *Fn) {
if (S.getLangOpts().CPlusPlus14 && Fn->getReturnType()->isUndeducedType() &&
S.DeduceReturnType(Fn, R.Expression->getExprLoc(), false))
return {};
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
if (Method->isInstance()) {
if (!R.HasFormOfMemberPointer)
return {};
return S.Context.getMemberPointerType(Fn->getType(),
S.Context.getTypeDeclType(Method->getParent()).getTypePtr());
}
if (!R.IsAddressOfOperand) return Fn->getType();
return S.Context.getPointerType(Fn->getType());
}
static QualType
ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
Expr *Arg, QualType ParamType,
bool ParamWasReference) {
OverloadExpr::FindResult R = OverloadExpr::find(Arg);
OverloadExpr *Ovl = R.Expression;
unsigned TDF = 0;
if (ParamWasReference)
TDF |= TDF_ParamWithReferenceType;
if (R.IsAddressOfOperand)
TDF |= TDF_IgnoreQualifiers;
if (!ParamType->isFunctionType() &&
!ParamType->isFunctionPointerType() &&
!ParamType->isMemberFunctionPointerType()) {
if (Ovl->hasExplicitTemplateArgs()) {
if (FunctionDecl *ExplicitSpec
= S.ResolveSingleFunctionTemplateSpecialization(Ovl))
return GetTypeOfFunction(S, R, ExplicitSpec);
}
DeclAccessPair DAP;
if (FunctionDecl *Viable =
S.resolveAddressOfSingleOverloadCandidate(Arg, DAP))
return GetTypeOfFunction(S, R, Viable);
return {};
}
TemplateArgumentListInfo ExplicitTemplateArgs;
if (Ovl->hasExplicitTemplateArgs())
Ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs);
QualType Match;
for (UnresolvedSetIterator I = Ovl->decls_begin(),
E = Ovl->decls_end(); I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) {
if (!Ovl->hasExplicitTemplateArgs())
return {};
FunctionDecl *Specialization = nullptr;
TemplateDeductionInfo Info(Ovl->getNameLoc());
if (S.DeduceTemplateArguments(FunTmpl, &ExplicitTemplateArgs,
Specialization, Info))
continue;
D = Specialization;
}
FunctionDecl *Fn = cast<FunctionDecl>(D);
QualType ArgType = GetTypeOfFunction(S, R, Fn);
if (ArgType.isNull()) continue;
if (!ParamWasReference && ParamType->isPointerType() &&
ArgType->isFunctionType())
ArgType = S.Context.getPointerType(ArgType);
SmallVector<DeducedTemplateArgument, 8>
Deduced(TemplateParams->size());
TemplateDeductionInfo Info(Ovl->getNameLoc());
Sema::TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
ArgType, Info, Deduced, TDF);
if (Result) continue;
if (!Match.isNull())
return {};
Match = ArgType;
}
return Match;
}
static bool AdjustFunctionParmAndArgTypesForDeduction(
Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex,
QualType &ParamType, QualType &ArgType, Expr *Arg, unsigned &TDF) {
if (ParamType.hasQualifiers())
ParamType = ParamType.getUnqualifiedType();
const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>();
if (ParamRefType)
ParamType = ParamRefType->getPointeeType();
if (ArgType == S.Context.OverloadTy) {
ArgType = ResolveOverloadForDeduction(S, TemplateParams,
Arg, ParamType,
ParamRefType != nullptr);
if (ArgType.isNull())
return true;
}
if (ParamRefType) {
if (ArgType->isIncompleteArrayType())
ArgType = S.getCompletedType(Arg);
if (isForwardingReference(QualType(ParamRefType, 0), FirstInnerIndex) &&
Arg->isLValue()) {
if (S.getLangOpts().OpenCL && !ArgType.hasAddressSpace())
ArgType = S.Context.getAddrSpaceQualType(
ArgType, S.Context.getDefaultOpenCLPointeeAddrSpace());
ArgType = S.Context.getLValueReferenceType(ArgType);
}
} else {
if (ArgType->isArrayType())
ArgType = S.Context.getArrayDecayedType(ArgType);
else if (ArgType->isFunctionType())
ArgType = S.Context.getPointerType(ArgType);
else {
ArgType = ArgType.getUnqualifiedType();
}
}
TDF = TDF_SkipNonDependent;
if (ParamRefType)
TDF |= TDF_ParamWithReferenceType;
if (ArgType->isPointerType() || ArgType->isMemberPointerType() ||
ArgType->isObjCObjectPointerType())
TDF |= TDF_IgnoreQualifiers;
if (isSimpleTemplateIdType(ParamType) ||
(isa<PointerType>(ParamType) &&
isSimpleTemplateIdType(
ParamType->castAs<PointerType>()->getPointeeType())))
TDF |= TDF_DerivedClass;
return false;
}
static bool
hasDeducibleTemplateParameters(Sema &S, FunctionTemplateDecl *FunctionTemplate,
QualType T);
static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex,
QualType ParamType, Expr *Arg, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
bool DecomposedParam, unsigned ArgIdx, unsigned TDF);
static Sema::TemplateDeductionResult DeduceFromInitializerList(
Sema &S, TemplateParameterList *TemplateParams, QualType AdjustedParamType,
InitListExpr *ILE, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, unsigned ArgIdx,
unsigned TDF) {
if (!ILE->getNumInits())
return Sema::TDK_Success;
QualType ElTy;
auto *ArrTy = S.Context.getAsArrayType(AdjustedParamType);
if (ArrTy)
ElTy = ArrTy->getElementType();
else if (!S.isStdInitializerList(AdjustedParamType, &ElTy)) {
return Sema::TDK_Success;
}
for (Expr *E : ILE->inits())
if (isa<DesignatedInitExpr>(E))
return Sema::TDK_Success;
if (ElTy->isDependentType()) {
for (Expr *E : ILE->inits()) {
if (auto Result = DeduceTemplateArgumentsFromCallArgument(
S, TemplateParams, 0, ElTy, E, Info, Deduced, OriginalCallArgs, true,
ArgIdx, TDF))
return Result;
}
}
if (auto *DependentArrTy = dyn_cast_or_null<DependentSizedArrayType>(ArrTy)) {
if (const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, DependentArrTy->getSizeExpr())) {
QualType T = S.Context.getSizeType();
llvm::APInt Size(S.Context.getIntWidth(T), ILE->getNumInits());
if (auto Result = DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, llvm::APSInt(Size), T,
true, Info, Deduced))
return Result;
}
}
return Sema::TDK_Success;
}
static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex,
QualType ParamType, Expr *Arg, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
bool DecomposedParam, unsigned ArgIdx, unsigned TDF) {
QualType ArgType = Arg->getType();
QualType OrigParamType = ParamType;
if (AdjustFunctionParmAndArgTypesForDeduction(
S, TemplateParams, FirstInnerIndex, ParamType, ArgType, Arg, TDF))
return Sema::TDK_Success;
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg))
return DeduceFromInitializerList(S, TemplateParams, ParamType, ILE, Info,
Deduced, OriginalCallArgs, ArgIdx, TDF);
OriginalCallArgs.push_back(
Sema::OriginalCallArg(OrigParamType, DecomposedParam, ArgIdx, ArgType));
return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
ArgType, Info, Deduced, TDF);
}
Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
FunctionDecl *&Specialization, TemplateDeductionInfo &Info,
bool PartialOverloading,
llvm::function_ref<bool(ArrayRef<QualType>)> CheckNonDependent) {
if (FunctionTemplate->isInvalidDecl())
return TDK_Invalid;
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
unsigned NumParams = Function->getNumParams();
unsigned FirstInnerIndex = getFirstInnerIndex(FunctionTemplate);
if (Args.size() < Function->getMinRequiredArguments() && !PartialOverloading)
return TDK_TooFewArguments;
else if (TooManyArguments(NumParams, Args.size(), PartialOverloading)) {
const auto *Proto = Function->getType()->castAs<FunctionProtoType>();
if (Proto->isTemplateVariadic())
;
else if (!Proto->isVariadic())
return TDK_TooManyArguments;
}
LocalInstantiationScope InstScope(*this);
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
SmallVector<DeducedTemplateArgument, 4> Deduced;
SmallVector<QualType, 8> ParamTypes;
unsigned NumExplicitlySpecified = 0;
if (ExplicitTemplateArgs) {
TemplateDeductionResult Result;
runWithSufficientStackSpace(Info.getLocation(), [&] {
Result = SubstituteExplicitTemplateArguments(
FunctionTemplate, *ExplicitTemplateArgs, Deduced, ParamTypes, nullptr,
Info);
});
if (Result)
return Result;
NumExplicitlySpecified = Deduced.size();
} else {
for (unsigned I = 0; I != NumParams; ++I)
ParamTypes.push_back(Function->getParamDecl(I)->getType());
}
SmallVector<OriginalCallArg, 8> OriginalCallArgs;
auto DeduceCallArgument = [&](QualType ParamType, unsigned ArgIdx) {
if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType))
return Sema::TDK_Success;
return DeduceTemplateArgumentsFromCallArgument(
*this, TemplateParams, FirstInnerIndex, ParamType, Args[ArgIdx], Info, Deduced,
OriginalCallArgs, false, ArgIdx, 0);
};
Deduced.resize(TemplateParams->size());
SmallVector<QualType, 8> ParamTypesForArgChecking;
for (unsigned ParamIdx = 0, NumParamTypes = ParamTypes.size(), ArgIdx = 0;
ParamIdx != NumParamTypes; ++ParamIdx) {
QualType ParamType = ParamTypes[ParamIdx];
const PackExpansionType *ParamExpansion =
dyn_cast<PackExpansionType>(ParamType);
if (!ParamExpansion) {
if (ArgIdx >= Args.size())
break;
ParamTypesForArgChecking.push_back(ParamType);
if (auto Result = DeduceCallArgument(ParamType, ArgIdx++))
return Result;
continue;
}
QualType ParamPattern = ParamExpansion->getPattern();
PackDeductionScope PackScope(*this, TemplateParams, Deduced, Info,
ParamPattern);
if (ParamIdx + 1 == NumParamTypes || PackScope.hasFixedArity()) {
for (; ArgIdx < Args.size() && PackScope.hasNextElement();
PackScope.nextPackElement(), ++ArgIdx) {
ParamTypesForArgChecking.push_back(ParamPattern);
if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx))
return Result;
}
} else {
Optional<unsigned> NumExpansions = ParamExpansion->getNumExpansions();
if (NumExpansions && !PackScope.isPartiallyExpanded()) {
for (unsigned I = 0; I != *NumExpansions && ArgIdx < Args.size();
++I, ++ArgIdx) {
ParamTypesForArgChecking.push_back(ParamPattern);
PackScope.nextPackElement();
}
}
}
if (auto Result = PackScope.finish())
return Result;
}
DeclContext *CallingCtx = CurContext;
TemplateDeductionResult Result;
runWithSufficientStackSpace(Info.getLocation(), [&] {
Result = FinishTemplateArgumentDeduction(
FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info,
&OriginalCallArgs, PartialOverloading, [&, CallingCtx]() {
ContextRAII SavedContext(*this, CallingCtx);
return CheckNonDependent(ParamTypesForArgChecking);
});
});
return Result;
}
QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,
QualType FunctionType,
bool AdjustExceptionSpec) {
if (ArgFunctionType.isNull())
return ArgFunctionType;
const auto *FunctionTypeP = FunctionType->castAs<FunctionProtoType>();
const auto *ArgFunctionTypeP = ArgFunctionType->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = ArgFunctionTypeP->getExtProtoInfo();
bool Rebuild = false;
CallingConv CC = FunctionTypeP->getCallConv();
if (EPI.ExtInfo.getCC() != CC) {
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC);
Rebuild = true;
}
bool NoReturn = FunctionTypeP->getNoReturnAttr();
if (EPI.ExtInfo.getNoReturn() != NoReturn) {
EPI.ExtInfo = EPI.ExtInfo.withNoReturn(NoReturn);
Rebuild = true;
}
if (AdjustExceptionSpec && (FunctionTypeP->hasExceptionSpec() ||
ArgFunctionTypeP->hasExceptionSpec())) {
EPI.ExceptionSpec = FunctionTypeP->getExtProtoInfo().ExceptionSpec;
Rebuild = true;
}
if (!Rebuild)
return ArgFunctionType;
return Context.getFunctionType(ArgFunctionTypeP->getReturnType(),
ArgFunctionTypeP->getParamTypes(), EPI);
}
Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType,
FunctionDecl *&Specialization, TemplateDeductionInfo &Info,
bool IsAddressOfFunction) {
if (FunctionTemplate->isInvalidDecl())
return TDK_Invalid;
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
QualType FunctionType = Function->getType();
LocalInstantiationScope InstScope(*this);
SmallVector<DeducedTemplateArgument, 4> Deduced;
unsigned NumExplicitlySpecified = 0;
SmallVector<QualType, 4> ParamTypes;
if (ExplicitTemplateArgs) {
TemplateDeductionResult Result;
runWithSufficientStackSpace(Info.getLocation(), [&] {
Result = SubstituteExplicitTemplateArguments(
FunctionTemplate, *ExplicitTemplateArgs, Deduced, ParamTypes,
&FunctionType, Info);
});
if (Result)
return Result;
NumExplicitlySpecified = Deduced.size();
}
if (!IsAddressOfFunction)
ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType,
false);
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
Deduced.resize(TemplateParams->size());
bool HasDeducedReturnType = false;
if (getLangOpts().CPlusPlus14 && IsAddressOfFunction &&
Function->getReturnType()->getContainedAutoType()) {
FunctionType = SubstAutoTypeDependent(FunctionType);
HasDeducedReturnType = true;
}
if (!ArgFunctionType.isNull() && !FunctionType.isNull()) {
unsigned TDF =
TDF_TopLevelParameterTypeList | TDF_AllowCompatibleFunctionType;
if (TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
FunctionType, ArgFunctionType,
Info, Deduced, TDF))
return Result;
}
TemplateDeductionResult Result;
runWithSufficientStackSpace(Info.getLocation(), [&] {
Result = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
NumExplicitlySpecified,
Specialization, Info);
});
if (Result)
return Result;
if (HasDeducedReturnType &&
Specialization->getReturnType()->isUndeducedType() &&
DeduceReturnType(Specialization, Info.getLocation(), false))
return TDK_MiscellaneousDeductionFailure;
auto *SpecializationFPT =
Specialization->getType()->castAs<FunctionProtoType>();
if (getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) &&
!ResolveExceptionSpec(Info.getLocation(), SpecializationFPT))
return TDK_MiscellaneousDeductionFailure;
QualType SpecializationType = Specialization->getType();
if (!IsAddressOfFunction)
ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, SpecializationType,
true);
if (!ArgFunctionType.isNull()) {
if (IsAddressOfFunction &&
!isSameOrCompatibleFunctionType(
Context.getCanonicalType(SpecializationType),
Context.getCanonicalType(ArgFunctionType)))
return TDK_MiscellaneousDeductionFailure;
if (!IsAddressOfFunction &&
!Context.hasSameType(SpecializationType, ArgFunctionType))
return TDK_MiscellaneousDeductionFailure;
}
return TDK_Success;
}
Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
QualType ToType,
CXXConversionDecl *&Specialization,
TemplateDeductionInfo &Info) {
if (ConversionTemplate->isInvalidDecl())
return TDK_Invalid;
CXXConversionDecl *ConversionGeneric
= cast<CXXConversionDecl>(ConversionTemplate->getTemplatedDecl());
QualType FromType = ConversionGeneric->getConversionType();
QualType P = Context.getCanonicalType(FromType);
QualType A = Context.getCanonicalType(ToType);
if (const ReferenceType *PRef = P->getAs<ReferenceType>())
P = PRef->getPointeeType();
if (const ReferenceType *ARef = A->getAs<ReferenceType>()) {
A = ARef->getPointeeType();
if (!FromType->getAs<ReferenceType>()) {
A = A.getUnqualifiedType();
P = P.getUnqualifiedType();
}
} else {
assert(!A->isReferenceType() && "Reference types were handled above");
if (P->isArrayType())
P = Context.getArrayDecayedType(P);
else if (P->isFunctionType())
P = Context.getPointerType(P);
else
P = P.getUnqualifiedType();
A = A.getUnqualifiedType();
}
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
TemplateParameterList *TemplateParams
= ConversionTemplate->getTemplateParameters();
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(TemplateParams->size());
unsigned TDF = 0;
if (ToType->isReferenceType())
TDF |= TDF_ArgWithReferenceType;
if ((P->isPointerType() && A->isPointerType()) ||
(P->isMemberPointerType() && A->isMemberPointerType()))
TDF |= TDF_IgnoreQualifiers;
if (TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
P, A, Info, Deduced, TDF))
return Result;
LocalInstantiationScope InstScope(*this);
FunctionDecl *ConversionSpecialized = nullptr;
TemplateDeductionResult Result;
runWithSufficientStackSpace(Info.getLocation(), [&] {
Result = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0,
ConversionSpecialized, Info);
});
Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized);
return Result;
}
Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs,
FunctionDecl *&Specialization, TemplateDeductionInfo &Info,
bool IsAddressOfFunction) {
return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
QualType(), Specialization, Info,
IsAddressOfFunction);
}
namespace {
struct DependentAuto { bool IsPack; };
class SubstituteDeducedTypeTransform :
public TreeTransform<SubstituteDeducedTypeTransform> {
QualType Replacement;
bool ReplacementIsPack;
bool UseTypeSugar;
public:
SubstituteDeducedTypeTransform(Sema &SemaRef, DependentAuto DA)
: TreeTransform<SubstituteDeducedTypeTransform>(SemaRef),
ReplacementIsPack(DA.IsPack), UseTypeSugar(true) {}
SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement,
bool UseTypeSugar = true)
: TreeTransform<SubstituteDeducedTypeTransform>(SemaRef),
Replacement(Replacement), ReplacementIsPack(false),
UseTypeSugar(UseTypeSugar) {}
QualType TransformDesugared(TypeLocBuilder &TLB, DeducedTypeLoc TL) {
assert(isa<TemplateTypeParmType>(Replacement) &&
"unexpected unsugared replacement kind");
QualType Result = Replacement;
TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) {
if (!UseTypeSugar)
return TransformDesugared(TLB, TL);
QualType Result = SemaRef.Context.getAutoType(
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(),
ReplacementIsPack, TL.getTypePtr()->getTypeConstraintConcept(),
TL.getTypePtr()->getTypeConstraintArguments());
auto NewTL = TLB.push<AutoTypeLoc>(Result);
NewTL.copy(TL);
return Result;
}
QualType TransformDeducedTemplateSpecializationType(
TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) {
if (!UseTypeSugar)
return TransformDesugared(TLB, TL);
QualType Result = SemaRef.Context.getDeducedTemplateSpecializationType(
TL.getTypePtr()->getTemplateName(),
Replacement, Replacement.isNull());
auto NewTL = TLB.push<DeducedTemplateSpecializationTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
ExprResult TransformLambdaExpr(LambdaExpr *E) {
return E;
}
QualType Apply(TypeLoc TL) {
TypeLocBuilder TLB;
TLB.reserve(TL.getFullDataSize());
return TransformType(TLB, TL);
}
};
}
Sema::DeduceAutoResult
Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
Optional<unsigned> DependentDeductionDepth,
bool IgnoreConstraints) {
return DeduceAutoType(Type->getTypeLoc(), Init, Result,
DependentDeductionDepth, IgnoreConstraints);
}
static bool diagnoseAutoDeductionFailure(Sema &S,
Sema::TemplateDeductionResult TDK,
TemplateDeductionInfo &Info,
ArrayRef<SourceRange> Ranges) {
switch (TDK) {
case Sema::TDK_Inconsistent: {
auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction);
D << Info.FirstArg << Info.SecondArg;
for (auto R : Ranges)
D << R;
return true;
}
default:
return false;
}
}
static Sema::DeduceAutoResult
CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
AutoTypeLoc TypeLoc, QualType Deduced) {
ConstraintSatisfaction Satisfaction;
ConceptDecl *Concept = Type.getTypeConstraintConcept();
TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(),
TypeLoc.getRAngleLoc());
TemplateArgs.addArgument(
TemplateArgumentLoc(TemplateArgument(Deduced),
S.Context.getTrivialTypeSourceInfo(
Deduced, TypeLoc.getNameLoc())));
for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I)
TemplateArgs.addArgument(TypeLoc.getArgLoc(I));
llvm::SmallVector<TemplateArgument, 4> Converted;
if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
false, Converted))
return Sema::DAR_FailedAlreadyDiagnosed;
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
Converted, TypeLoc.getLocalSourceRange(),
Satisfaction))
return Sema::DAR_FailedAlreadyDiagnosed;
if (!Satisfaction.IsSatisfied) {
std::string Buf;
llvm::raw_string_ostream OS(Buf);
OS << "'" << Concept->getName();
if (TypeLoc.hasExplicitTemplateArgs()) {
printTemplateArgumentList(
OS, Type.getTypeConstraintArguments(), S.getPrintingPolicy(),
Type.getTypeConstraintConcept()->getTemplateParameters());
}
OS << "'";
OS.flush();
S.Diag(TypeLoc.getConceptNameLoc(),
diag::err_placeholder_constraints_not_satisfied)
<< Deduced << Buf << TypeLoc.getLocalSourceRange();
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
return Sema::DAR_FailedAlreadyDiagnosed;
}
return Sema::DAR_Succeeded;
}
Sema::DeduceAutoResult
Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
Optional<unsigned> DependentDeductionDepth,
bool IgnoreConstraints) {
if (Init->containsErrors())
return DAR_FailedAlreadyDiagnosed;
if (Init->getType()->isNonOverloadPlaceholderType()) {
ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
if (NonPlaceholder.isInvalid())
return DAR_FailedAlreadyDiagnosed;
Init = NonPlaceholder.get();
}
DependentAuto DependentResult = {
(bool)Type.getAs<PackExpansionTypeLoc>()};
if (!DependentDeductionDepth &&
(Type.getType()->isDependentType() || Init->isTypeDependent() ||
Init->containsUnexpandedParameterPack())) {
Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
unsigned Depth = DependentDeductionDepth.value_or(0);
if (const AutoType *AT = Type.getType()->getAs<AutoType>()) {
if (AT->isDecltypeAuto()) {
if (isa<InitListExpr>(Init)) {
Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list);
return DAR_FailedAlreadyDiagnosed;
}
ExprResult ER = CheckPlaceholderExpr(Init);
if (ER.isInvalid())
return DAR_FailedAlreadyDiagnosed;
QualType Deduced = getDecltypeForExpr(ER.get());
assert(!Deduced.isNull());
if (AT->isConstrained() && !IgnoreConstraints) {
auto ConstraintsResult =
CheckDeducedPlaceholderConstraints(*this, *AT,
Type.getContainedAutoTypeLoc(),
Deduced);
if (ConstraintsResult != DAR_Succeeded)
return ConstraintsResult;
}
Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
return DAR_Succeeded;
} else if (!getLangOpts().CPlusPlus) {
if (isa<InitListExpr>(Init)) {
Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c);
return DAR_FailedAlreadyDiagnosed;
}
}
}
SourceLocation Loc = Init->getExprLoc();
LocalInstantiationScope InstScope(*this);
TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create(
Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false,
false);
QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
NamedDecl *TemplParamPtr = TemplParam;
FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
QualType FuncParam =
SubstituteDeducedTypeTransform(*this, TemplArg, true)
.Apply(Type);
assert(!FuncParam.isNull() &&
"substituting template parameter for 'auto' failed");
SmallVector<DeducedTemplateArgument, 1> Deduced;
Deduced.resize(1);
TemplateDeductionInfo Info(Loc, Depth);
auto DeductionFailed = [&](TemplateDeductionResult TDK,
ArrayRef<SourceRange> Ranges) -> DeduceAutoResult {
if (Init->isTypeDependent()) {
Result =
SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
}
if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges))
return DAR_FailedAlreadyDiagnosed;
return DAR_Failed;
};
SmallVector<OriginalCallArg, 4> OriginalCallArgs;
InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
if (InitList) {
if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
return DAR_Failed;
for (Expr *E : InitList->inits())
if (isa<DesignatedInitExpr>(E))
return DAR_Failed;
SourceRange DeducedFromInitRange;
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
Expr *Init = InitList->getInit(i);
if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
*this, TemplateParamsSt.get(), 0, TemplArg, Init,
Info, Deduced, OriginalCallArgs, true,
0, 0))
return DeductionFailed(TDK, {DeducedFromInitRange,
Init->getSourceRange()});
if (DeducedFromInitRange.isInvalid() &&
Deduced[0].getKind() != TemplateArgument::Null)
DeducedFromInitRange = Init->getSourceRange();
}
} else {
if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
Diag(Loc, diag::err_auto_bitfield);
return DAR_FailedAlreadyDiagnosed;
}
if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
*this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
OriginalCallArgs, false, 0, 0))
return DeductionFailed(TDK, {});
}
if (Deduced[0].getKind() != TemplateArgument::Type)
return DeductionFailed(TDK_Incomplete, {});
QualType DeducedType = Deduced[0].getAsType();
if (InitList) {
DeducedType = BuildStdInitializerList(DeducedType, Loc);
if (DeducedType.isNull())
return DAR_FailedAlreadyDiagnosed;
}
QualType MaybeAuto = Type.getType().getNonReferenceType();
while (MaybeAuto->isPointerType())
MaybeAuto = MaybeAuto->getPointeeType();
if (const auto *AT = MaybeAuto->getAs<AutoType>()) {
if (AT->isConstrained() && !IgnoreConstraints) {
auto ConstraintsResult = CheckDeducedPlaceholderConstraints(
*this, *AT, Type.getContainedAutoTypeLoc(), DeducedType);
if (ConstraintsResult != DAR_Succeeded)
return ConstraintsResult;
}
}
Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
QualType DeducedA = InitList ? Deduced[0].getAsType() : Result;
for (const OriginalCallArg &OriginalArg : OriginalCallArgs) {
assert((bool)InitList == OriginalArg.DecomposedParam &&
"decomposed non-init-list in auto deduction?");
if (auto TDK =
CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) {
Result = QualType();
return DeductionFailed(TDK, {});
}
}
return DAR_Succeeded;
}
QualType Sema::SubstAutoType(QualType TypeWithAuto,
QualType TypeToReplaceAuto) {
assert(TypeToReplaceAuto != Context.DependentTy);
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
.TransformType(TypeWithAuto);
}
TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
QualType TypeToReplaceAuto) {
assert(TypeToReplaceAuto != Context.DependentTy);
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto)
.TransformType(TypeWithAuto);
}
QualType Sema::SubstAutoTypeDependent(QualType TypeWithAuto) {
return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
.TransformType(TypeWithAuto);
}
TypeSourceInfo *
Sema::SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto) {
return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
.TransformType(TypeWithAuto);
}
QualType Sema::ReplaceAutoType(QualType TypeWithAuto,
QualType TypeToReplaceAuto) {
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto,
false)
.TransformType(TypeWithAuto);
}
TypeSourceInfo *Sema::ReplaceAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
QualType TypeToReplaceAuto) {
return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto,
false)
.TransformType(TypeWithAuto);
}
void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) {
if (isa<InitListExpr>(Init))
Diag(VDecl->getLocation(),
VDecl->isInitCapture()
? diag::err_init_capture_deduction_failure_from_init_list
: diag::err_auto_var_deduction_failure_from_init_list)
<< VDecl->getDeclName() << VDecl->getType() << Init->getSourceRange();
else
Diag(VDecl->getLocation(),
VDecl->isInitCapture() ? diag::err_init_capture_deduction_failure
: diag::err_auto_var_deduction_failure)
<< VDecl->getDeclName() << VDecl->getType() << Init->getType()
<< Init->getSourceRange();
}
bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose) {
assert(FD->getReturnType()->isUndeducedType());
if (isLambdaConversionOperator(FD)) {
CXXRecordDecl *Lambda = cast<CXXMethodDecl>(FD)->getParent();
FunctionDecl *CallOp = Lambda->getLambdaCallOperator();
if (auto *Args = FD->getTemplateSpecializationArgs()) {
CallOp = InstantiateFunctionDeclaration(
CallOp->getDescribedFunctionTemplate(), Args, Loc);
if (!CallOp || CallOp->isInvalidDecl())
return true;
if (CallOp->getReturnType()->isUndeducedType()) {
runWithSufficientStackSpace(Loc, [&] {
InstantiateFunctionDefinition(Loc, CallOp);
});
}
}
if (CallOp->isInvalidDecl())
return true;
assert(!CallOp->getReturnType()->isUndeducedType() &&
"failed to deduce lambda return type");
CallingConv RetTyCC = FD->getReturnType()
->getPointeeType()
->castAs<FunctionType>()
->getCallConv();
QualType RetType = getLambdaConversionFunctionResultType(
CallOp->getType()->castAs<FunctionProtoType>(), RetTyCC);
if (FD->getReturnType()->getAs<PointerType>())
RetType = Context.getPointerType(RetType);
else {
assert(FD->getReturnType()->getAs<BlockPointerType>());
RetType = Context.getBlockPointerType(RetType);
}
Context.adjustDeducedFunctionResultType(FD, RetType);
return false;
}
if (FD->getTemplateInstantiationPattern()) {
runWithSufficientStackSpace(Loc, [&] {
InstantiateFunctionDefinition(Loc, FD);
});
}
bool StillUndeduced = FD->getReturnType()->isUndeducedType();
if (StillUndeduced && Diagnose && !FD->isInvalidDecl()) {
Diag(Loc, diag::err_auto_fn_used_before_defined) << FD;
Diag(FD->getLocation(), diag::note_callee_decl) << FD;
}
return StillUndeduced;
}
static void
AddImplicitObjectParameterType(ASTContext &Context,
CXXMethodDecl *Method,
SmallVectorImpl<QualType> &ArgTypes) {
QualType ArgTy = Context.getTypeDeclType(Method->getParent());
ArgTy = Context.getQualifiedType(ArgTy, Method->getMethodQualifiers());
if (Method->getRefQualifier() == RQ_RValue)
ArgTy = Context.getRValueReferenceType(ArgTy);
else
ArgTy = Context.getLValueReferenceType(ArgTy);
ArgTypes.push_back(ArgTy);
}
static bool isAtLeastAsSpecializedAs(Sema &S,
SourceLocation Loc,
FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC,
unsigned NumCallArguments1,
bool Reversed) {
assert(!Reversed || TPOC == TPOC_Call);
FunctionDecl *FD1 = FT1->getTemplatedDecl();
FunctionDecl *FD2 = FT2->getTemplatedDecl();
const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>();
const FunctionProtoType *Proto2 = FD2->getType()->getAs<FunctionProtoType>();
assert(Proto1 && Proto2 && "Function templates must have prototypes");
TemplateParameterList *TemplateParams = FT2->getTemplateParameters();
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(TemplateParams->size());
TemplateDeductionInfo Info(Loc);
SmallVector<QualType, 4> Args2;
switch (TPOC) {
case TPOC_Call: {
CXXMethodDecl *Method1 = dyn_cast<CXXMethodDecl>(FD1);
CXXMethodDecl *Method2 = dyn_cast<CXXMethodDecl>(FD2);
SmallVector<QualType, 4> Args1;
unsigned NumComparedArguments = NumCallArguments1;
if (!Method2 && Method1 && !Method1->isStatic()) {
AddImplicitObjectParameterType(S.Context, Method1, Args1);
++NumComparedArguments;
} else if (!Method1 && Method2 && !Method2->isStatic()) {
AddImplicitObjectParameterType(S.Context, Method2, Args2);
} else if (Method1 && Method2 && Reversed) {
AddImplicitObjectParameterType(S.Context, Method1, Args1);
AddImplicitObjectParameterType(S.Context, Method2, Args2);
++NumComparedArguments;
}
Args1.insert(Args1.end(), Proto1->param_type_begin(),
Proto1->param_type_end());
Args2.insert(Args2.end(), Proto2->param_type_begin(),
Proto2->param_type_end());
if (Args1.size() > NumComparedArguments)
Args1.resize(NumComparedArguments);
if (Args2.size() > NumComparedArguments)
Args2.resize(NumComparedArguments);
if (Reversed)
std::reverse(Args2.begin(), Args2.end());
if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
Args1.data(), Args1.size(), Info, Deduced,
TDF_None, true))
return false;
break;
}
case TPOC_Conversion:
if (DeduceTemplateArgumentsByTypeMatch(
S, TemplateParams, Proto2->getReturnType(), Proto1->getReturnType(),
Info, Deduced, TDF_None,
true))
return false;
break;
case TPOC_Other:
if (DeduceTemplateArgumentsByTypeMatch(S, TemplateParams,
FD2->getType(), FD1->getType(),
Info, Deduced, TDF_None,
true))
return false;
break;
}
unsigned ArgIdx = 0, NumArgs = Deduced.size();
for (; ArgIdx != NumArgs; ++ArgIdx)
if (Deduced[ArgIdx].isNull())
break;
if (ArgIdx == NumArgs) {
return true;
}
llvm::SmallBitVector UsedParameters(TemplateParams->size());
switch (TPOC) {
case TPOC_Call:
for (unsigned I = 0, N = Args2.size(); I != N; ++I)
::MarkUsedTemplateParameters(S.Context, Args2[I], false,
TemplateParams->getDepth(),
UsedParameters);
break;
case TPOC_Conversion:
::MarkUsedTemplateParameters(S.Context, Proto2->getReturnType(), false,
TemplateParams->getDepth(), UsedParameters);
break;
case TPOC_Other:
::MarkUsedTemplateParameters(S.Context, FD2->getType(), false,
TemplateParams->getDepth(),
UsedParameters);
break;
}
for (; ArgIdx != NumArgs; ++ArgIdx)
if (Deduced[ArgIdx].isNull() && UsedParameters[ArgIdx])
return false;
return true;
}
static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) {
FunctionDecl *Function = FunTmpl->getTemplatedDecl();
unsigned NumParams = Function->getNumParams();
if (NumParams == 0)
return false;
ParmVarDecl *Last = Function->getParamDecl(NumParams - 1);
if (!Last->isParameterPack())
return false;
while (--NumParams > 0) {
if (Function->getParamDecl(NumParams - 1)->isParameterPack())
return false;
}
return true;
}
FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,
TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1,
unsigned NumCallArguments2, bool Reversed,
bool AllowOrderingByConstraints) {
auto JudgeByConstraints = [&]() -> FunctionTemplateDecl * {
if (!AllowOrderingByConstraints)
return nullptr;
llvm::SmallVector<const Expr *, 3> AC1, AC2;
FT1->getAssociatedConstraints(AC1);
FT2->getAssociatedConstraints(AC2);
bool AtLeastAsConstrained1, AtLeastAsConstrained2;
if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1))
return nullptr;
if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2))
return nullptr;
if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
return nullptr;
return AtLeastAsConstrained1 ? FT1 : FT2;
};
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
NumCallArguments1, Reversed);
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
NumCallArguments2, Reversed);
if (Better1 != Better2) return Better1 ? FT1 : FT2;
if (!Better1 && !Better2) return JudgeByConstraints();
bool Variadic1 = isVariadicFunctionTemplate(FT1);
bool Variadic2 = isVariadicFunctionTemplate(FT2);
if (Variadic1 != Variadic2)
return Variadic1? FT2 : FT1;
return JudgeByConstraints();
}
static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
if (T1 == T2)
return true;
if (!T1 || !T2)
return false;
return T1->getCanonicalDecl() == T2->getCanonicalDecl();
}
UnresolvedSetIterator Sema::getMostSpecialized(
UnresolvedSetIterator SpecBegin, UnresolvedSetIterator SpecEnd,
TemplateSpecCandidateSet &FailedCandidates,
SourceLocation Loc, const PartialDiagnostic &NoneDiag,
const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &CandidateDiag,
bool Complain, QualType TargetType) {
if (SpecBegin == SpecEnd) {
if (Complain) {
Diag(Loc, NoneDiag);
FailedCandidates.NoteCandidates(*this, Loc);
}
return SpecEnd;
}
if (SpecBegin + 1 == SpecEnd)
return SpecBegin;
UnresolvedSetIterator Best = SpecBegin;
FunctionTemplateDecl *BestTemplate
= cast<FunctionDecl>(*Best)->getPrimaryTemplate();
assert(BestTemplate && "Not a function template specialization?");
for (UnresolvedSetIterator I = SpecBegin + 1; I != SpecEnd; ++I) {
FunctionTemplateDecl *Challenger
= cast<FunctionDecl>(*I)->getPrimaryTemplate();
assert(Challenger && "Not a function template specialization?");
if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
Loc, TPOC_Other, 0, 0),
Challenger)) {
Best = I;
BestTemplate = Challenger;
}
}
bool Ambiguous = false;
for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) {
FunctionTemplateDecl *Challenger
= cast<FunctionDecl>(*I)->getPrimaryTemplate();
if (I != Best &&
!isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
Loc, TPOC_Other, 0, 0),
BestTemplate)) {
Ambiguous = true;
break;
}
}
if (!Ambiguous) {
return Best;
}
if (Complain) {
Diag(Loc, AmbigDiag);
for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) {
PartialDiagnostic PD = CandidateDiag;
const auto *FD = cast<FunctionDecl>(*I);
PD << FD << getTemplateArgumentBindingsText(
FD->getPrimaryTemplate()->getTemplateParameters(),
*FD->getTemplateSpecializationArgs());
if (!TargetType.isNull())
HandleFunctionTypeMismatch(PD, FD->getType(), TargetType);
Diag((*I)->getLocation(), PD);
}
}
return SpecEnd;
}
template<typename TemplateLikeDecl>
static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
TemplateLikeDecl *P2,
TemplateDeductionInfo &Info) {
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(P2->getTemplateParameters()->size());
if (DeduceTemplateArgumentsByTypeMatch(S, P2->getTemplateParameters(),
T2, T1, Info, Deduced, TDF_None,
true))
return false;
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
Deduced.end());
Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2, DeducedArgs,
Info);
if (Inst.isInvalid())
return false;
auto *TST1 = T1->castAs<TemplateSpecializationType>();
bool AtLeastAsSpecialized;
S.runWithSufficientStackSpace(Info.getLocation(), [&] {
AtLeastAsSpecialized = !FinishTemplateArgumentDeduction(
S, P2, true,
TemplateArgumentList(TemplateArgumentList::OnStack,
TST1->template_arguments()),
Deduced, Info);
});
return AtLeastAsSpecialized;
}
ClassTemplatePartialSpecializationDecl *
Sema::getMoreSpecializedPartialSpecialization(
ClassTemplatePartialSpecializationDecl *PS1,
ClassTemplatePartialSpecializationDecl *PS2,
SourceLocation Loc) {
QualType PT1 = PS1->getInjectedSpecializationType();
QualType PT2 = PS2->getInjectedSpecializationType();
TemplateDeductionInfo Info(Loc);
bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
if (!Better1 && !Better2)
return nullptr;
if (Better1 && Better2) {
llvm::SmallVector<const Expr *, 3> AC1, AC2;
PS1->getAssociatedConstraints(AC1);
PS2->getAssociatedConstraints(AC2);
bool AtLeastAsConstrained1, AtLeastAsConstrained2;
if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1))
return nullptr;
if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2))
return nullptr;
if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
return nullptr;
return AtLeastAsConstrained1 ? PS1 : PS2;
}
return Better1 ? PS1 : PS2;
}
bool Sema::isMoreSpecializedThanPrimary(
ClassTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
ClassTemplateDecl *Primary = Spec->getSpecializedTemplate();
QualType PrimaryT = Primary->getInjectedClassNameSpecialization();
QualType PartialT = Spec->getInjectedSpecializationType();
if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
return false;
if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info))
return true;
Info.clearSFINAEDiagnostic();
llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC;
Primary->getAssociatedConstraints(PrimaryAC);
Spec->getAssociatedConstraints(SpecAC);
bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec;
if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC,
AtLeastAsConstrainedSpec))
return false;
if (!AtLeastAsConstrainedSpec)
return false;
if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC,
AtLeastAsConstrainedPrimary))
return false;
return !AtLeastAsConstrainedPrimary;
}
VarTemplatePartialSpecializationDecl *
Sema::getMoreSpecializedPartialSpecialization(
VarTemplatePartialSpecializationDecl *PS1,
VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc) {
assert(PS1->getSpecializedTemplate() == PS2->getSpecializedTemplate() &&
"the partial specializations being compared should specialize"
" the same template.");
TemplateName Name(PS1->getSpecializedTemplate());
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
QualType PT1 = Context.getTemplateSpecializationType(
CanonTemplate, PS1->getTemplateArgs().asArray());
QualType PT2 = Context.getTemplateSpecializationType(
CanonTemplate, PS2->getTemplateArgs().asArray());
TemplateDeductionInfo Info(Loc);
bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
if (!Better1 && !Better2)
return nullptr;
if (Better1 && Better2) {
llvm::SmallVector<const Expr *, 3> AC1, AC2;
PS1->getAssociatedConstraints(AC1);
PS2->getAssociatedConstraints(AC2);
bool AtLeastAsConstrained1, AtLeastAsConstrained2;
if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1))
return nullptr;
if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2))
return nullptr;
if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
return nullptr;
return AtLeastAsConstrained1 ? PS1 : PS2;
}
return Better1 ? PS1 : PS2;
}
bool Sema::isMoreSpecializedThanPrimary(
VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
TemplateDecl *Primary = Spec->getSpecializedTemplate();
SmallVector<TemplateArgument, 8> PrimaryArgs;
Context.getInjectedTemplateArgs(Primary->getTemplateParameters(),
PrimaryArgs);
TemplateName CanonTemplate =
Context.getCanonicalTemplateName(TemplateName(Primary));
QualType PrimaryT = Context.getTemplateSpecializationType(
CanonTemplate, PrimaryArgs);
QualType PartialT = Context.getTemplateSpecializationType(
CanonTemplate, Spec->getTemplateArgs().asArray());
if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
return false;
if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info))
return true;
Info.clearSFINAEDiagnostic();
llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC;
Primary->getAssociatedConstraints(PrimaryAC);
Spec->getAssociatedConstraints(SpecAC);
bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec;
if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC,
AtLeastAsConstrainedSpec))
return false;
if (!AtLeastAsConstrainedSpec)
return false;
if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC,
AtLeastAsConstrainedPrimary))
return false;
return !AtLeastAsConstrainedPrimary;
}
bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
TemplateParameterList *P, TemplateDecl *AArg, SourceLocation Loc) {
TemplateName X = Context.getCanonicalTemplateName(TemplateName(AArg));
TemplateParameterList *A = AArg->getTemplateParameters();
SmallVector<TemplateArgument, 8> AArgs;
Context.getInjectedTemplateArgs(A, AArgs);
SmallVector<TemplateArgument, 4> PArgs;
{
SFINAETrap Trap(*this);
Context.getInjectedTemplateArgs(P, PArgs);
TemplateArgumentListInfo PArgList(P->getLAngleLoc(),
P->getRAngleLoc());
for (unsigned I = 0, N = P->size(); I != N; ++I) {
TemplateArgument Arg = PArgs[I];
if (Arg.getKind() == TemplateArgument::Pack) {
assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion());
Arg = *Arg.pack_begin();
}
PArgList.addArgument(getTrivialTemplateArgumentLoc(
Arg, QualType(), P->getParam(I)->getLocation()));
}
PArgs.clear();
if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, PArgs) ||
Trap.hasErrorOccurred())
return false;
}
QualType AType = Context.getTemplateSpecializationType(X, AArgs);
QualType PType = Context.getTemplateSpecializationType(X, PArgs);
TemplateDeductionInfo Info(Loc, A->getDepth());
return isAtLeastAsSpecializedAs(*this, PType, AType, AArg, Info);
}
namespace {
struct MarkUsedTemplateParameterVisitor :
RecursiveASTVisitor<MarkUsedTemplateParameterVisitor> {
llvm::SmallBitVector &Used;
unsigned Depth;
MarkUsedTemplateParameterVisitor(llvm::SmallBitVector &Used,
unsigned Depth)
: Used(Used), Depth(Depth) { }
bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
if (T->getDepth() == Depth)
Used[T->getIndex()] = true;
return true;
}
bool TraverseTemplateName(TemplateName Template) {
if (auto *TTP =
dyn_cast<TemplateTemplateParmDecl>(Template.getAsTemplateDecl()))
if (TTP->getDepth() == Depth)
Used[TTP->getIndex()] = true;
RecursiveASTVisitor<MarkUsedTemplateParameterVisitor>::
TraverseTemplateName(Template);
return true;
}
bool VisitDeclRefExpr(DeclRefExpr *E) {
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl()))
if (NTTP->getDepth() == Depth)
Used[NTTP->getIndex()] = true;
return true;
}
};
}
static void
MarkUsedTemplateParameters(ASTContext &Ctx,
const Expr *E,
bool OnlyDeduced,
unsigned Depth,
llvm::SmallBitVector &Used) {
if (!OnlyDeduced) {
MarkUsedTemplateParameterVisitor(Used, Depth)
.TraverseStmt(const_cast<Expr *>(E));
return;
}
if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E))
E = Expansion->getPattern();
const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(E, Depth);
if (!NTTP)
return;
if (NTTP->getDepth() == Depth)
Used[NTTP->getIndex()] = true;
if (Ctx.getLangOpts().CPlusPlus17)
MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used);
}
static void
MarkUsedTemplateParameters(ASTContext &Ctx,
NestedNameSpecifier *NNS,
bool OnlyDeduced,
unsigned Depth,
llvm::SmallBitVector &Used) {
if (!NNS)
return;
MarkUsedTemplateParameters(Ctx, NNS->getPrefix(), OnlyDeduced, Depth,
Used);
MarkUsedTemplateParameters(Ctx, QualType(NNS->getAsType(), 0),
OnlyDeduced, Depth, Used);
}
static void
MarkUsedTemplateParameters(ASTContext &Ctx,
TemplateName Name,
bool OnlyDeduced,
unsigned Depth,
llvm::SmallBitVector &Used) {
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(Template)) {
if (TTP->getDepth() == Depth)
Used[TTP->getIndex()] = true;
}
return;
}
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName())
MarkUsedTemplateParameters(Ctx, QTN->getQualifier(), OnlyDeduced,
Depth, Used);
if (DependentTemplateName *DTN = Name.getAsDependentTemplateName())
MarkUsedTemplateParameters(Ctx, DTN->getQualifier(), OnlyDeduced,
Depth, Used);
}
static void
MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced,
unsigned Depth,
llvm::SmallBitVector &Used) {
if (T.isNull())
return;
if (!T->isDependentType())
return;
T = Ctx.getCanonicalType(T);
switch (T->getTypeClass()) {
case Type::Pointer:
MarkUsedTemplateParameters(Ctx,
cast<PointerType>(T)->getPointeeType(),
OnlyDeduced,
Depth,
Used);
break;
case Type::BlockPointer:
MarkUsedTemplateParameters(Ctx,
cast<BlockPointerType>(T)->getPointeeType(),
OnlyDeduced,
Depth,
Used);
break;
case Type::LValueReference:
case Type::RValueReference:
MarkUsedTemplateParameters(Ctx,
cast<ReferenceType>(T)->getPointeeType(),
OnlyDeduced,
Depth,
Used);
break;
case Type::MemberPointer: {
const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr());
MarkUsedTemplateParameters(Ctx, MemPtr->getPointeeType(), OnlyDeduced,
Depth, Used);
MarkUsedTemplateParameters(Ctx, QualType(MemPtr->getClass(), 0),
OnlyDeduced, Depth, Used);
break;
}
case Type::DependentSizedArray:
MarkUsedTemplateParameters(Ctx,
cast<DependentSizedArrayType>(T)->getSizeExpr(),
OnlyDeduced, Depth, Used);
LLVM_FALLTHROUGH;
case Type::ConstantArray:
case Type::IncompleteArray:
MarkUsedTemplateParameters(Ctx,
cast<ArrayType>(T)->getElementType(),
OnlyDeduced, Depth, Used);
break;
case Type::Vector:
case Type::ExtVector:
MarkUsedTemplateParameters(Ctx,
cast<VectorType>(T)->getElementType(),
OnlyDeduced, Depth, Used);
break;
case Type::DependentVector: {
const auto *VecType = cast<DependentVectorType>(T);
MarkUsedTemplateParameters(Ctx, VecType->getElementType(), OnlyDeduced,
Depth, Used);
MarkUsedTemplateParameters(Ctx, VecType->getSizeExpr(), OnlyDeduced, Depth,
Used);
break;
}
case Type::DependentSizedExtVector: {
const DependentSizedExtVectorType *VecType
= cast<DependentSizedExtVectorType>(T);
MarkUsedTemplateParameters(Ctx, VecType->getElementType(), OnlyDeduced,
Depth, Used);
MarkUsedTemplateParameters(Ctx, VecType->getSizeExpr(), OnlyDeduced,
Depth, Used);
break;
}
case Type::DependentAddressSpace: {
const DependentAddressSpaceType *DependentASType =
cast<DependentAddressSpaceType>(T);
MarkUsedTemplateParameters(Ctx, DependentASType->getPointeeType(),
OnlyDeduced, Depth, Used);
MarkUsedTemplateParameters(Ctx,
DependentASType->getAddrSpaceExpr(),
OnlyDeduced, Depth, Used);
break;
}
case Type::ConstantMatrix: {
const ConstantMatrixType *MatType = cast<ConstantMatrixType>(T);
MarkUsedTemplateParameters(Ctx, MatType->getElementType(), OnlyDeduced,
Depth, Used);
break;
}
case Type::DependentSizedMatrix: {
const DependentSizedMatrixType *MatType = cast<DependentSizedMatrixType>(T);
MarkUsedTemplateParameters(Ctx, MatType->getElementType(), OnlyDeduced,
Depth, Used);
MarkUsedTemplateParameters(Ctx, MatType->getRowExpr(), OnlyDeduced, Depth,
Used);
MarkUsedTemplateParameters(Ctx, MatType->getColumnExpr(), OnlyDeduced,
Depth, Used);
break;
}
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
MarkUsedTemplateParameters(Ctx, Proto->getReturnType(), OnlyDeduced, Depth,
Used);
for (unsigned I = 0, N = Proto->getNumParams(); I != N; ++I) {
if (!OnlyDeduced || I + 1 == N ||
!Proto->getParamType(I)->getAs<PackExpansionType>()) {
MarkUsedTemplateParameters(Ctx, Proto->getParamType(I), OnlyDeduced,
Depth, Used);
} else {
}
}
if (auto *E = Proto->getNoexceptExpr())
MarkUsedTemplateParameters(Ctx, E, OnlyDeduced, Depth, Used);
break;
}
case Type::TemplateTypeParm: {
const TemplateTypeParmType *TTP = cast<TemplateTypeParmType>(T);
if (TTP->getDepth() == Depth)
Used[TTP->getIndex()] = true;
break;
}
case Type::SubstTemplateTypeParmPack: {
const SubstTemplateTypeParmPackType *Subst
= cast<SubstTemplateTypeParmPackType>(T);
MarkUsedTemplateParameters(Ctx,
QualType(Subst->getReplacedParameter(), 0),
OnlyDeduced, Depth, Used);
MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(),
OnlyDeduced, Depth, Used);
break;
}
case Type::InjectedClassName:
T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType();
LLVM_FALLTHROUGH;
case Type::TemplateSpecialization: {
const TemplateSpecializationType *Spec
= cast<TemplateSpecializationType>(T);
MarkUsedTemplateParameters(Ctx, Spec->getTemplateName(), OnlyDeduced,
Depth, Used);
if (OnlyDeduced &&
hasPackExpansionBeforeEnd(Spec->template_arguments()))
break;
for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth,
Used);
break;
}
case Type::Complex:
if (!OnlyDeduced)
MarkUsedTemplateParameters(Ctx,
cast<ComplexType>(T)->getElementType(),
OnlyDeduced, Depth, Used);
break;
case Type::Atomic:
if (!OnlyDeduced)
MarkUsedTemplateParameters(Ctx,
cast<AtomicType>(T)->getValueType(),
OnlyDeduced, Depth, Used);
break;
case Type::DependentName:
if (!OnlyDeduced)
MarkUsedTemplateParameters(Ctx,
cast<DependentNameType>(T)->getQualifier(),
OnlyDeduced, Depth, Used);
break;
case Type::DependentTemplateSpecialization: {
if (OnlyDeduced)
break;
const DependentTemplateSpecializationType *Spec
= cast<DependentTemplateSpecializationType>(T);
MarkUsedTemplateParameters(Ctx, Spec->getQualifier(),
OnlyDeduced, Depth, Used);
for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth,
Used);
break;
}
case Type::TypeOf:
if (!OnlyDeduced)
MarkUsedTemplateParameters(Ctx,
cast<TypeOfType>(T)->getUnderlyingType(),
OnlyDeduced, Depth, Used);
break;
case Type::TypeOfExpr:
if (!OnlyDeduced)
MarkUsedTemplateParameters(Ctx,
cast<TypeOfExprType>(T)->getUnderlyingExpr(),
OnlyDeduced, Depth, Used);
break;
case Type::Decltype:
if (!OnlyDeduced)
MarkUsedTemplateParameters(Ctx,
cast<DecltypeType>(T)->getUnderlyingExpr(),
OnlyDeduced, Depth, Used);
break;
case Type::UnaryTransform:
if (!OnlyDeduced)
MarkUsedTemplateParameters(Ctx,
cast<UnaryTransformType>(T)->getUnderlyingType(),
OnlyDeduced, Depth, Used);
break;
case Type::PackExpansion:
MarkUsedTemplateParameters(Ctx,
cast<PackExpansionType>(T)->getPattern(),
OnlyDeduced, Depth, Used);
break;
case Type::Auto:
case Type::DeducedTemplateSpecialization:
MarkUsedTemplateParameters(Ctx,
cast<DeducedType>(T)->getDeducedType(),
OnlyDeduced, Depth, Used);
break;
case Type::DependentBitInt:
MarkUsedTemplateParameters(Ctx,
cast<DependentBitIntType>(T)->getNumBitsExpr(),
OnlyDeduced, Depth, Used);
break;
case Type::Builtin:
case Type::VariableArray:
case Type::FunctionNoProto:
case Type::Record:
case Type::Enum:
case Type::ObjCInterface:
case Type::ObjCObject:
case Type::ObjCObjectPointer:
case Type::UnresolvedUsing:
case Type::Pipe:
case Type::BitInt:
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#include "clang/AST/TypeNodes.inc"
break;
}
}
static void
MarkUsedTemplateParameters(ASTContext &Ctx,
const TemplateArgument &TemplateArg,
bool OnlyDeduced,
unsigned Depth,
llvm::SmallBitVector &Used) {
switch (TemplateArg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
break;
case TemplateArgument::NullPtr:
MarkUsedTemplateParameters(Ctx, TemplateArg.getNullPtrType(), OnlyDeduced,
Depth, Used);
break;
case TemplateArgument::Type:
MarkUsedTemplateParameters(Ctx, TemplateArg.getAsType(), OnlyDeduced,
Depth, Used);
break;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
MarkUsedTemplateParameters(Ctx,
TemplateArg.getAsTemplateOrTemplatePattern(),
OnlyDeduced, Depth, Used);
break;
case TemplateArgument::Expression:
MarkUsedTemplateParameters(Ctx, TemplateArg.getAsExpr(), OnlyDeduced,
Depth, Used);
break;
case TemplateArgument::Pack:
for (const auto &P : TemplateArg.pack_elements())
MarkUsedTemplateParameters(Ctx, P, OnlyDeduced, Depth, Used);
break;
}
}
void
Sema::MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced,
unsigned Depth,
llvm::SmallBitVector &Used) {
::MarkUsedTemplateParameters(Context, E, OnlyDeduced, Depth, Used);
}
void
Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced, unsigned Depth,
llvm::SmallBitVector &Used) {
if (OnlyDeduced &&
hasPackExpansionBeforeEnd(TemplateArgs.asArray()))
return;
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
::MarkUsedTemplateParameters(Context, TemplateArgs[I], OnlyDeduced,
Depth, Used);
}
void Sema::MarkDeducedTemplateParameters(
ASTContext &Ctx, const FunctionTemplateDecl *FunctionTemplate,
llvm::SmallBitVector &Deduced) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
Deduced.clear();
Deduced.resize(TemplateParams->size());
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I)
::MarkUsedTemplateParameters(Ctx, Function->getParamDecl(I)->getType(),
true, TemplateParams->getDepth(), Deduced);
}
bool hasDeducibleTemplateParameters(Sema &S,
FunctionTemplateDecl *FunctionTemplate,
QualType T) {
if (!T->isDependentType())
return false;
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
llvm::SmallBitVector Deduced(TemplateParams->size());
::MarkUsedTemplateParameters(S.Context, T, true, TemplateParams->getDepth(),
Deduced);
return Deduced.any();
}