Revert "DR1391: Check for implicit conversion sequences for non-dependent function template parameters between deduction and substitution. The idea is to accept as many cases as possible, on the basis that substitution failure outside the immediate context is much more common during substitution than during implicit conversion sequence formation."

This reverts commit r290808, as it broken all ARM and AArch64 test-suite
test: MultiSource/UnitTests/C++11/frame_layout

Also, please, next time, try to write a commit message in according to
our guidelines:

http://llvm.org/docs/DeveloperPolicy.html#commit-messages

llvm-svn: 290811
This commit is contained in:
Renato Golin 2017-01-02 11:15:42 +00:00
parent 21706cbd24
commit dad96d6751
9 changed files with 124 additions and 362 deletions

View File

@ -531,13 +531,6 @@ namespace clang {
Ambiguous.construct(); Ambiguous.construct();
} }
void setAsIdentityConversion(QualType T) {
setStandard();
Standard.setAsIdentityConversion();
Standard.setFromType(T);
Standard.setAllToTypes(T);
}
/// \brief Whether the target is really a std::initializer_list, and the /// \brief Whether the target is really a std::initializer_list, and the
/// sequence only represents the worst element conversion. /// sequence only represents the worst element conversion.
bool isStdInitializerListElement() const { bool isStdInitializerListElement() const {
@ -610,11 +603,6 @@ namespace clang {
ovl_fail_ext_disabled, ovl_fail_ext_disabled,
}; };
/// A list of implicit conversion sequences for the arguments of an
/// OverloadCandidate.
typedef llvm::MutableArrayRef<ImplicitConversionSequence>
ConversionSequenceList;
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3). /// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
struct OverloadCandidate { struct OverloadCandidate {
/// Function - The actual function that this candidate /// Function - The actual function that this candidate
@ -639,13 +627,18 @@ namespace clang {
/// is a surrogate, but only if IsSurrogate is true. /// is a surrogate, but only if IsSurrogate is true.
CXXConversionDecl *Surrogate; CXXConversionDecl *Surrogate;
/// The conversion sequences used to convert the function arguments /// Conversions - The conversion sequences used to convert the
/// to the function parameters. /// function arguments to the function parameters, the pointer points to a
ConversionSequenceList Conversions; /// fixed size array with NumConversions elements. The memory is owned by
/// the OverloadCandidateSet.
ImplicitConversionSequence *Conversions;
/// The FixIt hints which can be used to fix the Bad candidate. /// The FixIt hints which can be used to fix the Bad candidate.
ConversionFixItGenerator Fix; ConversionFixItGenerator Fix;
/// NumConversions - The number of elements in the Conversions array.
unsigned NumConversions;
/// Viable - True to indicate that this overload candidate is viable. /// Viable - True to indicate that this overload candidate is viable.
bool Viable; bool Viable;
@ -684,9 +677,9 @@ namespace clang {
/// hasAmbiguousConversion - Returns whether this overload /// hasAmbiguousConversion - Returns whether this overload
/// candidate requires an ambiguous conversion or not. /// candidate requires an ambiguous conversion or not.
bool hasAmbiguousConversion() const { bool hasAmbiguousConversion() const {
for (auto &C : Conversions) { for (unsigned i = 0, e = NumConversions; i != e; ++i) {
if (!C.isInitialized()) return false; if (!Conversions[i].isInitialized()) return false;
if (C.isAmbiguous()) return true; if (Conversions[i].isAmbiguous()) return true;
} }
return false; return false;
} }
@ -735,7 +728,7 @@ namespace clang {
SmallVector<OverloadCandidate, 16> Candidates; SmallVector<OverloadCandidate, 16> Candidates;
llvm::SmallPtrSet<Decl *, 16> Functions; llvm::SmallPtrSet<Decl *, 16> Functions;
// Allocator for ConversionSequenceLists. We store the first few // Allocator for OverloadCandidate::Conversions. We store the first few
// elements inline to avoid allocation for small sets. // elements inline to avoid allocation for small sets.
llvm::BumpPtrAllocator ConversionSequenceAllocator; llvm::BumpPtrAllocator ConversionSequenceAllocator;
@ -776,45 +769,30 @@ namespace clang {
size_t size() const { return Candidates.size(); } size_t size() const { return Candidates.size(); }
bool empty() const { return Candidates.empty(); } bool empty() const { return Candidates.empty(); }
/// \brief Allocate storage for conversion sequences for NumConversions /// \brief Add a new candidate with NumConversions conversion sequence slots
/// conversions. /// to the overload set.
ConversionSequenceList OverloadCandidate &addCandidate(unsigned NumConversions = 0) {
allocateConversionSequences(unsigned NumConversions) { Candidates.push_back(OverloadCandidate());
ImplicitConversionSequence *Conversions; OverloadCandidate &C = Candidates.back();
// Assign space from the inline array if there are enough free slots // Assign space from the inline array if there are enough free slots
// available. // available.
if (NumConversions + NumInlineSequences <= 16) { if (NumConversions + NumInlineSequences <= 16) {
ImplicitConversionSequence *I = ImplicitConversionSequence *I =
(ImplicitConversionSequence *)InlineSpace.buffer; (ImplicitConversionSequence *)InlineSpace.buffer;
Conversions = &I[NumInlineSequences]; C.Conversions = &I[NumInlineSequences];
NumInlineSequences += NumConversions; NumInlineSequences += NumConversions;
} else { } else {
// Otherwise get memory from the allocator. // Otherwise get memory from the allocator.
Conversions = C.Conversions = ConversionSequenceAllocator
ConversionSequenceAllocator.Allocate<ImplicitConversionSequence>( .Allocate<ImplicitConversionSequence>(NumConversions);
NumConversions);
} }
// Construct the new objects. // Construct the new objects.
for (unsigned I = 0; I != NumConversions; ++I) for (unsigned i = 0; i != NumConversions; ++i)
new (&Conversions[I]) ImplicitConversionSequence(); new (&C.Conversions[i]) ImplicitConversionSequence();
return ConversionSequenceList(Conversions, NumConversions); C.NumConversions = NumConversions;
}
/// \brief Add a new candidate with NumConversions conversion sequence slots
/// to the overload set.
OverloadCandidate &addCandidate(unsigned NumConversions = 0,
ConversionSequenceList Conversions = None) {
assert((Conversions.empty() || Conversions.size() == NumConversions) &&
"preallocated conversion sequence has wrong length");
Candidates.push_back(OverloadCandidate());
OverloadCandidate &C = Candidates.back();
C.Conversions = Conversions.empty()
? allocateConversionSequences(NumConversions)
: Conversions;
return C; return C;
} }

View File

@ -119,7 +119,6 @@ namespace clang {
class FunctionProtoType; class FunctionProtoType;
class FunctionTemplateDecl; class FunctionTemplateDecl;
class ImplicitConversionSequence; class ImplicitConversionSequence;
typedef MutableArrayRef<ImplicitConversionSequence> ConversionSequenceList;
class InitListExpr; class InitListExpr;
class InitializationKind; class InitializationKind;
class InitializationSequence; class InitializationSequence;
@ -2511,11 +2510,10 @@ public:
void AddOverloadCandidate(FunctionDecl *Function, void AddOverloadCandidate(FunctionDecl *Function,
DeclAccessPair FoundDecl, DeclAccessPair FoundDecl,
ArrayRef<Expr *> Args, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false, bool SuppressUserConversions = false,
bool PartialOverloading = false, bool PartialOverloading = false,
bool AllowExplicit = false, bool AllowExplicit = false);
ConversionSequenceList EarlyConversions = None);
void AddFunctionCandidates(const UnresolvedSetImpl &Functions, void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
ArrayRef<Expr *> Args, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, OverloadCandidateSet &CandidateSet,
@ -2535,8 +2533,7 @@ public:
ArrayRef<Expr *> Args, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet, OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false, bool SuppressUserConversions = false,
bool PartialOverloading = false, bool PartialOverloading = false);
ConversionSequenceList EarlyConversions = None);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
DeclAccessPair FoundDecl, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, CXXRecordDecl *ActingContext,
@ -2554,15 +2551,6 @@ public:
OverloadCandidateSet& CandidateSet, OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false, bool SuppressUserConversions = false,
bool PartialOverloading = false); bool PartialOverloading = false);
bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
ConversionSequenceList &Conversions,
bool SuppressUserConversions,
CXXRecordDecl *ActingContext = nullptr,
QualType ObjectType = QualType(),
Expr::Classification
ObjectClassification = {});
void AddConversionCandidate(CXXConversionDecl *Conversion, void AddConversionCandidate(CXXConversionDecl *Conversion,
DeclAccessPair FoundDecl, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, CXXRecordDecl *ActingContext,
@ -6591,8 +6579,6 @@ public:
/// \brief The arguments included an overloaded function name that could /// \brief The arguments included an overloaded function name that could
/// not be resolved to a suitable function. /// not be resolved to a suitable function.
TDK_FailedOverloadResolution, TDK_FailedOverloadResolution,
/// \brief Checking non-dependent argument conversions failed.
TDK_NonDependentConversionFailure,
/// \brief Deduction failed; that's all we know. /// \brief Deduction failed; that's all we know.
TDK_MiscellaneousDeductionFailure, TDK_MiscellaneousDeductionFailure,
/// \brief CUDA Target attributes do not match. /// \brief CUDA Target attributes do not match.
@ -6630,14 +6616,14 @@ public:
QualType OriginalArgType; QualType OriginalArgType;
}; };
TemplateDeductionResult FinishTemplateArgumentDeduction( TemplateDeductionResult
FunctionTemplateDecl *FunctionTemplate, FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
SmallVectorImpl<DeducedTemplateArgument> &Deduced, SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, unsigned NumExplicitlySpecified,
sema::TemplateDeductionInfo &Info, FunctionDecl *&Specialization,
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr, sema::TemplateDeductionInfo &Info,
bool PartialOverloading = false, SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr,
llvm::function_ref<bool()> CheckNonDependent = []{ return false; }); bool PartialOverloading = false);
TemplateDeductionResult TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
@ -6645,8 +6631,7 @@ public:
ArrayRef<Expr *> Args, ArrayRef<Expr *> Args,
FunctionDecl *&Specialization, FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info, sema::TemplateDeductionInfo &Info,
bool PartialOverloading, bool PartialOverloading = false);
llvm::function_ref<bool()> CheckNonDependent);
TemplateDeductionResult TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,

