r314231 - Resolve a defect in C++17 copy omission.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 26 11:37:55 PDT 2017
Author: rsmith
Date: Tue Sep 26 11:37:55 2017
New Revision: 314231
URL: http://llvm.org/viewvc/llvm-project?rev=314231&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/Sema/Overload.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaCodeComplete.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp
Modified: cfe/trunk/include/clang/Sema/Overload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Overload.h (original)
+++ cfe/trunk/include/clang/Sema/Overload.h Tue Sep 26 11:37:55 2017
@@ -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;
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Sep 26 11:37:55 2017
@@ -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,
Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Tue Sep 26 11:37:55 2017
@@ -4293,7 +4293,8 @@ static void mergeCandidatesWithResults(S
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.
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Sep 26 11:37:55 2017
@@ -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, Sour
}
}
+ // 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
// 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
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
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
// 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 TryRefInitWithC
// 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 TryRefInitWithC
// 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(Sem
// 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(Sem
// 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 CheckCXX98CompatAccessibleCo
// 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(Se
<< 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::DeduceTemplateSpecializat
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())
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Sep 26 11:37:55 2017
@@ -837,12 +837,13 @@ void OverloadCandidateSet::destroyCandid
}
}
-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(S
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(S
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 *F
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 *F
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 *F
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, Implic
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, Implic
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(CXXConversi
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(CXXConversi
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(Fun
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(Fun
// 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(c
/// 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(Se
// 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(Se
// 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::diagnoseEquivalentInternalLin
/// \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
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
// 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 CompareOverloadCandidatesForDispl
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 CompareOverloadCandidatesForDispl
// 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::NoteCandidate
}
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
// 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(SourceLo
Expr *Range, ExprResult *CallExpr) {
Scope *S = nullptr;
- CandidateSet->clear();
+ CandidateSet->clear(OverloadCandidateSet::CSK_Normal);
if (!MemberLookup.empty()) {
ExprResult MemberRef =
BuildMemberReferenceExpr(Range, Range->getType(), Loc,
Modified: cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp Tue Sep 26 11:37:55 2017
@@ -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()] {};
More information about the cfe-commits
mailing list