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:
Richard Smith 2017-09-26 18:37:55 +00:00
parent afd34c6df7
commit 67ef14fe48
6 changed files with 186 additions and 58 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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.

View File

@ -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())

View File

@ -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,

View File

@ -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()] {};