View File

@ -589,6 +589,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
Result.Result = static_cast<unsigned>(TDK); Result.Result = static_cast<unsigned>(TDK);
Result.HasDiagnostic = false; Result.HasDiagnostic = false;
switch (TDK) { switch (TDK) {
case Sema::TDK_Success:
case Sema::TDK_Invalid: case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth: case Sema::TDK_InstantiationDepth:
case Sema::TDK_TooManyArguments: case Sema::TDK_TooManyArguments:
@ -647,10 +648,6 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
case Sema::TDK_FailedOverloadResolution: case Sema::TDK_FailedOverloadResolution:
Result.Data = Info.Expression; Result.Data = Info.Expression;
break; break;
case Sema::TDK_Success:
case Sema::TDK_NonDependentConversionFailure:
llvm_unreachable("not a deduction failure");
} }
return Result; return Result;
@ -667,7 +664,6 @@ void DeductionFailureInfo::Destroy() {
case Sema::TDK_InvalidExplicitArguments: case Sema::TDK_InvalidExplicitArguments:
case Sema::TDK_FailedOverloadResolution: case Sema::TDK_FailedOverloadResolution:
case Sema::TDK_CUDATargetMismatch: case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
break; break;
case Sema::TDK_Inconsistent: case Sema::TDK_Inconsistent:
@ -711,7 +707,6 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() {
case Sema::TDK_NonDeducedMismatch: case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_FailedOverloadResolution: case Sema::TDK_FailedOverloadResolution:
case Sema::TDK_CUDATargetMismatch: case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
return TemplateParameter(); return TemplateParameter();
case Sema::TDK_Incomplete: case Sema::TDK_Incomplete:
@ -744,7 +739,6 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
case Sema::TDK_NonDeducedMismatch: case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_FailedOverloadResolution: case Sema::TDK_FailedOverloadResolution:
case Sema::TDK_CUDATargetMismatch: case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
return nullptr; return nullptr;
case Sema::TDK_DeducedMismatch: case Sema::TDK_DeducedMismatch:
@ -773,7 +767,6 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
case Sema::TDK_SubstitutionFailure: case Sema::TDK_SubstitutionFailure:
case Sema::TDK_FailedOverloadResolution: case Sema::TDK_FailedOverloadResolution:
case Sema::TDK_CUDATargetMismatch: case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
return nullptr; return nullptr;
case Sema::TDK_Inconsistent: case Sema::TDK_Inconsistent:
@ -802,7 +795,6 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
case Sema::TDK_SubstitutionFailure: case Sema::TDK_SubstitutionFailure:
case Sema::TDK_FailedOverloadResolution: case Sema::TDK_FailedOverloadResolution:
case Sema::TDK_CUDATargetMismatch: case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
return nullptr; return nullptr;
case Sema::TDK_Inconsistent: case Sema::TDK_Inconsistent:
@ -837,8 +829,8 @@ llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
void OverloadCandidateSet::destroyCandidates() { void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) { for (iterator i = begin(), e = end(); i != e; ++i) {
for (auto &C : i->Conversions) for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
C.~ImplicitConversionSequence(); i->Conversions[ii].~ImplicitConversionSequence();
if (!i->Viable && i->FailureKind == ovl_fail_bad_deduction) if (!i->Viable && i->FailureKind == ovl_fail_bad_deduction)
i->DeductionFailure.Destroy(); i->DeductionFailure.Destroy();
} }
@ -5845,8 +5837,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
OverloadCandidateSet &CandidateSet, OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions, bool SuppressUserConversions,
bool PartialOverloading, bool PartialOverloading,
bool AllowExplicit, bool AllowExplicit) {
ConversionSequenceList EarlyConversions) {
const FunctionProtoType *Proto const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded"); assert(Proto && "Functions without a prototype cannot be overloaded");
@ -5865,7 +5856,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
AddMethodCandidate(Method, FoundDecl, Method->getParent(), AddMethodCandidate(Method, FoundDecl, Method->getParent(),
QualType(), Expr::Classification::makeSimpleLValue(), QualType(), Expr::Classification::makeSimpleLValue(),
Args, CandidateSet, SuppressUserConversions, Args, CandidateSet, SuppressUserConversions,
PartialOverloading, EarlyConversions); PartialOverloading);
return; return;
} }
// We treat a constructor like a non-member function, since its object // We treat a constructor like a non-member function, since its object
@ -5898,8 +5889,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate // Add this candidate
OverloadCandidate &Candidate = OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
CandidateSet.addCandidate(Args.size(), EarlyConversions);
Candidate.FoundDecl = FoundDecl; Candidate.FoundDecl = FoundDecl;
Candidate.Function = Function; Candidate.Function = Function;
Candidate.Viable = true; Candidate.Viable = true;
@ -5963,10 +5953,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// Determine the implicit conversion sequences for each of the // Determine the implicit conversion sequences for each of the
// arguments. // arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) { for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
if (Candidate.Conversions[ArgIdx].isInitialized()) { if (ArgIdx < NumParams) {
// We already formed a conversion sequence for this parameter during
// template argument deduction.
} else if (ArgIdx < NumParams) {
// (C++ 13.3.2p3): for F to be a viable function, there shall // (C++ 13.3.2p3): for F to be a viable function, there shall
// exist for each argument an implicit conversion sequence // exist for each argument an implicit conversion sequence
// (13.3.3.1) that converts that argument to the corresponding // (13.3.3.1) that converts that argument to the corresponding
@ -6275,8 +6262,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
ArrayRef<Expr *> Args, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions, bool SuppressUserConversions,
bool PartialOverloading, bool PartialOverloading) {
ConversionSequenceList EarlyConversions) {
const FunctionProtoType *Proto const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>()); = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded"); assert(Proto && "Methods without a prototype cannot be overloaded");
@ -6297,8 +6283,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate // Add this candidate
OverloadCandidate &Candidate = OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size() + 1);
CandidateSet.addCandidate(Args.size() + 1, EarlyConversions);
Candidate.FoundDecl = FoundDecl; Candidate.FoundDecl = FoundDecl;
Candidate.Function = Method; Candidate.Function = Method;
Candidate.IsSurrogate = false; Candidate.IsSurrogate = false;
@ -6360,10 +6345,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// Determine the implicit conversion sequences for each of the // Determine the implicit conversion sequences for each of the
// arguments. // arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) { for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
if (Candidate.Conversions[ArgIdx + 1].isInitialized()) { if (ArgIdx < NumParams) {
// We already formed a conversion sequence for this parameter during
// template argument deduction.
} else if (ArgIdx < NumParams) {
// (C++ 13.3.2p3): for F to be a viable function, there shall // (C++ 13.3.2p3): for F to be a viable function, there shall
// exist for each argument an implicit conversion sequence // exist for each argument an implicit conversion sequence
// (13.3.3.1) that converts that argument to the corresponding // (13.3.3.1) that converts that argument to the corresponding
@ -6424,30 +6406,19 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
// functions. // functions.
TemplateDeductionInfo Info(CandidateSet.getLocation()); TemplateDeductionInfo Info(CandidateSet.getLocation());
FunctionDecl *Specialization = nullptr; FunctionDecl *Specialization = nullptr;
ConversionSequenceList Conversions; if (TemplateDeductionResult Result
if (TemplateDeductionResult Result = DeduceTemplateArguments( = DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, Args,
MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info, Specialization, Info, PartialOverloading)) {
PartialOverloading, [&]() { OverloadCandidate &Candidate = CandidateSet.addCandidate();
return CheckNonDependentConversions(
MethodTmpl, Args, CandidateSet, Conversions,
SuppressUserConversions, ActingContext, ObjectType,
ObjectClassification);
})) {
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl; Candidate.FoundDecl = FoundDecl;
Candidate.Function = MethodTmpl->getTemplatedDecl(); Candidate.Function = MethodTmpl->getTemplatedDecl();
Candidate.Viable = false; Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false; Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false; Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size(); Candidate.ExplicitCallArguments = Args.size();
if (Result == TDK_NonDependentConversionFailure) Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
Candidate.FailureKind = ovl_fail_bad_conversion; Info);
else {
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
Info);
}
return; return;
} }
@ -6458,8 +6429,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
"Specialization is not a member function?"); "Specialization is not a member function?");
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl, AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
ActingContext, ObjectType, ObjectClassification, Args, ActingContext, ObjectType, ObjectClassification, Args,
CandidateSet, SuppressUserConversions, PartialOverloading, CandidateSet, SuppressUserConversions, PartialOverloading);
Conversions);
} }
/// \brief Add a C++ function template specialization as a candidate /// \brief Add a C++ function template specialization as a candidate
@ -6487,29 +6457,19 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// functions. // functions.
TemplateDeductionInfo Info(CandidateSet.getLocation()); TemplateDeductionInfo Info(CandidateSet.getLocation());
FunctionDecl *Specialization = nullptr; FunctionDecl *Specialization = nullptr;
ConversionSequenceList Conversions; if (TemplateDeductionResult Result
if (TemplateDeductionResult Result = DeduceTemplateArguments( = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, Args,
FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info, Specialization, Info, PartialOverloading)) {
PartialOverloading, [&]() { OverloadCandidate &Candidate = CandidateSet.addCandidate();
return CheckNonDependentConversions(FunctionTemplate, Args,
CandidateSet, Conversions,
SuppressUserConversions);
})) {
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl; Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl(); Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false; Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false; Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false; Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size(); Candidate.ExplicitCallArguments = Args.size();
if (Result == TDK_NonDependentConversionFailure) Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
Candidate.FailureKind = ovl_fail_bad_conversion; Info);
else {
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
Info);
}
return; return;
} }
@ -6517,64 +6477,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// deduction as a candidate. // deduction as a candidate.
assert(Specialization && "Missing function template specialization?"); assert(Specialization && "Missing function template specialization?");
AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet, AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet,
SuppressUserConversions, PartialOverloading, SuppressUserConversions, PartialOverloading);
/*AllowExplicit*/false, Conversions);
}
/// Check that implicit conversion sequences can be formed for each argument
/// whose corresponding parameter has a non-dependent type, per DR1391's
/// [temp.deduct.call]p10.
bool Sema::CheckNonDependentConversions(
FunctionTemplateDecl *FunctionTemplate, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, ConversionSequenceList &Conversions,
bool SuppressUserConversions, CXXRecordDecl *ActingContext,
QualType ObjectType, Expr::Classification ObjectClassification) {
// FIXME: The cases in which we allow explicit conversions for constructor
// arguments never consider calling a constructor template. It's not clear
// that is correct.
const bool AllowExplicit = false;
auto *FD = FunctionTemplate->getTemplatedDecl();
auto *Method = dyn_cast<CXXMethodDecl>(FD);
bool HasThisConversion = Method && !isa<CXXConstructorDecl>(Method);
unsigned ThisConversions = HasThisConversion ? 1 : 0;
Conversions =
CandidateSet.allocateConversionSequences(ThisConversions + Args.size());
// Overload resolution is always an unevaluated context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// For a method call, check the 'this' conversion here too. DR1391 doesn't
// require that, but this check should never result in a hard error, and
// overload resolution is permitted to sidestep instantiations.
if (HasThisConversion && !cast<CXXMethodDecl>(FD)->isStatic() &&
!ObjectType.isNull()) {
Conversions[0] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
Method, ActingContext);
if (Conversions[0].isBad())
return true;
}
for (unsigned I = 0, N = std::min<unsigned>(FD->getNumParams(), Args.size());
I != N; ++I) {
QualType ParamType = FD->getParamDecl(I)->getType();
if (!ParamType->isDependentType()) {
Conversions[ThisConversions + I]
= TryCopyInitialization(*this, Args[I], ParamType,
SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
getLangOpts().ObjCAutoRefCount,
AllowExplicit);
if (Conversions[ThisConversions + I].isBad())
return true;
}
}
return false;
} }
/// Determine whether this is an allowable conversion from the result /// Determine whether this is an allowable conversion from the result
@ -8813,8 +8716,8 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
// Define functions that don't require ill-formed conversions for a given // Define functions that don't require ill-formed conversions for a given
// argument to be better candidates than functions that do. // argument to be better candidates than functions that do.
unsigned NumArgs = Cand1.Conversions.size(); unsigned NumArgs = Cand1.NumConversions;
assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch"); assert(Cand2.NumConversions == NumArgs && "Overload candidate mismatch");
bool HasBetterConversion = false; bool HasBetterConversion = false;
for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) { for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
bool Cand1Bad = IsIllFormedConversion(Cand1.Conversions[ArgIdx]); bool Cand1Bad = IsIllFormedConversion(Cand1.Conversions[ArgIdx]);
@ -10021,7 +9924,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_bad_conversion: { case ovl_fail_bad_conversion: {
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0); unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
for (unsigned N = Cand->Conversions.size(); I != N; ++I) for (unsigned N = Cand->NumConversions; I != N; ++I)
if (Cand->Conversions[I].isBad()) if (Cand->Conversions[I].isBad())
return DiagnoseBadConversion(S, Cand, I, TakingCandidateAddress); return DiagnoseBadConversion(S, Cand, I, TakingCandidateAddress);
@ -10084,12 +9987,12 @@ static void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc, static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
SourceLocation OpLoc, SourceLocation OpLoc,
OverloadCandidate *Cand) { OverloadCandidate *Cand) {
assert(Cand->Conversions.size() <= 2 && "builtin operator is not binary"); assert(Cand->NumConversions <= 2 && "builtin operator is not binary");
std::string TypeStr("operator"); std::string TypeStr("operator");
TypeStr += Opc; TypeStr += Opc;
TypeStr += "("; TypeStr += "(";
TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString(); TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString();
if (Cand->Conversions.size() == 1) { if (Cand->NumConversions == 1) {
TypeStr += ")"; TypeStr += ")";
S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr; S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr;
} else { } else {
@ -10102,7 +10005,9 @@ static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
static void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, static void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
OverloadCandidate *Cand) { OverloadCandidate *Cand) {
for (const ImplicitConversionSequence &ICS : Cand->Conversions) { unsigned NoOperands = Cand->NumConversions;
for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
if (ICS.isBad()) break; // all meaningless after first invalid if (ICS.isBad()) break; // all meaningless after first invalid
if (!ICS.isAmbiguous()) continue; if (!ICS.isAmbiguous()) continue;
@ -10122,8 +10027,7 @@ static SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) {
static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) { static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
switch ((Sema::TemplateDeductionResult)DFI.Result) { switch ((Sema::TemplateDeductionResult)DFI.Result) {
case Sema::TDK_Success: case Sema::TDK_Success:
case Sema::TDK_NonDependentConversionFailure: llvm_unreachable("TDK_success while diagnosing bad deduction");
llvm_unreachable("non-deduction failure while diagnosing bad deduction");
case Sema::TDK_Invalid: case Sema::TDK_Invalid:
case Sema::TDK_Incomplete: case Sema::TDK_Incomplete:
@ -10226,11 +10130,11 @@ struct CompareOverloadCandidatesForDisplay {
// If there's any ordering between the defined conversions... // If there's any ordering between the defined conversions...
// FIXME: this might not be transitive. // FIXME: this might not be transitive.
assert(L->Conversions.size() == R->Conversions.size()); assert(L->NumConversions == R->NumConversions);
int leftBetter = 0; int leftBetter = 0;
unsigned I = (L->IgnoreObjectArgument || R->IgnoreObjectArgument); unsigned I = (L->IgnoreObjectArgument || R->IgnoreObjectArgument);
for (unsigned E = L->Conversions.size(); I != E; ++I) { for (unsigned E = L->NumConversions; I != E; ++I) {
switch (CompareImplicitConversionSequences(S, Loc, switch (CompareImplicitConversionSequences(S, Loc,
L->Conversions[I], L->Conversions[I],
R->Conversions[I])) { R->Conversions[I])) {
@ -10279,8 +10183,7 @@ struct CompareOverloadCandidatesForDisplay {
} }
/// CompleteNonViableCandidate - Normally, overload resolution only /// CompleteNonViableCandidate - Normally, overload resolution only
/// computes up to the first bad conversion. Produces the FixIt set if /// computes up to the first. Produces the FixIt set if possible.
/// possible.
static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
ArrayRef<Expr *> Args) { ArrayRef<Expr *> Args) {
assert(!Cand->Viable); assert(!Cand->Viable);
@ -10293,24 +10196,30 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
// Use a implicit copy initialization to check conversion fixes. // Use a implicit copy initialization to check conversion fixes.
Cand->Fix.setConversionChecker(TryCopyInitialization); Cand->Fix.setConversionChecker(TryCopyInitialization);
// Attempt to fix the bad conversion. // Skip forward to the first bad conversion.
unsigned ConvCount = Cand->Conversions.size(); unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0);
for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); /**/; unsigned ConvCount = Cand->NumConversions;
++ConvIdx) { while (true) {
assert(ConvIdx != ConvCount && "no bad conversion in candidate"); assert(ConvIdx != ConvCount && "no bad conversion in candidate");
if (Cand->Conversions[ConvIdx].isInitialized() && ConvIdx++;
Cand->Conversions[ConvIdx].isBad()) { if (Cand->Conversions[ConvIdx - 1].isBad()) {
Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S); Unfixable = !Cand->TryToFixBadConversion(ConvIdx - 1, S);
break; break;
} }
} }
if (ConvIdx == ConvCount)
return;
assert(!Cand->Conversions[ConvIdx].isInitialized() &&
"remaining conversion is initialized?");
// FIXME: this should probably be preserved from the overload // FIXME: this should probably be preserved from the overload
// operation somehow. // operation somehow.
bool SuppressUserConversions = false; bool SuppressUserConversions = false;
const FunctionProtoType *Proto; const FunctionProtoType* Proto;
unsigned ArgIdx = 0; unsigned ArgIdx = ConvIdx;
if (Cand->IsSurrogate) { if (Cand->IsSurrogate) {
QualType ConvType QualType ConvType
@ -10318,56 +10227,40 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
ConvType = ConvPtrType->getPointeeType(); ConvType = ConvPtrType->getPointeeType();
Proto = ConvType->getAs<FunctionProtoType>(); Proto = ConvType->getAs<FunctionProtoType>();
ArgIdx = 1; ArgIdx--;
} else if (Cand->Function) { } else if (Cand->Function) {
Proto = Cand->Function->getType()->getAs<FunctionProtoType>(); Proto = Cand->Function->getType()->getAs<FunctionProtoType>();
if (isa<CXXMethodDecl>(Cand->Function) && if (isa<CXXMethodDecl>(Cand->Function) &&
!isa<CXXConstructorDecl>(Cand->Function)) !isa<CXXConstructorDecl>(Cand->Function))
ArgIdx = 1; ArgIdx--;
} else { } else {
// Builtin binary operator with a bad first conversion. // Builtin binary operator with a bad first conversion.
assert(ConvCount <= 3); assert(ConvCount <= 3);
for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); for (; ConvIdx != ConvCount; ++ConvIdx)
ConvIdx != ConvCount; ++ConvIdx) { Cand->Conversions[ConvIdx]
if (Cand->Conversions[ConvIdx].isInitialized()) = TryCopyInitialization(S, Args[ConvIdx],
continue; Cand->BuiltinTypes.ParamTypes[ConvIdx],
if (Cand->BuiltinTypes.ParamTypes[ConvIdx]->isDependentType()) SuppressUserConversions,
Cand->Conversions[ConvIdx].setAsIdentityConversion( /*InOverloadResolution*/ true,
Args[ConvIdx]->getType()); /*AllowObjCWritebackConversion=*/
else S.getLangOpts().ObjCAutoRefCount);
Cand->Conversions[ConvIdx] = TryCopyInitialization(
S, Args[ConvIdx], Cand->BuiltinTypes.ParamTypes[ConvIdx],
SuppressUserConversions,
/*InOverloadResolution*/ true,
/*AllowObjCWritebackConversion=*/
S.getLangOpts().ObjCAutoRefCount);
// FIXME: If the conversion is bad, try to fix it.
}
return; return;
} }
// Fill in the rest of the conversions. // Fill in the rest of the conversions.
unsigned NumParams = Proto->getNumParams(); unsigned NumParams = Proto->getNumParams();
for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) { if (ArgIdx < NumParams) {
if (Cand->Conversions[ConvIdx].isInitialized()) { Cand->Conversions[ConvIdx] = TryCopyInitialization(
// Found the bad conversion. S, Args[ArgIdx], Proto->getParamType(ArgIdx), SuppressUserConversions,
} else if (ArgIdx < NumParams) { /*InOverloadResolution=*/true,
if (Proto->getParamType(ArgIdx)->isDependentType()) /*AllowObjCWritebackConversion=*/
Cand->Conversions[ConvIdx].setAsIdentityConversion( S.getLangOpts().ObjCAutoRefCount);
Args[ArgIdx]->getType()); // Store the FixIt in the candidate if it exists.
else { if (!Unfixable && Cand->Conversions[ConvIdx].isBad())
Cand->Conversions[ConvIdx] = Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S);
TryCopyInitialization(S, Args[ArgIdx], Proto->getParamType(ArgIdx), }
SuppressUserConversions, else
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
S.getLangOpts().ObjCAutoRefCount);
// Store the FixIt in the candidate if it exists.
if (!Unfixable && Cand->Conversions[ConvIdx].isBad())
Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S);
}
} else
Cand->Conversions[ConvIdx].setEllipsis(); Cand->Conversions[ConvIdx].setEllipsis();
} }
} }

