Add missing "original call argument has same type as deduced parameter type"

check for deductions from elements of a braced-init-list.

llvm-svn: 291190
This commit is contained in:
Richard Smith 2017-01-05 23:02:44 +00:00
parent 1594e0629d
commit c92d206ce4
5 changed files with 125 additions and 37 deletions

View File

@ -3377,8 +3377,10 @@ def note_addrof_ovl_candidate_disabled_by_enable_if_attr : Note<
"candidate function made ineligible by enable_if">;
def note_ovl_candidate_deduced_mismatch : Note<
"candidate template ignored: deduced type "
"%diff{$ of %ordinal0 parameter does not match adjusted type $ of argument"
"|of %ordinal0 parameter does not match adjusted type of argument}1,2%3">;
"%diff{$ of %select{|element of }4%ordinal0 parameter does not match "
"adjusted type $ of %select{|element of }4argument"
"|of %select{|element of }4%ordinal0 parameter does not match "
"adjusted type of %select{|element of }4argument}1,2%3">;
def note_ovl_candidate_non_deduced_mismatch : Note<
"candidate template ignored: could not match %diff{$ against $|types}0,1">;
// This note is needed because the above note would sometimes print two

View File

@ -6564,6 +6564,10 @@ public:
/// \brief After substituting deduced template arguments, a dependent
/// parameter type did not match the corresponding argument.
TDK_DeducedMismatch,
/// \brief After substituting deduced template arguments, an element of
/// a dependent parameter type did not match the corresponding element
/// of the corresponding argument (when deducing from an initializer list).
TDK_DeducedMismatchNested,
/// \brief A non-depnedent component of the parameter did not match the
/// corresponding component of the argument.
TDK_NonDeducedMismatch,
@ -6602,13 +6606,14 @@ public:
/// brief A function argument from which we performed template argument
// deduction for a call.
struct OriginalCallArg {
OriginalCallArg(QualType OriginalParamType,
unsigned ArgIdx,
QualType OriginalArgType)
: OriginalParamType(OriginalParamType), ArgIdx(ArgIdx),
OriginalArgType(OriginalArgType) { }
OriginalCallArg(QualType OriginalParamType, bool DecomposedParam,
unsigned ArgIdx, QualType OriginalArgType)
: OriginalParamType(OriginalParamType),
DecomposedParam(DecomposedParam), ArgIdx(ArgIdx),
OriginalArgType(OriginalArgType) {}
QualType OriginalParamType;
bool DecomposedParam;
unsigned ArgIdx;
QualType OriginalArgType;
};

View File

