Implement C++11 [over.match.copy]p1b2, which allows the use of

explicit conversion functions to initialize the argument to a
copy/move constructor that itself is the subject of direct
initialization. Since we don't have that much context in overload
resolution, we end up threading more flags :(.

Fixes <rdar://problem/10903741> / PR10456. 

llvm-svn: 151409
This commit is contained in:
Douglas Gregor
2012-02-24 23:56:31 +00:00
parent 41bd8ac206
commit 6073dcab38
8 changed files with 97 additions and 43 deletions

View File

@@ -2827,10 +2827,22 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
/*ExplicitArgs*/ 0,
Args, NumArgs, CandidateSet,
SuppressUserConversions);
else
else {
// C++ [over.match.copy]p1:
// - When initializing a temporary to be bound to the first parameter
// of a constructor that takes a reference to possibly cv-qualified
// T as its first argument, called with a single argument in the
// context of direct-initialization, explicit conversion functions
// are also considered.
bool AllowExplicitConv = AllowExplicit && !CopyInitializing &&
NumArgs == 1 &&
Constructor->isCopyOrMoveConstructor();
S.AddOverloadCandidate(Constructor, FoundDecl,
Args, NumArgs, CandidateSet,
SuppressUserConversions);
SuppressUserConversions,
/*PartialOverloading=*/false,
/*AllowExplicit=*/AllowExplicitConv);
}
}
}
@@ -3122,8 +3134,8 @@ static void TryListInitialization(Sema &S,
static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr *Initializer,
bool AllowRValues,
Expr *Initializer,
bool AllowRValues,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
@@ -3151,7 +3163,8 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// Determine whether we are allowed to call explicit constructors or
// explicit conversion operators.
bool AllowExplicit = Kind.AllowExplicit();
bool AllowExplicitConvs = Kind.allowExplicitConversionFunctions();
const RecordType *T1RecordType = 0;
if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) &&
!S.RequireCompleteType(Kind.getLocation(), T1, 0)) {
@@ -3220,7 +3233,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// FIXME: Do we need to make sure that we only consider conversion
// candidates with reference-compatible results? That might be needed to
// break recursion.
if ((AllowExplicit || !Conv->isExplicit()) &&
if ((AllowExplicitConvs || !Conv->isExplicit()) &&
(AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
if (ConvTemplate)
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
@@ -4636,10 +4649,21 @@ PerformConstructorInitialization(Sema &S,
ExprResult CurInit = S.Owned((Expr *)0);
// C++ [over.match.copy]p1:
// - When initializing a temporary to be bound to the first parameter
// of a constructor that takes a reference to possibly cv-qualified
// T as its first argument, called with a single argument in the
// context of direct-initialization, explicit conversion functions
// are also considered.
bool AllowExplicitConv = Kind.AllowExplicit() && !Kind.isCopyInit() &&
Args.size() == 1 &&
Constructor->isCopyOrMoveConstructor();
// Determine the arguments required to actually perform the constructor
// call.
if (S.CompleteConstructorCall(Constructor, move(Args),
Loc, ConstructorArgs))
Loc, ConstructorArgs,
AllowExplicitConv))
return ExprError();
@@ -6097,7 +6121,8 @@ ExprResult
Sema::PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
ExprResult Init,
bool TopLevelOfInitList) {
bool TopLevelOfInitList,
bool AllowExplicit) {
if (Init.isInvalid())
return ExprError();
@@ -6108,7 +6133,8 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity,
EqualLoc = InitE->getLocStart();
InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(),
EqualLoc);
EqualLoc,
AllowExplicit);
InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
Init.release();