View File

@ -2849,13 +2849,14 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
/// ///
/// \param OriginalCallArgs If non-NULL, the original call arguments against /// \param OriginalCallArgs If non-NULL, the original call arguments against
/// which the deduced argument types should be compared. /// which the deduced argument types should be compared.
Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( Sema::TemplateDeductionResult
FunctionTemplateDecl *FunctionTemplate, Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
SmallVectorImpl<DeducedTemplateArgument> &Deduced, SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, unsigned NumExplicitlySpecified,
TemplateDeductionInfo &Info, FunctionDecl *&Specialization,
SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs, TemplateDeductionInfo &Info,
bool PartialOverloading, llvm::function_ref<bool()> CheckNonDependent) { SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
bool PartialOverloading) {
// Unevaluated SFINAE context. // Unevaluated SFINAE context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
SFINAETrap Trap(*this); SFINAETrap Trap(*this);
@ -2882,18 +2883,6 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
PartialOverloading)) PartialOverloading))
return Result; return Result;
// C++ [temp.deduct.call]p10: [DR1391]
// If deduction succeeds for all parameters that contain
// template-parameters that participate in template argument deduction,
// and all template arguments are explicitly specified, deduced, or
// obtained from default template arguments, remaining parameters are then
// compared with the corresponding arguments. For each remaining parameter
// P with a type that was non-dependent before substitution of any
// explicitly-specified template arguments, if the corresponding argument
// A cannot be implicitly converted to P, deduction fails.
if (CheckNonDependent())
return TDK_NonDependentConversionFailure;
// Form the template argument list from the deduced template arguments. // Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList TemplateArgumentList *DeducedArgumentList
= TemplateArgumentList::CreateCopy(Context, Builder); = TemplateArgumentList::CreateCopy(Context, Builder);
@ -3318,17 +3307,12 @@ DeduceTemplateArgumentByListElement(Sema &S,
/// \param Info the argument will be updated to provide additional information /// \param Info the argument will be updated to provide additional information
/// about template argument deduction. /// about template argument deduction.
/// ///
/// \param CheckNonDependent A callback to invoke to check conversions for
/// non-dependent parameters, between deduction and substitution, per DR1391.
/// If this returns true, substitution will be skipped and we return
/// TDK_NonDependentConversionFailure.
///
/// \returns the result of template argument deduction. /// \returns the result of template argument deduction.
Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
FunctionTemplateDecl *FunctionTemplate, FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
FunctionDecl *&Specialization, TemplateDeductionInfo &Info, FunctionDecl *&Specialization, TemplateDeductionInfo &Info,
bool PartialOverloading, llvm::function_ref<bool()> CheckNonDependent) { bool PartialOverloading) {
if (FunctionTemplate->isInvalidDecl()) if (FunctionTemplate->isInvalidDecl())
return TDK_Invalid; return TDK_Invalid;
@ -3512,7 +3496,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
NumExplicitlySpecified, Specialization, NumExplicitlySpecified, Specialization,
Info, &OriginalCallArgs, Info, &OriginalCallArgs,
PartialOverloading, CheckNonDependent); PartialOverloading);
} }
QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType, QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,

