forked from OSchip/llvm-project
Resolve a defect in C++17 copy omission.
When selecting constructors for initializing an object of type T from a single expression of class type U, also consider conversion functions of U that convert to T (rather than modeling such conversions as calling a conversion function and then calling a constructor). This approach is proposed as the resolution for the defect, and is also already implemented by GCC. llvm-svn: 314231
This commit is contained in:
parent
afd34c6df7
commit
67ef14fe48
|
@ -726,11 +726,20 @@ namespace clang {
|
|||
enum CandidateSetKind {
|
||||
/// Normal lookup.
|
||||
CSK_Normal,
|
||||
/// Lookup for candidates for a call using operator syntax. Candidates
|
||||
/// that have no parameters of class type will be skipped unless there
|
||||
/// is a parameter of (reference to) enum type and the corresponding
|
||||
/// argument is of the same enum type.
|
||||
CSK_Operator
|
||||
/// C++ [over.match.oper]:
|
||||
/// Lookup of operator function candidates in a call using operator
|
||||
/// syntax. Candidates that have no parameters of class type will be
|
||||
/// skipped unless there is a parameter of (reference to) enum type and
|
||||
/// the corresponding argument is of the same enum type.
|
||||
CSK_Operator,
|
||||
/// C++ [over.match.copy]:
|
||||
/// Copy-initialization of an object of class type by user-defined
|
||||
/// conversion.
|
||||
CSK_InitByUserDefinedConversion,
|
||||
/// C++ [over.match.ctor], [over.match.list]
|
||||
/// Initialization of an object of class type by constructor,
|
||||
/// using either a parenthesized or braced list of arguments.
|
||||
CSK_InitByConstructor,
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -795,7 +804,7 @@ namespace clang {
|
|||
}
|
||||
|
||||
/// \brief Clear out all of the candidates.
|
||||
void clear();
|
||||
void clear(CandidateSetKind CSK);
|
||||
|
||||
typedef SmallVectorImpl<OverloadCandidate>::iterator iterator;
|
||||
iterator begin() { return Candidates.begin(); }
|
||||
|
@ -835,8 +844,7 @@ namespace clang {
|
|||
|
||||
/// Find the best viable function on this overload set, if it exists.
|
||||
OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc,
|
||||
OverloadCandidateSet::iterator& Best,
|
||||
bool UserDefinedConversion = false);
|
||||
OverloadCandidateSet::iterator& Best);
|
||||
|
||||
void NoteCandidates(Sema &S,
|
||||
OverloadCandidateDisplayKind OCD,
|
||||
|
@ -848,10 +856,10 @@ namespace clang {
|
|||
};
|
||||
|
||||
bool isBetterOverloadCandidate(Sema &S,
|
||||
const OverloadCandidate& Cand1,
|
||||
const OverloadCandidate& Cand2,
|
||||
const OverloadCandidate &Cand1,
|
||||
const OverloadCandidate &Cand2,
|
||||
SourceLocation Loc,
|
||||
bool UserDefinedConversion = false);
|
||||
OverloadCandidateSet::CandidateSetKind Kind);
|
||||
|
||||
struct ConstructorInfo {
|
||||
DeclAccessPair FoundDecl;
|
||||
|
|
|
@ -2742,13 +2742,15 @@ public:
|
|||
CXXRecordDecl *ActingContext,
|
||||
Expr *From, QualType ToType,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool AllowObjCConversionOnExplicit);
|
||||
bool AllowObjCConversionOnExplicit,
|
||||
bool AllowResultConversion = true);
|
||||
void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
|
||||
DeclAccessPair FoundDecl,
|
||||
CXXRecordDecl *ActingContext,
|
||||
Expr *From, QualType ToType,
|
||||
OverloadCandidateSet &CandidateSet,
|
||||
bool AllowObjCConversionOnExplicit);
|
||||
bool AllowObjCConversionOnExplicit,
|
||||
bool AllowResultConversion = true);
|
||||
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
|
||||
DeclAccessPair FoundDecl,
|
||||
CXXRecordDecl *ActingContext,
|
||||
|
|
|
@ -4293,7 +4293,8 @@ static void mergeCandidatesWithResults(Sema &SemaRef,
|
|||
std::stable_sort(
|
||||
CandidateSet.begin(), CandidateSet.end(),
|
||||
[&](const OverloadCandidate &X, const OverloadCandidate &Y) {
|
||||
return isBetterOverloadCandidate(SemaRef, X, Y, Loc);
|
||||
return isBetterOverloadCandidate(SemaRef, X, Y, Loc,
|
||||
CandidateSet.getKind());
|
||||
});
|
||||
|
||||
// Add the remaining viable overload candidates as code-completion results.
|
||||
|
|
|
@ -3531,12 +3531,13 @@ static OverloadingResult
|
|||
ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
|
||||
MultiExprArg Args,
|
||||
OverloadCandidateSet &CandidateSet,
|
||||
QualType DestType,
|
||||
DeclContext::lookup_result Ctors,
|
||||
OverloadCandidateSet::iterator &Best,
|
||||
bool CopyInitializing, bool AllowExplicit,
|
||||
bool OnlyListConstructors, bool IsListInit,
|
||||
bool SecondStepOfCopyInit = false) {
|
||||
CandidateSet.clear();
|
||||
CandidateSet.clear(OverloadCandidateSet::CSK_InitByConstructor);
|
||||
|
||||
for (NamedDecl *D : Ctors) {
|
||||
auto Info = getConstructorInfo(D);
|
||||
|
@ -3587,6 +3588,50 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Work around a bug in C++17 guaranteed copy elision.
|
||||
//
|
||||
// When initializing an object of class type T by constructor
|
||||
// ([over.match.ctor]) or by list-initialization ([over.match.list])
|
||||
// from a single expression of class type U, conversion functions of
|
||||
// U that convert to the non-reference type cv T are candidates.
|
||||
// Explicit conversion functions are only candidates during
|
||||
// direct-initialization.
|
||||
//
|
||||
// Note: SecondStepOfCopyInit is only ever true in this case when
|
||||
// evaluating whether to produce a C++98 compatibility warning.
|
||||
if (S.getLangOpts().CPlusPlus1z && Args.size() == 1 &&
|
||||
!SecondStepOfCopyInit) {
|
||||
Expr *Initializer = Args[0];
|
||||
auto *SourceRD = Initializer->getType()->getAsCXXRecordDecl();
|
||||
if (SourceRD && S.isCompleteType(DeclLoc, Initializer->getType())) {
|
||||
const auto &Conversions = SourceRD->getVisibleConversionFunctions();
|
||||
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
|
||||
NamedDecl *D = *I;
|
||||
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
|
||||
D = D->getUnderlyingDecl();
|
||||
|
||||
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
|
||||
CXXConversionDecl *Conv;
|
||||
if (ConvTemplate)
|
||||
Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
|
||||
else
|
||||
Conv = cast<CXXConversionDecl>(D);
|
||||
|
||||
if ((AllowExplicit && !CopyInitializing) || !Conv->isExplicit()) {
|
||||
if (ConvTemplate)
|
||||
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
|
||||
ActingDC, Initializer, DestType,
|
||||
CandidateSet, AllowExplicit,
|
||||
/*AllowResultConversion*/false);
|
||||
else
|
||||
S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
|
||||
DestType, CandidateSet, AllowExplicit,
|
||||
/*AllowResultConversion*/false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform overload resolution and return the result.
|
||||
return CandidateSet.BestViableFunction(S, DeclLoc, Best);
|
||||
}
|
||||
|
@ -3686,7 +3731,7 @@ static void TryConstructorInitialization(Sema &S,
|
|||
// the first phase is omitted.
|
||||
if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor()))
|
||||
Result = ResolveConstructorOverload(S, Kind.getLocation(), Args,
|
||||
CandidateSet, Ctors, Best,
|
||||
CandidateSet, DestType, Ctors, Best,
|
||||
CopyInitialization, AllowExplicit,
|
||||
/*OnlyListConstructor=*/true,
|
||||
IsListInit);
|
||||
|
@ -3700,7 +3745,7 @@ static void TryConstructorInitialization(Sema &S,
|
|||
if (Result == OR_No_Viable_Function) {
|
||||
AsInitializerList = false;
|
||||
Result = ResolveConstructorOverload(S, Kind.getLocation(), UnwrappedArgs,
|
||||
CandidateSet, Ctors, Best,
|
||||
CandidateSet, DestType, Ctors, Best,
|
||||
CopyInitialization, AllowExplicit,
|
||||
/*OnlyListConstructors=*/false,
|
||||
IsListInit);
|
||||
|
@ -3713,6 +3758,24 @@ static void TryConstructorInitialization(Sema &S,
|
|||
return;
|
||||
}
|
||||
|
||||
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
||||
|
||||
// In C++17, ResolveConstructorOverload can select a conversion function
|
||||
// instead of a constructor.
|
||||
if (auto *CD = dyn_cast<CXXConversionDecl>(Best->Function)) {
|
||||
// Add the user-defined conversion step that calls the conversion function.
|
||||
QualType ConvType = CD->getConversionType();
|
||||
assert(S.Context.hasSameUnqualifiedType(ConvType, DestType) &&
|
||||
"should not have selected this conversion function");
|
||||
Sequence.AddUserConversionStep(CD, Best->FoundDecl, ConvType,
|
||||
HadMultipleCandidates);
|
||||
if (!S.Context.hasSameType(ConvType, DestType))
|
||||
Sequence.AddQualificationConversionStep(DestType, VK_RValue);
|
||||
if (IsListInit)
|
||||
Sequence.RewrapReferenceInitList(Entity.getType(), ILE);
|
||||
return;
|
||||
}
|
||||
|
||||
// C++11 [dcl.init]p6:
|
||||
// If a program calls for the default initialization of an object
|
||||
// of a const-qualified type T, T shall be a class type with a
|
||||
|
@ -3741,7 +3804,6 @@ static void TryConstructorInitialization(Sema &S,
|
|||
|
||||
// Add the constructor initialization step. Any cv-qualification conversion is
|
||||
// subsumed by the initialization.
|
||||
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
||||
Sequence.AddConstructorInitializationStep(
|
||||
Best->FoundDecl, CtorDecl, DestArrayType, HadMultipleCandidates,
|
||||
IsListInit | IsInitListCopy, AsInitializerList);
|
||||
|
@ -4087,7 +4149,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
|
|||
// Build the candidate set directly in the initialization sequence
|
||||
// structure, so that it will persist if we fail.
|
||||
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
|
||||
CandidateSet.clear();
|
||||
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
|
||||
|
||||
// Determine whether we are allowed to call explicit constructors or
|
||||
// explicit conversion operators.
|
||||
|
@ -4173,7 +4235,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
|
|||
// Perform overload resolution. If it fails, return the failed result.
|
||||
OverloadCandidateSet::iterator Best;
|
||||
if (OverloadingResult Result
|
||||
= CandidateSet.BestViableFunction(S, DeclLoc, Best, true))
|
||||
= CandidateSet.BestViableFunction(S, DeclLoc, Best))
|
||||
return Result;
|
||||
|
||||
FunctionDecl *Function = Best->Function;
|
||||
|
@ -4687,7 +4749,7 @@ static void TryUserDefinedConversion(Sema &S,
|
|||
// Build the candidate set directly in the initialization sequence
|
||||
// structure, so that it will persist if we fail.
|
||||
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
|
||||
CandidateSet.clear();
|
||||
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
|
||||
|
||||
// Determine whether we are allowed to call explicit constructors or
|
||||
// explicit conversion operators.
|
||||
|
@ -4766,7 +4828,7 @@ static void TryUserDefinedConversion(Sema &S,
|
|||
// Perform overload resolution. If it fails, return the failed result.
|
||||
OverloadCandidateSet::iterator Best;
|
||||
if (OverloadingResult Result
|
||||
= CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) {
|
||||
= CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
|
||||
Sequence.SetOverloadFailure(
|
||||
InitializationSequence::FK_UserConversionOverloadFailed,
|
||||
Result);
|
||||
|
@ -5657,7 +5719,7 @@ static ExprResult CopyObject(Sema &S,
|
|||
|
||||
OverloadCandidateSet::iterator Best;
|
||||
switch (ResolveConstructorOverload(
|
||||
S, Loc, CurInitExpr, CandidateSet, Ctors, Best,
|
||||
S, Loc, CurInitExpr, CandidateSet, T, Ctors, Best,
|
||||
/*CopyInitializing=*/false, /*AllowExplicit=*/true,
|
||||
/*OnlyListConstructors=*/false, /*IsListInit=*/false,
|
||||
/*SecondStepOfCopyInit=*/true)) {
|
||||
|
@ -5797,7 +5859,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
|
|||
// Perform overload resolution.
|
||||
OverloadCandidateSet::iterator Best;
|
||||
OverloadingResult OR = ResolveConstructorOverload(
|
||||
S, Loc, CurInitExpr, CandidateSet, Ctors, Best,
|
||||
S, Loc, CurInitExpr, CandidateSet, CurInitExpr->getType(), Ctors, Best,
|
||||
/*CopyInitializing=*/false, /*AllowExplicit=*/true,
|
||||
/*OnlyListConstructors=*/false, /*IsListInit=*/false,
|
||||
/*SecondStepOfCopyInit=*/true);
|
||||
|
@ -7535,8 +7597,7 @@ bool InitializationSequence::Diagnose(Sema &S,
|
|||
<< Args[0]->getSourceRange();
|
||||
OverloadCandidateSet::iterator Best;
|
||||
OverloadingResult Ovl
|
||||
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best,
|
||||
true);
|
||||
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
|
||||
if (Ovl == OR_Deleted) {
|
||||
S.NoteDeletedFunction(Best->Function);
|
||||
} else {
|
||||
|
@ -8415,7 +8476,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
|
|||
OverloadCandidateSet::iterator Best;
|
||||
auto tryToResolveOverload =
|
||||
[&](bool OnlyListConstructors) -> OverloadingResult {
|
||||
Candidates.clear();
|
||||
Candidates.clear(OverloadCandidateSet::CSK_Normal);
|
||||
for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
|
||||
NamedDecl *D = (*I)->getUnderlyingDecl();
|
||||
if (D->isInvalidDecl())
|
||||
|
|
|
@ -837,12 +837,13 @@ void OverloadCandidateSet::destroyCandidates() {
|
|||
}
|
||||
}
|
||||
|
||||
void OverloadCandidateSet::clear() {
|
||||
void OverloadCandidateSet::clear(CandidateSetKind CSK) {
|
||||
destroyCandidates();
|
||||
SlabAllocator.Reset();
|
||||
NumInlineBytesUsed = 0;
|
||||
Candidates.clear();
|
||||
Functions.clear();
|
||||
Kind = CSK;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -3175,6 +3176,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
|
|||
UserDefinedConversionSequence &User,
|
||||
OverloadCandidateSet &CandidateSet,
|
||||
bool AllowExplicit) {
|
||||
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
|
||||
for (auto *D : S.LookupConstructors(To)) {
|
||||
auto Info = getConstructorInfo(D);
|
||||
if (!Info)
|
||||
|
@ -3203,7 +3205,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
|
|||
OverloadCandidateSet::iterator Best;
|
||||
switch (auto Result =
|
||||
CandidateSet.BestViableFunction(S, From->getLocStart(),
|
||||
Best, true)) {
|
||||
Best)) {
|
||||
case OR_Deleted:
|
||||
case OR_Success: {
|
||||
// Record the standard conversion we used and the conversion function.
|
||||
|
@ -3250,6 +3252,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
|
|||
bool AllowExplicit,
|
||||
bool AllowObjCConversionOnExplicit) {
|
||||
assert(AllowExplicit || !AllowObjCConversionOnExplicit);
|
||||
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
|
||||
|
||||
// Whether we will only visit constructors.
|
||||
bool ConstructorsOnly = false;
|
||||
|
@ -3285,7 +3288,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
|
|||
if (Result != OR_No_Viable_Function)
|
||||
return Result;
|
||||
// Never mind.
|
||||
CandidateSet.clear();
|
||||
CandidateSet.clear(
|
||||
OverloadCandidateSet::CSK_InitByUserDefinedConversion);
|
||||
|
||||
// If we're list-initializing, we pass the individual elements as
|
||||
// arguments, not the entire list.
|
||||
|
@ -3375,7 +3379,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
|
|||
|
||||
OverloadCandidateSet::iterator Best;
|
||||
switch (auto Result = CandidateSet.BestViableFunction(S, From->getLocStart(),
|
||||
Best, true)) {
|
||||
Best)) {
|
||||
case OR_Success:
|
||||
case OR_Deleted:
|
||||
// Record the standard conversion we used and the conversion function.
|
||||
|
@ -4309,7 +4313,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
|
|||
CXXRecordDecl *T2RecordDecl
|
||||
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
|
||||
|
||||
OverloadCandidateSet CandidateSet(DeclLoc, OverloadCandidateSet::CSK_Normal);
|
||||
OverloadCandidateSet CandidateSet(
|
||||
DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion);
|
||||
const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions();
|
||||
for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
|
||||
NamedDecl *D = *I;
|
||||
|
@ -4379,7 +4384,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
|
|||
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
||||
|
||||
OverloadCandidateSet::iterator Best;
|
||||
switch (CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) {
|
||||
switch (CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
|
||||
case OR_Success:
|
||||
// C++ [over.ics.ref]p1:
|
||||
//
|
||||
|
@ -6788,7 +6793,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
|
|||
CXXRecordDecl *ActingContext,
|
||||
Expr *From, QualType ToType,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool AllowObjCConversionOnExplicit) {
|
||||
bool AllowObjCConversionOnExplicit,
|
||||
bool AllowResultConversion) {
|
||||
assert(!Conversion->getDescribedFunctionTemplate() &&
|
||||
"Conversion function templates use AddTemplateConversionCandidate");
|
||||
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
|
||||
|
@ -6803,6 +6809,12 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
|
|||
ConvType = Conversion->getConversionType().getNonReferenceType();
|
||||
}
|
||||
|
||||
// If we don't allow any conversion of the result type, ignore conversion
|
||||
// functions that don't convert to exactly (possibly cv-qualified) T.
|
||||
if (!AllowResultConversion &&
|
||||
!Context.hasSameUnqualifiedType(Conversion->getConversionType(), ToType))
|
||||
return;
|
||||
|
||||
// Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion
|
||||
// operator is only a candidate if its return type is the target type or
|
||||
// can be converted to the target type with a qualification conversion.
|
||||
|
@ -6956,7 +6968,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
|
|||
CXXRecordDecl *ActingDC,
|
||||
Expr *From, QualType ToType,
|
||||
OverloadCandidateSet &CandidateSet,
|
||||
bool AllowObjCConversionOnExplicit) {
|
||||
bool AllowObjCConversionOnExplicit,
|
||||
bool AllowResultConversion) {
|
||||
assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
|
||||
"Only conversion function templates permitted here");
|
||||
|
||||
|
@ -6985,7 +6998,8 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
|
|||
// template argument deduction as a candidate.
|
||||
assert(Specialization && "Missing function template specialization?");
|
||||
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
|
||||
CandidateSet, AllowObjCConversionOnExplicit);
|
||||
CandidateSet, AllowObjCConversionOnExplicit,
|
||||
AllowResultConversion);
|
||||
}
|
||||
|
||||
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
|
||||
|
@ -8844,10 +8858,9 @@ static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1,
|
|||
|
||||
/// isBetterOverloadCandidate - Determines whether the first overload
|
||||
/// candidate is a better candidate than the second (C++ 13.3.3p1).
|
||||
bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
|
||||
const OverloadCandidate &Cand2,
|
||||
SourceLocation Loc,
|
||||
bool UserDefinedConversion) {
|
||||
bool clang::isBetterOverloadCandidate(
|
||||
Sema &S, const OverloadCandidate &Cand1, const OverloadCandidate &Cand2,
|
||||
SourceLocation Loc, OverloadCandidateSet::CandidateSetKind Kind) {
|
||||
// Define viable functions to be better candidates than non-viable
|
||||
// functions.
|
||||
if (!Cand2.Viable)
|
||||
|
@ -8929,7 +8942,8 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
|
|||
// the type of the entity being initialized) is a better
|
||||
// conversion sequence than the standard conversion sequence
|
||||
// from the return type of F2 to the destination type.
|
||||
if (UserDefinedConversion && Cand1.Function && Cand2.Function &&
|
||||
if (Kind == OverloadCandidateSet::CSK_InitByUserDefinedConversion &&
|
||||
Cand1.Function && Cand2.Function &&
|
||||
isa<CXXConversionDecl>(Cand1.Function) &&
|
||||
isa<CXXConversionDecl>(Cand2.Function)) {
|
||||
// First check whether we prefer one of the conversion functions over the
|
||||
|
@ -9001,6 +9015,18 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
|
|||
// Inherited from sibling base classes: still ambiguous.
|
||||
}
|
||||
|
||||
// FIXME: Work around a defect in the C++17 guaranteed copy elision wording,
|
||||
// as combined with the resolution to CWG issue 243.
|
||||
//
|
||||
// When the context is initialization by constructor ([over.match.ctor] or
|
||||
// either phase of [over.match.list]), a constructor is preferred over
|
||||
// a conversion function.
|
||||
if (Kind == OverloadCandidateSet::CSK_InitByConstructor && NumArgs == 1 &&
|
||||
Cand1.Function && Cand2.Function &&
|
||||
isa<CXXConstructorDecl>(Cand1.Function) !=
|
||||
isa<CXXConstructorDecl>(Cand2.Function))
|
||||
return isa<CXXConstructorDecl>(Cand1.Function);
|
||||
|
||||
// Check for enable_if value-based overload resolution.
|
||||
if (Cand1.Function && Cand2.Function) {
|
||||
Comparison Cmp = compareEnableIfAttrs(S, Cand1.Function, Cand2.Function);
|
||||
|
@ -9100,8 +9126,7 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations(
|
|||
/// \returns The result of overload resolution.
|
||||
OverloadingResult
|
||||
OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
|
||||
iterator &Best,
|
||||
bool UserDefinedConversion) {
|
||||
iterator &Best) {
|
||||
llvm::SmallVector<OverloadCandidate *, 16> Candidates;
|
||||
std::transform(begin(), end(), std::back_inserter(Candidates),
|
||||
[](OverloadCandidate &Cand) { return &Cand; });
|
||||
|
@ -9135,8 +9160,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
|
|||
Best = end();
|
||||
for (auto *Cand : Candidates)
|
||||
if (Cand->Viable)
|
||||
if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc,
|
||||
UserDefinedConversion))
|
||||
if (Best == end() ||
|
||||
isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind))
|
||||
Best = Cand;
|
||||
|
||||
// If we didn't find any viable functions, abort.
|
||||
|
@ -9148,10 +9173,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
|
|||
// Make sure that this function is better than every other viable
|
||||
// function. If not, we have an ambiguity.
|
||||
for (auto *Cand : Candidates) {
|
||||
if (Cand->Viable &&
|
||||
Cand != Best &&
|
||||
!isBetterOverloadCandidate(S, *Best, *Cand, Loc,
|
||||
UserDefinedConversion)) {
|
||||
if (Cand->Viable && Cand != Best &&
|
||||
!isBetterOverloadCandidate(S, *Best, *Cand, Loc, Kind)) {
|
||||
if (S.isEquivalentInternalLinkageDeclaration(Best->Function,
|
||||
Cand->Function)) {
|
||||
EquivalentCands.push_back(Cand->Function);
|
||||
|
@ -10243,9 +10266,12 @@ struct CompareOverloadCandidatesForDisplay {
|
|||
Sema &S;
|
||||
SourceLocation Loc;
|
||||
size_t NumArgs;
|
||||
OverloadCandidateSet::CandidateSetKind CSK;
|
||||
|
||||
CompareOverloadCandidatesForDisplay(Sema &S, SourceLocation Loc, size_t nArgs)
|
||||
: S(S), NumArgs(nArgs) {}
|
||||
CompareOverloadCandidatesForDisplay(
|
||||
Sema &S, SourceLocation Loc, size_t NArgs,
|
||||
OverloadCandidateSet::CandidateSetKind CSK)
|
||||
: S(S), NumArgs(NArgs) {}
|
||||
|
||||
bool operator()(const OverloadCandidate *L,
|
||||
const OverloadCandidate *R) {
|
||||
|
@ -10259,8 +10285,10 @@ struct CompareOverloadCandidatesForDisplay {
|
|||
// TODO: introduce a tri-valued comparison for overload
|
||||
// candidates. Would be more worthwhile if we had a sort
|
||||
// that could exploit it.
|
||||
if (isBetterOverloadCandidate(S, *L, *R, SourceLocation())) return true;
|
||||
if (isBetterOverloadCandidate(S, *R, *L, SourceLocation())) return false;
|
||||
if (isBetterOverloadCandidate(S, *L, *R, SourceLocation(), CSK))
|
||||
return true;
|
||||
if (isBetterOverloadCandidate(S, *R, *L, SourceLocation(), CSK))
|
||||
return false;
|
||||
} else if (R->Viable)
|
||||
return false;
|
||||
|
||||
|
@ -10468,7 +10496,7 @@ void OverloadCandidateSet::NoteCandidates(
|
|||
}
|
||||
|
||||
std::sort(Cands.begin(), Cands.end(),
|
||||
CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size()));
|
||||
CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size(), Kind));
|
||||
|
||||
bool ReportedAmbiguousConversions = false;
|
||||
|
||||
|
@ -12917,7 +12945,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
|
|||
// Perform overload resolution.
|
||||
OverloadCandidateSet::iterator Best;
|
||||
switch (CandidateSet.BestViableFunction(*this, Object.get()->getLocStart(),
|
||||
Best)) {
|
||||
Best)) {
|
||||
case OR_Success:
|
||||
// Overload resolution succeeded; we'll build the appropriate call
|
||||
// below.
|
||||
|
@ -13311,7 +13339,7 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
|
|||
Expr *Range, ExprResult *CallExpr) {
|
||||
Scope *S = nullptr;
|
||||
|
||||
CandidateSet->clear();
|
||||
CandidateSet->clear(OverloadCandidateSet::CSK_Normal);
|
||||
if (!MemberLookup.empty()) {
|
||||
ExprResult MemberRef =
|
||||
BuildMemberReferenceExpr(Range, Range->getType(), Loc,
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
struct Noncopyable {
|
||||
Noncopyable();
|
||||
Noncopyable(const Noncopyable &) = delete; // expected-note 1+{{deleted}}
|
||||
Noncopyable(const Noncopyable &) = delete; // expected-note 1+{{deleted}} expected-note 1+ {{not viable}}
|
||||
virtual ~Noncopyable();
|
||||
};
|
||||
struct Derived : Noncopyable {};
|
||||
struct NoncopyableAggr {
|
||||
struct NoncopyableAggr { // expected-note 3{{candidate}}
|
||||
Noncopyable nc;
|
||||
};
|
||||
struct Indestructible {
|
||||
|
@ -38,11 +38,39 @@ Noncopyable nrvo() {
|
|||
Noncopyable nc1 = make();
|
||||
Noncopyable nc2 = Noncopyable();
|
||||
Noncopyable nc3 = Derived(); // expected-error {{deleted constructor}}
|
||||
Noncopyable nc4((Noncopyable()));
|
||||
Noncopyable nc5 = {Noncopyable()};
|
||||
Noncopyable nc6{Noncopyable()};
|
||||
|
||||
NoncopyableAggr nca1 = NoncopyableAggr{};
|
||||
NoncopyableAggr nca2 = NoncopyableAggr{{}};
|
||||
NoncopyableAggr nca3 = NoncopyableAggr{NoncopyableAggr{Noncopyable()}};
|
||||
|
||||
template<typename T> struct Convert { operator T(); }; // expected-note 1+{{candidate}}
|
||||
Noncopyable conv1 = Convert<Noncopyable>();
|
||||
Noncopyable conv2((Convert<Noncopyable>()));
|
||||
Noncopyable conv3 = {Convert<Noncopyable>()};
|
||||
Noncopyable conv4{Convert<Noncopyable>()};
|
||||
|
||||
Noncopyable ref_conv1 = Convert<Noncopyable&>(); // expected-error {{deleted constructor}}
|
||||
Noncopyable ref_conv2((Convert<Noncopyable&>())); // expected-error {{deleted constructor}}
|
||||
Noncopyable ref_conv3 = {Convert<Noncopyable&>()}; // expected-error {{deleted constructor}}
|
||||
Noncopyable ref_conv4{Convert<Noncopyable&>()}; // expected-error {{deleted constructor}}
|
||||
|
||||
Noncopyable derived_conv1 = Convert<Derived>(); // expected-error {{deleted constructor}}
|
||||
Noncopyable derived_conv2((Convert<Derived>())); // expected-error {{deleted constructor}}
|
||||
Noncopyable derived_conv3 = {Convert<Derived>()}; // expected-error {{deleted constructor}}
|
||||
Noncopyable derived_conv4{Convert<Derived>()}; // expected-error {{deleted constructor}}
|
||||
|
||||
NoncopyableAggr nc_aggr1 = Convert<NoncopyableAggr>();
|
||||
NoncopyableAggr nc_aggr2((Convert<NoncopyableAggr>()));
|
||||
NoncopyableAggr nc_aggr3 = {Convert<NoncopyableAggr>()}; // expected-error {{no viable conversion}}
|
||||
NoncopyableAggr nc_aggr4{Convert<NoncopyableAggr>()}; // expected-error {{no viable conversion}}
|
||||
NoncopyableAggr nc_aggr5 = Convert<Noncopyable>(); // expected-error {{no viable}}
|
||||
NoncopyableAggr nc_aggr6((Convert<Noncopyable>())); // expected-error {{no matching constructor}}
|
||||
NoncopyableAggr nc_aggr7 = {Convert<Noncopyable>()};
|
||||
NoncopyableAggr nc_aggr8{Convert<Noncopyable>()};
|
||||
|
||||
void test_expressions(bool b) {
|
||||
auto lambda = [a = make()] {};
|
||||
|
||||
|
|
Loading…
Reference in New Issue