@ -604,7 +604,8 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
Result.Data = Info.Param.getOpaqueValue();
break;
case Sema::TDK_DeducedMismatch: {
case Sema::TDK_DeducedMismatch:
case Sema::TDK_DeducedMismatchNested: {
// FIXME: Should allocate from normal heap so that we can free this later.
auto *Saved = new (Context) DFIDeducedMismatchArgs;
Saved->FirstArg = Info.FirstArg;
@ -664,6 +665,7 @@ void DeductionFailureInfo::Destroy() {
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
case Sema::TDK_DeducedMismatch:
case Sema::TDK_DeducedMismatchNested:
case Sema::TDK_NonDeducedMismatch:
// FIXME: Destroy the data?
Data = nullptr;
@ -699,6 +701,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() {
case Sema::TDK_TooFewArguments:
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_DeducedMismatch:
case Sema::TDK_DeducedMismatchNested:
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_CUDATargetMismatch:
return TemplateParameter();
@ -735,6 +738,7 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
return nullptr;
case Sema::TDK_DeducedMismatch:
case Sema::TDK_DeducedMismatchNested:
return static_cast<DFIDeducedMismatchArgs*>(Data)->TemplateArgs;
case Sema::TDK_SubstitutionFailure:
@ -764,6 +768,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
case Sema::TDK_DeducedMismatch:
case Sema::TDK_DeducedMismatchNested:
case Sema::TDK_NonDeducedMismatch:
return &static_cast<DFIArguments*>(Data)->FirstArg;
@ -791,6 +796,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
case Sema::TDK_DeducedMismatch:
case Sema::TDK_DeducedMismatchNested:
case Sema::TDK_NonDeducedMismatch:
return &static_cast<DFIArguments*>(Data)->SecondArg;
@ -803,11 +809,14 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
}
llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
if (static_cast<Sema::TemplateDeductionResult>(Result) ==
Sema::TDK_DeducedMismatch)
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_DeducedMismatch:
case Sema::TDK_DeducedMismatchNested:
return static_cast<DFIDeducedMismatchArgs*>(Data)->CallArgIndex;
return llvm::None;
default:
return llvm::None;
}
}
void OverloadCandidateSet::destroyCandidates() {
@ -9682,7 +9691,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
return;
}
case Sema::TDK_DeducedMismatch: {
case Sema::TDK_DeducedMismatch:
case Sema::TDK_DeducedMismatchNested: {
// Format the template argument list into the argument string.
SmallString<128> TemplateArgString;
if (TemplateArgumentList *Args =
@ -9695,7 +9705,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
S.Diag(Templated->getLocation(), diag::note_ovl_candidate_deduced_mismatch)
<< (*DeductionFailure.getCallArgIndex() + 1)
<< *DeductionFailure.getFirstArg() << *DeductionFailure.getSecondArg()
<< TemplateArgString;
<< TemplateArgString
<< (DeductionFailure.Result == Sema::TDK_DeducedMismatchNested);
break;
}
@ -10012,6 +10023,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_DeducedMismatch:
case Sema::TDK_DeducedMismatchNested:
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_MiscellaneousDeductionFailure:
case Sema::TDK_CUDATargetMismatch:

View File

@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/Template.h"
@ -2856,6 +2857,36 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
return true;
}
/// Find the pack index for a particular parameter index in an instantiation of
/// a function template with specific arguments.
///
/// \return The pack index for whichever pack produced this parameter, or -1
/// if this was not produced by a parameter. Intended to be used as the
/// ArgumentPackSubstitutionIndex for further substitutions.
// FIXME: We should track this in OriginalCallArgs so we don't need to
// reconstruct it here.
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).getValueOr(1);
if (Idx + NumExpansions > ParamIdx)
return ParamIdx - Idx;
Idx += NumExpansions;
} else {
if (Idx == ParamIdx)
return -1; // Not a pack expansion
++Idx;
}
}
llvm_unreachable("parameter index would not be produced from template");
}
/// \brief Finish template argument deduction for a function template,
/// checking the deduced template arguments for completeness and forming
/// the function template specialization.
@ -2906,9 +2937,9 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
DeclContext *Owner = FunctionTemplate->getDeclContext();
if (FunctionTemplate->getFriendObjectKind())
Owner = FunctionTemplate->getLexicalDeclContext();
MultiLevelTemplateArgumentList SubstArgs(*DeducedArgumentList);
Specialization = cast_or_null<FunctionDecl>(
SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner,
MultiLevelTemplateArgumentList(*DeducedArgumentList)));
SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs));
if (!Specialization || Specialization->isInvalidDecl())
return TDK_SubstitutionFailure;
@ -2934,19 +2965,46 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// In general, the deduction process attempts to find template argument
// values that will make the deduced A identical to A (after the type A
// is transformed as described above). [...]
llvm::SmallDenseMap<std::pair<unsigned, QualType>, QualType> DeducedATypes;
for (unsigned I = 0, N = OriginalCallArgs->size(); I != N; ++I) {
OriginalCallArg OriginalArg = (*OriginalCallArgs)[I];
unsigned ParamIdx = OriginalArg.ArgIdx;
auto ParamIdx = OriginalArg.ArgIdx;
if (ParamIdx >= Specialization->getNumParams())
// FIXME: This presumably means a pack ended up smaller than we
// expected while deducing. Should this not result in deduction
// failure? Can it even happen?
continue;
QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType();
QualType DeducedA;
if (!OriginalArg.DecomposedParam) {
// P is one of the function parameters, just look up its substituted
// type.
DeducedA = Specialization->getParamDecl(ParamIdx)->getType();
} else {
// P is a decomposed element of a parameter corresponding to a
// braced-init-list argument. Substitute back into P to find the
// deduced A.
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 (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
Info.FirstArg = TemplateArgument(DeducedA);
Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType);
Info.CallArgIndex = OriginalArg.ArgIdx;
return TDK_DeducedMismatch;
return OriginalArg.DecomposedParam ? TDK_DeducedMismatchNested
: TDK_DeducedMismatch;
}
}
}
@ -3203,7 +3261,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
Expr *Arg, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
Optional<unsigned> ArgIdx, unsigned TDF);
bool DecomposedParam, unsigned ArgIdx, unsigned TDF);
/// \brief Attempt template argument deduction from an initializer list
/// deemed to be an argument in a function call.
@ -3211,7 +3269,8 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList(
Sema &S, TemplateParameterList *TemplateParams, QualType AdjustedParamType,
InitListExpr *ILE, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, unsigned TDF) {
SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs, unsigned ArgIdx,
unsigned TDF) {
// C++ [temp.deduct.call]p1: (CWG 1591)
// If removing references and cv-qualifiers from P gives
// std::initializer_list<P0> or P0[N] for some P0 and N and the argument is
@ -3237,8 +3296,8 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList(
if (ElTy->isDependentType()) {
for (Expr *E : ILE->inits()) {
if (auto Result = DeduceTemplateArgumentsFromCallArgument(
S, TemplateParams, ElTy, E, Info, Deduced, OriginalCallArgs, None,
TDF))
S, TemplateParams, ElTy, E, Info, Deduced, OriginalCallArgs, true,
ArgIdx, TDF))
return Result;
}
}
@ -3270,7 +3329,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
Expr *Arg, TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
SmallVectorImpl<Sema::OriginalCallArg> &OriginalCallArgs,
Optional<unsigned> ArgIdx, unsigned TDF) {
bool DecomposedParam, unsigned ArgIdx, unsigned TDF) {
QualType ArgType = Arg->getType();
QualType OrigParamType = ParamType;
@ -3283,19 +3342,15 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument(
// If [...] the argument is a non-empty initializer list [...]
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Arg))
return DeduceFromInitializerList(S, TemplateParams, ParamType, ILE, Info,
Deduced, OriginalCallArgs, TDF);
Deduced, OriginalCallArgs, ArgIdx, TDF);
// [...] the deduction process attempts to find template argument values
// that will make the deduced A identical to A
//
// Keep track of the argument type and corresponding parameter index,
// so we can check for compatibility between the deduced A and A.
//
// FIXME: We are supposed to perform this check for the P/A pairs we extract
// from the initializer list case too.
if (ArgIdx)
OriginalCallArgs.push_back(
Sema::OriginalCallArg(OrigParamType, *ArgIdx, ArgType));
OriginalCallArgs.push_back(
Sema::OriginalCallArg(OrigParamType, DecomposedParam, ArgIdx, ArgType));
return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
ArgType, Info, Deduced, TDF);
}
@ -3388,7 +3443,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// ... with the type of the corresponding argument
return DeduceTemplateArgumentsFromCallArgument(
*this, TemplateParams, ParamType, Args[ArgIdx], Info, Deduced,
OriginalCallArgs, ArgIdx, /*TDF*/ 0);
OriginalCallArgs, /*Decomposed*/false, ArgIdx, /*TDF*/ 0);
};
// Deduce template arguments from the function parameters.
@ -4075,7 +4130,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
if (DeduceTemplateArgumentsFromCallArgument(
*this, TemplateParamsSt.get(), TemplArg, InitList->getInit(i),
Info, Deduced, OriginalCallArgs, None, /*TDF*/0))
Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
/*ArgIdx*/ 0, /*TDF*/ 0))
return DeductionFailed();
}
} else {
@ -4086,7 +4142,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
if (DeduceTemplateArgumentsFromCallArgument(
*this, TemplateParamsSt.get(), FuncParam, Init, Info, Deduced,
OriginalCallArgs, /*ArgIdx*/0, /*TDF*/0))
OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
return DeductionFailed();
}
@ -4108,8 +4164,11 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
// Check that the deduced argument type is compatible with the original
// argument type per C++ [temp.deduct.call]p4.
QualType DeducedA = InitList ? Deduced[0].getAsType() : Result;
for (const OriginalCallArg &OriginalArg : OriginalCallArgs) {
if (CheckOriginalCallArgDeduction(*this, OriginalArg, Result)) {
assert((bool)InitList == OriginalArg.DecomposedParam &&
"decomposed non-init-list in auto deduction?");
if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) {
Result = QualType();
return DeductionFailed();
}

View File

@ -105,6 +105,7 @@ T deduce_ref(const std::initializer_list<T>&); // expected-note {{conflicting ty
template<typename T, typename U> struct pair { pair(...); };
template<typename T> void deduce_pairs(std::initializer_list<pair<T, typename T::type>>);
// expected-note@-1 {{deduced type 'pair<[...], typename WithIntType::type>' of element of 1st parameter does not match adjusted type 'pair<[...], float>' of element of argument [with T = WithIntType]}}
struct WithIntType { typedef int type; };
template<typename ...T> void deduce_after_init_list_in_pack(void (*)(T...), T...); // expected-note {{<int, int> vs. <(no value), double>}}
@ -123,7 +124,7 @@ void argument_deduction() {
pair<WithIntType, int> pi;
pair<WithIntType, float> pf;
deduce_pairs({pi, pi, pi}); // ok
deduce_pairs({pi, pf, pi}); // FIXME: This should be rejected, as we fail to produce a type that exactly matches the argument type.
deduce_pairs({pi, pf, pi}); // expected-error {{no matching function}}
deduce_after_init_list_in_pack((void(*)(int,int))0, {}, 0);
deduce_after_init_list_in_pack((void(*)(int,int))0, {}, 0.0); // expected-error {{no matching function}}
@ -298,9 +299,18 @@ namespace TemporaryInitListSourceRange_PR22367 {
namespace ParameterPackNestedInitializerLists_PR23904c3 {
template <typename ...T>
void f(std::initializer_list<std::initializer_list<T>> ...tt);
void f(std::initializer_list<std::initializer_list<T>> ...tt); // expected-note 2{{conflicting}} expected-note {{incomplete pack}}
void foo() { f({{0}}, {{'\0'}}); }
void foo() {
f({{0}}, {{'\0'}}); // ok, T = <int, char>
f({{0}, {'\0'}}); // expected-error {{no match}}
f({{0, '\0'}}); // expected-error {{no match}}
f({{0}}, {{{}}}); // expected-error {{no match}}
f({{0}}, {{{}, '\0'}}); // ok, T = <int, char>
f({{0}, {{}}}); // ok, T = <int>
f({{0, {}}}); // ok, T = <int>
}
}
namespace update_rbrace_loc_crash {