View File

@ -174,81 +174,3 @@ namespace dr1359 { // dr1359: 3.5
constexpr Y y = Y(); // expected-error {{no matching}} constexpr Y y = Y(); // expected-error {{no matching}}
#endif #endif
} }
namespace dr1391 { // dr1391: partial
struct A {}; struct B : A {};
template<typename T> struct C { C(int); typename T::error error; }; // expected-error 2{{'::'}}
template<typename T> struct D {};
// No deduction is performed for parameters with no deducible template-parameters, therefore types do not need to match.
template<typename T> void a(T, int T::*);
void test_a(int A::*p) { a(A(), p); } // ok, type of second parameter does not need to match
namespace dr_example_1 {
template<typename T, typename U> void f(C<T>);
template<typename T> void f(D<T>);
void g(D<int> d) {
f(d); // ok, first 'f' eliminated by deduction failure
f<int>(d); // ok, first 'f' eliminated because 'U' cannot be deduced
}
}
namespace dr_example_2 {
template<typename T> typename C<T>::error f(int, T);
template<typename T> T f(T, T);
void g(A a) {
f(a, a); // ok, no conversion from A to int for first parameter of first candidate
}
}
namespace std_example {
template<typename T> struct Z {
typedef typename T::x xx;
};
template<typename T> typename Z<T>::xx f(void *, T);
template<typename T> void f(int, T);
struct A {} a;
void g() { f(1, a); }
}
template<typename T> void b(C<int> ci, T *p);
void b(...);
void test_b() {
b(0, 0); // ok, deduction fails prior to forming a conversion sequence and instantiating C<int>
// FIXME: The "while substituting" note should point at the overload candidate.
b<int>(0, 0); // expected-note {{instantiation of}} expected-note {{while substituting}}
}
template<typename T> struct Id { typedef T type; };
template<typename T> void c(T, typename Id<C<T> >::type);
void test_c() {
// Implicit conversion sequences for dependent types are checked later.
c(0.0, 0); // expected-note {{instantiation of}}
}
namespace partial_ordering {
// FIXME: Second template should be considered more specialized because non-dependent parameter is ignored.
template<typename T> int a(T, short) = delete; // expected-error 0-1{{extension}} expected-note {{candidate}}
template<typename T> int a(T*, char); // expected-note {{candidate}}
int test_a = a((int*)0, 0); // FIXME: expected-error {{ambiguous}}
// FIXME: Second template should be considered more specialized:
// deducing #1 from #2 ignores the second P/A pair, so deduction succeeds,
// deducing #2 from #1 fails to deduce T, so deduction fails.
template<typename T> int b(T, int) = delete; // expected-error 0-1{{extension}} expected-note {{candidate}}
template<typename T, typename U> int b(T*, U); // expected-note {{candidate}}
int test_b = b((int*)0, 0); // FIXME: expected-error {{ambiguous}}
// Unintended consequences: because partial ordering does not consider
// explicit template arguments, and deduction from a non-dependent type
// vacuously succeeds, a non-dependent template is less specialized than
// anything else!
// According to DR1391, this is ambiguous!
template<typename T> int c(int);
template<typename T> int c(T);
int test_c1 = c(0); // ok
int test_c2 = c<int>(0); // FIXME: apparently ambiguous
}
}

