summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Sema/Overload.h68
-rw-r--r--clang/include/clang/Sema/Sema.h39
-rw-r--r--clang/lib/Sema/SemaOverload.cpp257
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp36
-rw-r--r--clang/test/CXX/drs/dr13xx.cpp78
-rw-r--r--clang/test/Misc/diag-template-diffing.cpp2
-rw-r--r--clang/test/SemaCXX/overload-call.cpp2
-rw-r--r--clang/test/SemaCXX/overload-member-call.cpp2
-rw-r--r--clang/www/cxx_dr_status.html2
9 files changed, 362 insertions, 124 deletions
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 376db92d03b..0d74816dfd0 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -531,6 +531,13 @@ namespace clang {
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
/// sequence only represents the worst element conversion.
bool isStdInitializerListElement() const {
@@ -603,6 +610,11 @@ namespace clang {
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).
struct OverloadCandidate {
/// Function - The actual function that this candidate
@@ -627,18 +639,13 @@ namespace clang {
/// is a surrogate, but only if IsSurrogate is true.
CXXConversionDecl *Surrogate;
- /// Conversions - The conversion sequences used to convert the
- /// function arguments to the function parameters, the pointer points to a
- /// fixed size array with NumConversions elements. The memory is owned by
- /// the OverloadCandidateSet.
- ImplicitConversionSequence *Conversions;
+ /// The conversion sequences used to convert the function arguments
+ /// to the function parameters.
+ ConversionSequenceList Conversions;
/// The FixIt hints which can be used to fix the Bad candidate.
ConversionFixItGenerator Fix;
- /// NumConversions - The number of elements in the Conversions array.
- unsigned NumConversions;
-
/// Viable - True to indicate that this overload candidate is viable.
bool Viable;
@@ -677,9 +684,9 @@ namespace clang {
/// hasAmbiguousConversion - Returns whether this overload
/// candidate requires an ambiguous conversion or not.
bool hasAmbiguousConversion() const {
- for (unsigned i = 0, e = NumConversions; i != e; ++i) {
- if (!Conversions[i].isInitialized()) return false;
- if (Conversions[i].isAmbiguous()) return true;
+ for (auto &C : Conversions) {
+ if (!C.isInitialized()) return false;
+ if (C.isAmbiguous()) return true;
}
return false;
}
@@ -728,7 +735,7 @@ namespace clang {
SmallVector<OverloadCandidate, 16> Candidates;
llvm::SmallPtrSet<Decl *, 16> Functions;
- // Allocator for OverloadCandidate::Conversions. We store the first few
+ // Allocator for ConversionSequenceLists. We store the first few
// elements inline to avoid allocation for small sets.
llvm::BumpPtrAllocator ConversionSequenceAllocator;
@@ -769,30 +776,45 @@ namespace clang {
size_t size() const { return Candidates.size(); }
bool empty() const { return Candidates.empty(); }
- /// \brief Add a new candidate with NumConversions conversion sequence slots
- /// to the overload set.
- OverloadCandidate &addCandidate(unsigned NumConversions = 0) {
- Candidates.push_back(OverloadCandidate());
- OverloadCandidate &C = Candidates.back();
+ /// \brief Allocate storage for conversion sequences for NumConversions
+ /// conversions.
+ ConversionSequenceList
+ allocateConversionSequences(unsigned NumConversions) {
+ ImplicitConversionSequence *Conversions;
// Assign space from the inline array if there are enough free slots
// available.
if (NumConversions + NumInlineSequences <= 16) {
ImplicitConversionSequence *I =
(ImplicitConversionSequence *)InlineSpace.buffer;
- C.Conversions = &I[NumInlineSequences];
+ Conversions = &I[NumInlineSequences];
NumInlineSequences += NumConversions;
} else {
// Otherwise get memory from the allocator.
- C.Conversions = ConversionSequenceAllocator
- .Allocate<ImplicitConversionSequence>(NumConversions);
+ Conversions =
+ ConversionSequenceAllocator.Allocate<ImplicitConversionSequence>(
+ NumConversions);
}
// Construct the new objects.
- for (unsigned i = 0; i != NumConversions; ++i)
- new (&C.Conversions[i]) ImplicitConversionSequence();
+ for (unsigned I = 0; I != NumConversions; ++I)
+ new (&Conversions[I]) ImplicitConversionSequence();
+
+ return ConversionSequenceList(Conversions, 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");
- C.NumConversions = NumConversions;
+ Candidates.push_back(OverloadCandidate());
+ OverloadCandidate &C = Candidates.back();
+ C.Conversions = Conversions.empty()
+ ? allocateConversionSequences(NumConversions)
+ : Conversions;
return C;
}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 82caaeb24ae..a7e563d3b86 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -119,6 +119,7 @@ namespace clang {
class FunctionProtoType;
class FunctionTemplateDecl;
class ImplicitConversionSequence;
+ typedef MutableArrayRef<ImplicitConversionSequence> ConversionSequenceList;
class InitListExpr;
class InitializationKind;
class InitializationSequence;
@@ -2510,10 +2511,11 @@ public:
void AddOverloadCandidate(FunctionDecl *Function,
DeclAccessPair FoundDecl,
ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet,
+ OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions = false,
bool PartialOverloading = false,
- bool AllowExplicit = false);
+ bool AllowExplicit = false,
+ ConversionSequenceList EarlyConversions = None);
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
@@ -2533,7 +2535,8 @@ public:
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
- bool PartialOverloading = false);
+ bool PartialOverloading = false,
+ ConversionSequenceList EarlyConversions = None);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
@@ -2551,6 +2554,15 @@ public:
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = 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,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
@@ -6579,6 +6591,8 @@ public:
/// \brief The arguments included an overloaded function name that could
/// not be resolved to a suitable function.
TDK_FailedOverloadResolution,
+ /// \brief Checking non-dependent argument conversions failed.
+ TDK_NonDependentConversionFailure,
/// \brief Deduction failed; that's all we know.
TDK_MiscellaneousDeductionFailure,
/// \brief CUDA Target attributes do not match.
@@ -6616,14 +6630,14 @@ public:
QualType OriginalArgType;
};
- TemplateDeductionResult
- FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned NumExplicitlySpecified,
- FunctionDecl *&Specialization,
- sema::TemplateDeductionInfo &Info,
- SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr,
- bool PartialOverloading = false);
+ TemplateDeductionResult FinishTemplateArgumentDeduction(
+ FunctionTemplateDecl *FunctionTemplate,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ unsigned NumExplicitlySpecified, FunctionDecl *&Specialization,
+ sema::TemplateDeductionInfo &Info,
+ SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = nullptr,
+ bool PartialOverloading = false,
+ llvm::function_ref<bool()> CheckNonDependent = []{ return false; });
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
@@ -6631,7 +6645,8 @@ public:
ArrayRef<Expr *> Args,
FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info,
- bool PartialOverloading = false);
+ bool PartialOverloading,
+ llvm::function_ref<bool()> CheckNonDependent);
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 47e3df20d91..a2ee2b00ecf 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -589,7 +589,6 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
Result.Result = static_cast<unsigned>(TDK);
Result.HasDiagnostic = false;
switch (TDK) {
- case Sema::TDK_Success:
case Sema::TDK_Invalid:
case Sema::TDK_InstantiationDepth:
case Sema::TDK_TooManyArguments:
@@ -648,6 +647,10 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
case Sema::TDK_FailedOverloadResolution:
Result.Data = Info.Expression;
break;
+
+ case Sema::TDK_Success:
+ case Sema::TDK_NonDependentConversionFailure:
+ llvm_unreachable("not a deduction failure");
}
return Result;
@@ -664,6 +667,7 @@ void DeductionFailureInfo::Destroy() {
case Sema::TDK_InvalidExplicitArguments:
case Sema::TDK_FailedOverloadResolution:
case Sema::TDK_CUDATargetMismatch:
+ case Sema::TDK_NonDependentConversionFailure:
break;
case Sema::TDK_Inconsistent:
@@ -707,6 +711,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() {
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_FailedOverloadResolution:
case Sema::TDK_CUDATargetMismatch:
+ case Sema::TDK_NonDependentConversionFailure:
return TemplateParameter();
case Sema::TDK_Incomplete:
@@ -739,6 +744,7 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_FailedOverloadResolution:
case Sema::TDK_CUDATargetMismatch:
+ case Sema::TDK_NonDependentConversionFailure:
return nullptr;
case Sema::TDK_DeducedMismatch:
@@ -767,6 +773,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_FailedOverloadResolution:
case Sema::TDK_CUDATargetMismatch:
+ case Sema::TDK_NonDependentConversionFailure:
return nullptr;
case Sema::TDK_Inconsistent:
@@ -795,6 +802,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_FailedOverloadResolution:
case Sema::TDK_CUDATargetMismatch:
+ case Sema::TDK_NonDependentConversionFailure:
return nullptr;
case Sema::TDK_Inconsistent:
@@ -829,8 +837,8 @@ llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
- for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
- i->Conversions[ii].~ImplicitConversionSequence();
+ for (auto &C : i->Conversions)
+ C.~ImplicitConversionSequence();
if (!i->Viable && i->FailureKind == ovl_fail_bad_deduction)
i->DeductionFailure.Destroy();
}
@@ -5837,7 +5845,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions,
bool PartialOverloading,
- bool AllowExplicit) {
+ bool AllowExplicit,
+ ConversionSequenceList EarlyConversions) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -5856,7 +5865,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
AddMethodCandidate(Method, FoundDecl, Method->getParent(),
QualType(), Expr::Classification::makeSimpleLValue(),
Args, CandidateSet, SuppressUserConversions,
- PartialOverloading);
+ PartialOverloading, EarlyConversions);
return;
}
// We treat a constructor like a non-member function, since its object
@@ -5889,7 +5898,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate
- OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size());
+ OverloadCandidate &Candidate =
+ CandidateSet.addCandidate(Args.size(), EarlyConversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Function;
Candidate.Viable = true;
@@ -5953,7 +5963,10 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
- if (ArgIdx < NumParams) {
+ if (Candidate.Conversions[ArgIdx].isInitialized()) {
+ // 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
// exist for each argument an implicit conversion sequence
// (13.3.3.1) that converts that argument to the corresponding
@@ -6262,7 +6275,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions,
- bool PartialOverloading) {
+ bool PartialOverloading,
+ ConversionSequenceList EarlyConversions) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
@@ -6283,7 +6297,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
// Add this candidate
- OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size() + 1);
+ OverloadCandidate &Candidate =
+ CandidateSet.addCandidate(Args.size() + 1, EarlyConversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Method;
Candidate.IsSurrogate = false;
@@ -6345,7 +6360,10 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
- if (ArgIdx < NumParams) {
+ if (Candidate.Conversions[ArgIdx + 1].isInitialized()) {
+ // 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
// exist for each argument an implicit conversion sequence
// (13.3.3.1) that converts that argument to the corresponding
@@ -6406,19 +6424,30 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
// functions.
TemplateDeductionInfo Info(CandidateSet.getLocation());
FunctionDecl *Specialization = nullptr;
- if (TemplateDeductionResult Result
- = DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, Args,
- Specialization, Info, PartialOverloading)) {
- OverloadCandidate &Candidate = CandidateSet.addCandidate();
+ ConversionSequenceList Conversions;
+ if (TemplateDeductionResult Result = DeduceTemplateArguments(
+ MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info,
+ PartialOverloading, [&]() {
+ return CheckNonDependentConversions(
+ MethodTmpl, Args, CandidateSet, Conversions,
+ SuppressUserConversions, ActingContext, ObjectType,
+ ObjectClassification);
+ })) {
+ OverloadCandidate &Candidate =
+ CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = MethodTmpl->getTemplatedDecl();
Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
- Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
- Info);
+ if (Result == TDK_NonDependentConversionFailure)
+ Candidate.FailureKind = ovl_fail_bad_conversion;
+ else {
+ Candidate.FailureKind = ovl_fail_bad_deduction;
+ Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
+ Info);
+ }
return;
}
@@ -6429,7 +6458,8 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
"Specialization is not a member function?");
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
ActingContext, ObjectType, ObjectClassification, Args,
- CandidateSet, SuppressUserConversions, PartialOverloading);
+ CandidateSet, SuppressUserConversions, PartialOverloading,
+ Conversions);
}
/// \brief Add a C++ function template specialization as a candidate
@@ -6457,19 +6487,29 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// functions.
TemplateDeductionInfo Info(CandidateSet.getLocation());
FunctionDecl *Specialization = nullptr;
- if (TemplateDeductionResult Result
- = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, Args,
- Specialization, Info, PartialOverloading)) {
- OverloadCandidate &Candidate = CandidateSet.addCandidate();
+ ConversionSequenceList Conversions;
+ if (TemplateDeductionResult Result = DeduceTemplateArguments(
+ FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info,
+ PartialOverloading, [&]() {
+ return CheckNonDependentConversions(FunctionTemplate, Args,
+ CandidateSet, Conversions,
+ SuppressUserConversions);
+ })) {
+ OverloadCandidate &Candidate =
+ CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
- Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
- Info);
+ if (Result == TDK_NonDependentConversionFailure)
+ Candidate.FailureKind = ovl_fail_bad_conversion;
+ else {
+ Candidate.FailureKind = ovl_fail_bad_deduction;
+ Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result,
+ Info);
+ }
return;
}
@@ -6477,7 +6517,64 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
// deduction as a candidate.
assert(Specialization && "Missing function template specialization?");
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
@@ -8716,8 +8813,8 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
// Define functions that don't require ill-formed conversions for a given
// argument to be better candidates than functions that do.
- unsigned NumArgs = Cand1.NumConversions;
- assert(Cand2.NumConversions == NumArgs && "Overload candidate mismatch");
+ unsigned NumArgs = Cand1.Conversions.size();
+ assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch");
bool HasBetterConversion = false;
for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
bool Cand1Bad = IsIllFormedConversion(Cand1.Conversions[ArgIdx]);
@@ -9924,7 +10021,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_bad_conversion: {
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
- for (unsigned N = Cand->NumConversions; I != N; ++I)
+ for (unsigned N = Cand->Conversions.size(); I != N; ++I)
if (Cand->Conversions[I].isBad())
return DiagnoseBadConversion(S, Cand, I, TakingCandidateAddress);
@@ -9987,12 +10084,12 @@ static void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
SourceLocation OpLoc,
OverloadCandidate *Cand) {
- assert(Cand->NumConversions <= 2 && "builtin operator is not binary");
+ assert(Cand->Conversions.size() <= 2 && "builtin operator is not binary");
std::string TypeStr("operator");
TypeStr += Opc;
TypeStr += "(";
TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString();
- if (Cand->NumConversions == 1) {
+ if (Cand->Conversions.size() == 1) {
TypeStr += ")";
S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr;
} else {
@@ -10005,9 +10102,7 @@ static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
static void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
OverloadCandidate *Cand) {
- unsigned NoOperands = Cand->NumConversions;
- for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) {
- const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx];
+ for (const ImplicitConversionSequence &ICS : Cand->Conversions) {
if (ICS.isBad()) break; // all meaningless after first invalid
if (!ICS.isAmbiguous()) continue;
@@ -10027,7 +10122,8 @@ static SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) {
static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
switch ((Sema::TemplateDeductionResult)DFI.Result) {
case Sema::TDK_Success:
- llvm_unreachable("TDK_success while diagnosing bad deduction");
+ case Sema::TDK_NonDependentConversionFailure:
+ llvm_unreachable("non-deduction failure while diagnosing bad deduction");
case Sema::TDK_Invalid:
case Sema::TDK_Incomplete:
@@ -10130,11 +10226,11 @@ struct CompareOverloadCandidatesForDisplay {
// If there's any ordering between the defined conversions...
// FIXME: this might not be transitive.
- assert(L->NumConversions == R->NumConversions);
+ assert(L->Conversions.size() == R->Conversions.size());
int leftBetter = 0;
unsigned I = (L->IgnoreObjectArgument || R->IgnoreObjectArgument);
- for (unsigned E = L->NumConversions; I != E; ++I) {
+ for (unsigned E = L->Conversions.size(); I != E; ++I) {
switch (CompareImplicitConversionSequences(S, Loc,
L->Conversions[I],
R->Conversions[I])) {
@@ -10183,7 +10279,8 @@ struct CompareOverloadCandidatesForDisplay {
}
/// CompleteNonViableCandidate - Normally, overload resolution only
-/// computes up to the first. Produces the FixIt set if possible.
+/// computes up to the first bad conversion. Produces the FixIt set if
+/// possible.
static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
ArrayRef<Expr *> Args) {
assert(!Cand->Viable);
@@ -10196,30 +10293,24 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
// Use a implicit copy initialization to check conversion fixes.
Cand->Fix.setConversionChecker(TryCopyInitialization);
- // Skip forward to the first bad conversion.
- unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0);
- unsigned ConvCount = Cand->NumConversions;
- while (true) {
+ // Attempt to fix the bad conversion.
+ unsigned ConvCount = Cand->Conversions.size();
+ for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); /**/;
+ ++ConvIdx) {
assert(ConvIdx != ConvCount && "no bad conversion in candidate");
- ConvIdx++;
- if (Cand->Conversions[ConvIdx - 1].isBad()) {
- Unfixable = !Cand->TryToFixBadConversion(ConvIdx - 1, S);
+ if (Cand->Conversions[ConvIdx].isInitialized() &&
+ Cand->Conversions[ConvIdx].isBad()) {
+ Unfixable = !Cand->TryToFixBadConversion(ConvIdx, S);
break;
}
}
- if (ConvIdx == ConvCount)
- return;
-
- assert(!Cand->Conversions[ConvIdx].isInitialized() &&
- "remaining conversion is initialized?");
-
// FIXME: this should probably be preserved from the overload
// operation somehow.
bool SuppressUserConversions = false;
- const FunctionProtoType* Proto;
- unsigned ArgIdx = ConvIdx;
+ const FunctionProtoType *Proto;
+ unsigned ArgIdx = 0;
if (Cand->IsSurrogate) {
QualType ConvType
@@ -10227,40 +10318,56 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
ConvType = ConvPtrType->getPointeeType();
Proto = ConvType->getAs<FunctionProtoType>();
- ArgIdx--;
+ ArgIdx = 1;
} else if (Cand->Function) {
Proto = Cand->Function->getType()->getAs<FunctionProtoType>();
if (isa<CXXMethodDecl>(Cand->Function) &&
!isa<CXXConstructorDecl>(Cand->Function))
- ArgIdx--;
+ ArgIdx = 1;
} else {
// Builtin binary operator with a bad first conversion.
assert(ConvCount <= 3);
- for (; ConvIdx != ConvCount; ++ConvIdx)
- Cand->Conversions[ConvIdx]
- = TryCopyInitialization(S, Args[ConvIdx],
- Cand->BuiltinTypes.ParamTypes[ConvIdx],
- SuppressUserConversions,
- /*InOverloadResolution*/ true,
- /*AllowObjCWritebackConversion=*/
- S.getLangOpts().ObjCAutoRefCount);
+ for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0);
+ ConvIdx != ConvCount; ++ConvIdx) {
+ if (Cand->Conversions[ConvIdx].isInitialized())
+ continue;
+ if (Cand->BuiltinTypes.ParamTypes[ConvIdx]->isDependentType())
+ Cand->Conversions[ConvIdx].setAsIdentityConversion(
+ Args[ConvIdx]->getType());
+ else
+ 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;
}
// Fill in the rest of the conversions.
unsigned NumParams = Proto->getNumParams();
- for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
- if (ArgIdx < NumParams) {
- Cand->Conversions[ConvIdx] = TryCopyInitialization(
- S, Args[ArgIdx], Proto->getParamType(ArgIdx), SuppressUserConversions,
- /*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
+ for (unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0);
+ ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
+ if (Cand->Conversions[ConvIdx].isInitialized()) {
+ // Found the bad conversion.
+ } else if (ArgIdx < NumParams) {
+ if (Proto->getParamType(ArgIdx)->isDependentType())
+ Cand->Conversions[ConvIdx].setAsIdentityConversion(
+ Args[ArgIdx]->getType());
+ else {
+ Cand->Conversions[ConvIdx] =
+ TryCopyInitialization(S, Args[ArgIdx], Proto->getParamType(ArgIdx),
+ SuppressUserConversions,
+ /*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();
}
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 0bc85a2f263..dc291836fb9 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2849,14 +2849,13 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
///
/// \param OriginalCallArgs If non-NULL, the original call arguments against
/// which the deduced argument types should be compared.
-Sema::TemplateDeductionResult
-Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- unsigned NumExplicitlySpecified,
- FunctionDecl *&Specialization,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
- bool PartialOverloading) {
+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) {
// Unevaluated SFINAE context.
EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
SFINAETrap Trap(*this);
@@ -2883,6 +2882,18 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
PartialOverloading))
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.
TemplateArgumentList *DeducedArgumentList
= TemplateArgumentList::CreateCopy(Context, Builder);
@@ -3307,12 +3318,17 @@ DeduceTemplateArgumentByListElement(Sema &S,
/// \param Info the argument will be updated to provide additional information
/// 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.
Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
FunctionDecl *&Specialization, TemplateDeductionInfo &Info,
- bool PartialOverloading) {
+ bool PartialOverloading, llvm::function_ref<bool()> CheckNonDependent) {
if (FunctionTemplate->isInvalidDecl())
return TDK_Invalid;
@@ -3496,7 +3512,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced,
NumExplicitlySpecified, Specialization,
Info, &OriginalCallArgs,
- PartialOverloading);
+ PartialOverloading, CheckNonDependent);
}
QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,
diff --git a/clang/test/CXX/drs/dr13xx.cpp b/clang/test/CXX/drs/dr13xx.cpp
index 28bebcbb607..b9be5ca821c 100644
--- a/clang/test/CXX/drs/dr13xx.cpp
+++ b/clang/test/CXX/drs/dr13xx.cpp
@@ -174,3 +174,81 @@ namespace dr1359 { // dr1359: 3.5
constexpr Y y = Y(); // expected-error {{no matching}}
#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
+ }
+}
diff --git a/clang/test/Misc/diag-template-diffing.cpp b/clang/test/Misc/diag-template-diffing.cpp
index 78083989928..2192223191b 100644
--- a/clang/test/Misc/diag-template-diffing.cpp
+++ b/clang/test/Misc/diag-template-diffing.cpp
@@ -1401,7 +1401,7 @@ void run() {
f(1, integral_constant<bool, true>{});
}
// CHECK-ELIDE-NOTREE: error: no matching function for call to 'f'
-// 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
+// CHECK-ELIDE-NOTREE: note: candidate function not viable: no known conversion from 'integral_constant<[...], true>' to 'integral_constant<[...], false>' for 2nd argument
}
namespace ZeroArgs {
diff --git a/clang/test/SemaCXX/overload-call.cpp b/clang/test/SemaCXX/overload-call.cpp
index 3a01bf24b31..0e3a9ee50bb 100644
--- a/clang/test/SemaCXX/overload-call.cpp
+++ b/clang/test/SemaCXX/overload-call.cpp
@@ -338,7 +338,7 @@ namespace PR5756 {
// Tests the exact text used to note the candidates
namespace test1 {
- 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}}
+ 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}}
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 at least 3 arguments, but 2 were provided}}
diff --git a/clang/test/SemaCXX/overload-member-call.cpp b/clang/test/SemaCXX/overload-member-call.cpp
index e0f34d937f6..6e64b25d6b5 100644
--- a/clang/test/SemaCXX/overload-member-call.cpp
+++ b/clang/test/SemaCXX/overload-member-call.cpp
@@ -70,7 +70,7 @@ void test_X2(X2 *x2p, const X2 *cx2p) {
// Tests the exact text used to note the candidates
namespace test1 {
class A {
- 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}}
+ 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}}
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 at least 3 arguments, but 2 were provided}}
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index b4936eed3b3..90176314403 100644
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -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>DRWP</td>
<td>Conversions to parameter types with non-deduced template arguments</td>
- <td class="none" align="center">Unknown</td>
+ <td class="partial" align="center">Partial</td>
</tr>
<tr id="1392">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1392">1392</a></td>
OpenPOWER on IntegriCloud