summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplateDeduction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaTemplateDeduction.cpp')
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp182
1 files changed, 150 insertions, 32 deletions
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 983b1ea795dda..564692b030200 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -344,7 +344,7 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
}
Deduced[NTTP->getIndex()] = Result;
- if (!S.getLangOpts().CPlusPlus1z)
+ if (!S.getLangOpts().CPlusPlus17)
return Sema::TDK_Success;
if (NTTP->isExpandedParameterPack())
@@ -354,8 +354,9 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
// expanded NTTP should be a pack expansion type?
return Sema::TDK_Success;
- // Get the type of the parameter for deduction.
- QualType ParamType = NTTP->getType();
+ // Get the type of the parameter for deduction. If it's a (dependent) array
+ // or function type, we will not have decayed it yet, so do that now.
+ QualType ParamType = S.Context.getAdjustedParameterType(NTTP->getType());
if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType))
ParamType = Expansion->getPattern();
@@ -1843,6 +1844,59 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
return Sema::TDK_NonDeducedMismatch;
}
+ // (clang extension)
+ //
+ // T __attribute__(((address_space(N))))
+ case Type::DependentAddressSpace: {
+ const DependentAddressSpaceType *AddressSpaceParam =
+ cast<DependentAddressSpaceType>(Param);
+
+ if (const DependentAddressSpaceType *AddressSpaceArg =
+ dyn_cast<DependentAddressSpaceType>(Arg)) {
+ // Perform deduction on the pointer type.
+ if (Sema::TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, AddressSpaceParam->getPointeeType(),
+ AddressSpaceArg->getPointeeType(), Info, Deduced, TDF))
+ return Result;
+
+ // Perform deduction on the address space, if we can.
+ NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
+ Info, AddressSpaceParam->getAddrSpaceExpr());
+ if (!NTTP)
+ return Sema::TDK_Success;
+
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, AddressSpaceArg->getAddrSpaceExpr(), Info,
+ Deduced);
+ }
+
+ if (isTargetAddressSpace(Arg.getAddressSpace())) {
+ llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy),
+ false);
+ ArgAddressSpace = toTargetAddressSpace(Arg.getAddressSpace());
+
+ // Perform deduction on the pointer types.
+ if (Sema::TemplateDeductionResult Result =
+ DeduceTemplateArgumentsByTypeMatch(
+ S, TemplateParams, AddressSpaceParam->getPointeeType(),
+ S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF))
+ return Result;
+
+ // Perform deduction on the address space, if we can.
+ NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(
+ Info, AddressSpaceParam->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::TypeOfExpr:
case Type::TypeOf:
case Type::DependentName:
@@ -2695,6 +2749,17 @@ static bool isSimpleTemplateIdType(QualType T) {
= T->getAs<TemplateSpecializationType>())
return Spec->getTemplateName().getAsTemplateDecl() != nullptr;
+ // C++17 [temp.local]p2:
+ // the injected-class-name [...] is equivalent to the template-name followed
+ // by the template-arguments of the class template specialization or partial
+ // specialization enclosed in <>
+ // ... which means it's equivalent to a simple-template-id.
+ //
+ // This only arises during class template argument deduction for a copy
+ // deduction candidate, where it permits slicing.
+ if (T->getAs<InjectedClassNameType>())
+ return true;
+
return false;
}
@@ -2869,7 +2934,7 @@ Sema::SubstituteExplicitTemplateArguments(
// so substitution into the type must also substitute into the exception
// specification.
SmallVector<QualType, 4> ExceptionStorage;
- if (getLangOpts().CPlusPlus1z &&
+ if (getLangOpts().CPlusPlus17 &&
SubstExceptionSpec(
Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage,
MultiLevelTemplateArgumentList(*ExplicitArgumentList)))
@@ -2907,17 +2972,26 @@ Sema::SubstituteExplicitTemplateArguments(
/// \brief Check whether the deduced argument type for a call to a function
/// template matches the actual argument type per C++ [temp.deduct.call]p4.
-static bool
-CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
+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;
// Check for type equality (top-level cv-qualifiers are ignored).
if (Context.hasSameUnqualifiedType(A, DeducedA))
- return false;
+ return Sema::TDK_Success;
// Strip off references on the argument types; they aren't needed for
// the following checks.
@@ -2941,7 +3015,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
// the deduced A can be F.
QualType Tmp;
if (A->isFunctionType() && S.IsFunctionConversion(A, DeducedA, Tmp))
- return false;
+ return Sema::TDK_Success;
Qualifiers AQuals = A.getQualifiers();
Qualifiers DeducedAQuals = DeducedA.getQualifiers();
@@ -2961,7 +3035,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
if (AQuals == DeducedAQuals) {
// Qualifiers match; there's nothing to do.
} else if (!DeducedAQuals.compatiblyIncludes(AQuals)) {
- return true;
+ return Failed();
} else {
// Qualifiers are compatible, so have the argument type adopt the
// deduced argument type's qualifiers as if we had performed the
@@ -2982,7 +3056,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
(S.IsQualificationConversion(A, DeducedA, false,
ObjCLifetimeConversion) ||
S.IsFunctionConversion(A, DeducedA, ResultTy)))
- return false;
+ return Sema::TDK_Success;
// - If P is a class and P has the form simple-template-id, then the
// transformed A can be a derived class of the deduced A. [...]
@@ -3003,13 +3077,13 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
}
if (Context.hasSameUnqualifiedType(A, DeducedA))
- return false;
+ return Sema::TDK_Success;
if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) &&
S.IsDerivedFrom(SourceLocation(), A, DeducedA))
- return false;
+ return Sema::TDK_Success;
- return true;
+ return Failed();
}
/// Find the pack index for a particular parameter index in an instantiation of
@@ -3165,13 +3239,9 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
DeducedA = CacheEntry;
}
- if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
- Info.FirstArg = TemplateArgument(DeducedA);
- Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType);
- Info.CallArgIndex = OriginalArg.ArgIdx;
- return OriginalArg.DecomposedParam ? TDK_DeducedMismatchNested
- : TDK_DeducedMismatch;
- }
+ if (auto TDK =
+ CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA))
+ return TDK;
}
}
@@ -3838,7 +3908,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// so we can check that the exception specification matches.
auto *SpecializationFPT =
Specialization->getType()->castAs<FunctionProtoType>();
- if (getLangOpts().CPlusPlus1z &&
+ if (getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) &&
!ResolveExceptionSpec(Info.getLocation(), SpecializationFPT))
return TDK_MiscellaneousDeductionFailure;
@@ -4231,6 +4301,31 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
DependentDeductionDepth);
}
+/// Attempt to produce an informative diagostic explaining why auto deduction
+/// failed.
+/// \return \c true if diagnosed, \c false if not.
+static bool diagnoseAutoDeductionFailure(Sema &S,
+ Sema::TemplateDeductionResult TDK,
+ TemplateDeductionInfo &Info,
+ ArrayRef<SourceRange> Ranges) {
+ switch (TDK) {
+ case Sema::TDK_Inconsistent: {
+ // Inconsistent deduction means we were deducing from an initializer list.
+ auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction);
+ D << Info.FirstArg << Info.SecondArg;
+ for (auto R : Ranges)
+ D << R;
+ return true;
+ }
+
+ // FIXME: Are there other cases for which a custom diagnostic is more useful
+ // than the basic "types don't match" diagnostic?
+
+ default:
+ return false;
+ }
+}
+
/// \brief Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
///
/// Note that this is done even if the initializer is dependent. (This is
@@ -4318,12 +4413,15 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
// If deduction failed, don't diagnose if the initializer is dependent; it
// might acquire a matching type in the instantiation.
- auto DeductionFailed = [&]() -> DeduceAutoResult {
+ auto DeductionFailed = [&](TemplateDeductionResult TDK,
+ ArrayRef<SourceRange> Ranges) -> DeduceAutoResult {
if (Init->isTypeDependent()) {
Result = SubstituteDeducedTypeTransform(*this, QualType()).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;
};
@@ -4337,12 +4435,20 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
return DAR_Failed;
+ SourceRange DeducedFromInitRange;
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
- if (DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParamsSt.get(), 0, TemplArg, InitList->getInit(i),
+ Expr *Init = InitList->getInit(i);
+
+ if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
+ *this, TemplateParamsSt.get(), 0, TemplArg, Init,
Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
/*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed();
+ return DeductionFailed(TDK, {DeducedFromInitRange,
+ Init->getSourceRange()});
+
+ if (DeducedFromInitRange.isInvalid() &&
+ Deduced[0].getKind() != TemplateArgument::Null)
+ DeducedFromInitRange = Init->getSourceRange();
}
} else {
if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
@@ -4350,15 +4456,15 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
}
- if (DeduceTemplateArgumentsFromCallArgument(
+ if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
*this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed();
+ return DeductionFailed(TDK, {});
}
// Could be null if somehow 'auto' appears in a non-deduced context.
if (Deduced[0].getKind() != TemplateArgument::Type)
- return DeductionFailed();
+ return DeductionFailed(TDK_Incomplete, {});
QualType DeducedType = Deduced[0].getAsType();
@@ -4378,9 +4484,10 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
for (const OriginalCallArg &OriginalArg : OriginalCallArgs) {
assert((bool)InitList == OriginalArg.DecomposedParam &&
"decomposed non-init-list in auto deduction?");
- if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
+ if (auto TDK =
+ CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) {
Result = QualType();
- return DeductionFailed();
+ return DeductionFailed(TDK, {});
}
}
@@ -5045,9 +5152,9 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
if (NTTP->getDepth() == Depth)
Used[NTTP->getIndex()] = true;
- // In C++1z mode, additional arguments may be deduced from the type of a
+ // In C++17 mode, additional arguments may be deduced from the type of a
// non-type argument.
- if (Ctx.getLangOpts().CPlusPlus1z)
+ if (Ctx.getLangOpts().CPlusPlus17)
MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used);
}
@@ -5174,6 +5281,17 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
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::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
MarkUsedTemplateParameters(Ctx, Proto->getReturnType(), OnlyDeduced, Depth,