View File

@ -1401,7 +1401,7 @@ void run() {
f(1, integral_constant<bool, true>{}); f(1, integral_constant<bool, true>{});
} }
// CHECK-ELIDE-NOTREE: error: no matching function for call to 'f' // CHECK-ELIDE-NOTREE: error: no matching function for call to 'f'
// CHECK-ELIDE-NOTREE: note: candidate function not viable: no known conversion from 'integral_constant<[...], true>' to 'integral_constant<[...], false>' for 2nd argument // CHECK-ELIDE-NOTREE: note: candidate function [with T = int] not viable: no known conversion from 'integral_constant<[...], true>' to 'integral_constant<[...], false>' for 2nd argument
} }
namespace ZeroArgs { namespace ZeroArgs {

View File

@ -338,7 +338,7 @@ namespace PR5756 {
// Tests the exact text used to note the candidates // Tests the exact text used to note the candidates
namespace test1 { namespace test1 {
template <class T> void foo(T t, unsigned N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}} template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}}
void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'char' for 2nd argument}} void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'char' for 2nd argument}}
void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}} void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}}
void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}} void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}

View File

@ -70,7 +70,7 @@ void test_X2(X2 *x2p, const X2 *cx2p) {
// Tests the exact text used to note the candidates // Tests the exact text used to note the candidates
namespace test1 { namespace test1 {
class A { class A {
template <class T> void foo(T t, unsigned N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}} template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'const char [6]' to 'unsigned int' for 2nd argument}}
void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'char' for 2nd argument}} void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'const char [6]' to 'char' for 2nd argument}}
void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}} void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}}
void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}} void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}

View File

@ -8161,7 +8161,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1391">1391</a></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1391">1391</a></td>
<td>DRWP</td> <td>DRWP</td>
<td>Conversions to parameter types with non-deduced template arguments</td> <td>Conversions to parameter types with non-deduced template arguments</td>
<td class="partial" align="center">Partial</td> <td class="none" align="center">Unknown</td>
</tr> </tr>
<tr id="1392"> <tr id="1392">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1392">1392</a></td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1392">1392</a></td>