forked from OSchip/llvm-project
Give a better error if auto deduction fails due to inconsistent element types in a braced initializer list.
llvm-svn: 312085
This commit is contained in:
parent
d5ba54549d
commit
b1efc9b410
|
@ -1984,6 +1984,9 @@ def err_auto_var_deduction_failure_from_init_list : Error<
|
|||
"cannot deduce actual type for variable %0 with type %1 from initializer list">;
|
||||
def err_auto_new_deduction_failure : Error<
|
||||
"new expression for type %0 has incompatible constructor argument of type %1">;
|
||||
def err_auto_inconsistent_deduction : Error<
|
||||
"deduced conflicting types %diff{($ vs $) |}0,1"
|
||||
"for initializer list element type">;
|
||||
def err_auto_different_deductions : Error<
|
||||
"%select{'auto'|'decltype(auto)'|'__auto_type'|template arguments}0 "
|
||||
"deduced as %1 in declaration of %2 and "
|
||||
|
|
|
@ -2907,17 +2907,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 +2950,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 +2970,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 +2991,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 +3012,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 +3174,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4231,6 +4236,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 +4348,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 +4370,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 +4391,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 +4419,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, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -136,9 +136,15 @@ void auto_deduction() {
|
|||
auto l3 {1};
|
||||
static_assert(same_type<decltype(l), std::initializer_list<int>>::value, "");
|
||||
static_assert(same_type<decltype(l3), int>::value, "");
|
||||
auto bl = {1, 2.0}; // expected-error {{cannot deduce}}
|
||||
auto bl = {1, 2.0}; // expected-error {{deduced conflicting types ('int' vs 'double') for initializer list element type}}
|
||||
|
||||
void f1(int), f1(float), f2(int), f3(float);
|
||||
auto fil = {f1, f2};
|
||||
auto ffl = {f1, f3};
|
||||
auto fl = {f1, f2, f3}; // expected-error {{deduced conflicting types ('void (*)(int)' vs 'void (*)(float)') for initializer list element type}}
|
||||
|
||||
for (int i : {1, 2, 3, 4}) {}
|
||||
for (int j : {1.0, 2.0, 3.0f, 4.0}) {} // expected-error {{deduced conflicting types ('double' vs 'float') for initializer list element type}}
|
||||
}
|
||||
|
||||
void dangle() {
|
||||
|
|
Loading…
Reference in New Issue