mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-04 00:06:50 +00:00
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:
parent
41bd8ac206
commit
6073dcab38
@ -365,17 +365,18 @@ class InitializationKind {
|
||||
public:
|
||||
/// \brief The kind of initialization being performed.
|
||||
enum InitKind {
|
||||
IK_Direct, ///< Direct initialization
|
||||
IK_DirectList, ///< Direct list-initialization
|
||||
IK_Copy, ///< Copy initialization
|
||||
IK_Default, ///< Default initialization
|
||||
IK_Value ///< Value initialization
|
||||
IK_Direct, ///< Direct initialization
|
||||
IK_DirectList, ///< Direct list-initialization
|
||||
IK_Copy, ///< Copy initialization
|
||||
IK_Default, ///< Default initialization
|
||||
IK_Value ///< Value initialization
|
||||
};
|
||||
|
||||
private:
|
||||
/// \brief The context of the initialization.
|
||||
enum InitContext {
|
||||
IC_Normal, ///< Normal context
|
||||
IC_ExplicitConvs, ///< Normal context, but allows explicit conversion funcs
|
||||
IC_Implicit, ///< Implicit context (value initialization)
|
||||
IC_StaticCast, ///< Static cast context
|
||||
IC_CStyleCast, ///< C-style cast context
|
||||
@ -442,8 +443,11 @@ public:
|
||||
|
||||
/// \brief Create a copy initialization.
|
||||
static InitializationKind CreateCopy(SourceLocation InitLoc,
|
||||
SourceLocation EqualLoc) {
|
||||
return InitializationKind(IK_Copy, IC_Normal, InitLoc, EqualLoc, EqualLoc);
|
||||
SourceLocation EqualLoc,
|
||||
bool AllowExplicitConvs = false) {
|
||||
return InitializationKind(IK_Copy,
|
||||
AllowExplicitConvs? IC_ExplicitConvs : IC_Normal,
|
||||
InitLoc, EqualLoc, EqualLoc);
|
||||
}
|
||||
|
||||
/// \brief Create a default initialization.
|
||||
@ -511,6 +515,12 @@ public:
|
||||
/// constructors.
|
||||
bool AllowExplicit() const { return !isCopyInit(); }
|
||||
|
||||
/// \brief Retrieve whether this initialization allows the use of explicit
|
||||
/// conversion functions.
|
||||
bool allowExplicitConversionFunctions() const {
|
||||
return !isCopyInit() || Context == IC_ExplicitConvs;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the source range containing the locations of the open
|
||||
/// and closing parentheses for value and direct initializations.
|
||||
SourceRange getParenRange() const {
|
||||
|
@ -1458,7 +1458,8 @@ public:
|
||||
ExprResult PerformCopyInitialization(const InitializedEntity &Entity,
|
||||
SourceLocation EqualLoc,
|
||||
ExprResult Init,
|
||||
bool TopLevelOfInitList = false);
|
||||
bool TopLevelOfInitList = false,
|
||||
bool AllowExplicit = false);
|
||||
ExprResult PerformObjectArgumentInitialization(Expr *From,
|
||||
NestedNameSpecifier *Qualifier,
|
||||
NamedDecl *FoundDecl,
|
||||
@ -1502,7 +1503,8 @@ public:
|
||||
Expr **Args, unsigned NumArgs,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions = false,
|
||||
bool PartialOverloading = false);
|
||||
bool PartialOverloading = false,
|
||||
bool AllowExplicit = false);
|
||||
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
@ -3128,7 +3130,8 @@ public:
|
||||
bool CompleteConstructorCall(CXXConstructorDecl *Constructor,
|
||||
MultiExprArg ArgsPtr,
|
||||
SourceLocation Loc,
|
||||
ASTOwningVector<Expr*> &ConvertedArgs);
|
||||
ASTOwningVector<Expr*> &ConvertedArgs,
|
||||
bool AllowExplicit = false);
|
||||
|
||||
ParsedType getDestructorName(SourceLocation TildeLoc,
|
||||
IdentifierInfo &II, SourceLocation NameLoc,
|
||||
@ -5911,7 +5914,8 @@ public:
|
||||
unsigned FirstProtoArg,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SmallVector<Expr *, 8> &AllArgs,
|
||||
VariadicCallType CallType = VariadicDoesNotApply);
|
||||
VariadicCallType CallType = VariadicDoesNotApply,
|
||||
bool AllowExplicit = false);
|
||||
|
||||
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
|
||||
// will warn if the resulting type is not a POD type.
|
||||
|
@ -9032,7 +9032,8 @@ bool
|
||||
Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
|
||||
MultiExprArg ArgsPtr,
|
||||
SourceLocation Loc,
|
||||
ASTOwningVector<Expr*> &ConvertedArgs) {
|
||||
ASTOwningVector<Expr*> &ConvertedArgs,
|
||||
bool AllowExplicit) {
|
||||
// FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
|
||||
unsigned NumArgs = ArgsPtr.size();
|
||||
Expr **Args = (Expr **)ArgsPtr.get();
|
||||
@ -9053,7 +9054,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
|
||||
SmallVector<Expr *, 8> AllArgs;
|
||||
bool Invalid = GatherArgumentsForCall(Loc, Constructor,
|
||||
Proto, 0, Args, NumArgs, AllArgs,
|
||||
CallType);
|
||||
CallType, AllowExplicit);
|
||||
ConvertedArgs.append(AllArgs.begin(), AllArgs.end());
|
||||
|
||||
DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());
|
||||
|
@ -3248,7 +3248,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
|
||||
unsigned FirstProtoArg,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SmallVector<Expr *, 8> &AllArgs,
|
||||
VariadicCallType CallType) {
|
||||
VariadicCallType CallType,
|
||||
bool AllowExplicit) {
|
||||
unsigned NumArgsInProto = Proto->getNumArgs();
|
||||
unsigned NumArgsToCheck = NumArgs;
|
||||
bool Invalid = false;
|
||||
@ -3288,7 +3289,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
|
||||
Proto->isArgConsumed(i));
|
||||
ExprResult ArgE = PerformCopyInitialization(Entity,
|
||||
SourceLocation(),
|
||||
Owned(Arg));
|
||||
Owned(Arg),
|
||||
/*TopLevelOfInitList=*/false,
|
||||
AllowExplicit);
|
||||
if (ArgE.isInvalid())
|
||||
return true;
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -4213,7 +4213,8 @@ static ImplicitConversionSequence
|
||||
TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
|
||||
bool SuppressUserConversions,
|
||||
bool InOverloadResolution,
|
||||
bool AllowObjCWritebackConversion);
|
||||
bool AllowObjCWritebackConversion,
|
||||
bool AllowExplicit = false);
|
||||
|
||||
/// TryListConversion - Try to copy-initialize a value of type ToType from the
|
||||
/// initializer list From.
|
||||
@ -4413,7 +4414,8 @@ static ImplicitConversionSequence
|
||||
TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
|
||||
bool SuppressUserConversions,
|
||||
bool InOverloadResolution,
|
||||
bool AllowObjCWritebackConversion) {
|
||||
bool AllowObjCWritebackConversion,
|
||||
bool AllowExplicit) {
|
||||
if (InitListExpr *FromInitList = dyn_cast<InitListExpr>(From))
|
||||
return TryListConversion(S, FromInitList, ToType, SuppressUserConversions,
|
||||
InOverloadResolution,AllowObjCWritebackConversion);
|
||||
@ -4422,7 +4424,7 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType,
|
||||
return TryReferenceInit(S, From, ToType,
|
||||
/*FIXME:*/From->getLocStart(),
|
||||
SuppressUserConversions,
|
||||
/*AllowExplicit=*/false);
|
||||
AllowExplicit);
|
||||
|
||||
return TryImplicitConversion(S, From, ToType,
|
||||
SuppressUserConversions,
|
||||
@ -5103,7 +5105,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
OverloadCandidateSet& CandidateSet,
|
||||
bool SuppressUserConversions,
|
||||
bool PartialOverloading) {
|
||||
bool PartialOverloading,
|
||||
bool AllowExplicit) {
|
||||
const FunctionProtoType* Proto
|
||||
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
|
||||
assert(Proto && "Functions without a prototype cannot be overloaded");
|
||||
@ -5204,7 +5207,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
|
||||
SuppressUserConversions,
|
||||
/*InOverloadResolution=*/true,
|
||||
/*AllowObjCWritebackConversion=*/
|
||||
getLangOptions().ObjCAutoRefCount);
|
||||
getLangOptions().ObjCAutoRefCount,
|
||||
AllowExplicit);
|
||||
if (Candidate.Conversions[ArgIdx].isBad()) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_bad_conversion;
|
||||
|
@ -0,0 +1,15 @@
|
||||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify
|
||||
|
||||
namespace ExplicitConv {
|
||||
struct X { }; // expected-note 2{{candidate constructor}}
|
||||
|
||||
struct Y {
|
||||
explicit operator X() const;
|
||||
};
|
||||
|
||||
void test(const Y& y) {
|
||||
X x(static_cast<X>(y));
|
||||
X x2((X)y);
|
||||
X x3 = y; // expected-error{{no viable conversion from 'const ExplicitConv::Y' to 'ExplicitConv::X'}}
|
||||
}
|
||||
}
|
@ -43,16 +43,8 @@ namespace Conversion {
|
||||
class Y { }; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y &' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}} \
|
||||
expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}} \
|
||||
expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'Conversion::Z' to 'const Conversion::Y' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}} \
|
||||
expected-note {{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
|
||||
expected-note {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'Conversion::Z' to 'Conversion::Y &&' for 1st argument}}
|
||||
|
||||
struct Z {
|
||||
explicit operator Y() const;
|
||||
explicit operator int() const;
|
||||
@ -61,10 +53,9 @@ namespace Conversion {
|
||||
Z z;
|
||||
// 13.3.1.4p1 & 8.5p16:
|
||||
Y y2 = z; // expected-error {{no viable conversion from 'Conversion::Z' to 'Conversion::Y'}}
|
||||
// FIXME: These are well-formed per C++0x 13.3.1.4p1 (see DR899).
|
||||
Y y3 = (Y)z; // expected-error {{no matching conversion for C-style cast from 'Conversion::Z' to 'Conversion::Y'}}
|
||||
Y y4 = Y(z); // expected-error {{no matching conversion for functional-style cast from 'Conversion::Z' to 'Conversion::Y'}}
|
||||
Y y5 = static_cast<Y>(z); // expected-error {{no matching conversion for static_cast from 'Conversion::Z' to 'Conversion::Y'}}
|
||||
Y y3 = (Y)z;
|
||||
Y y4 = Y(z);
|
||||
Y y5 = static_cast<Y>(z);
|
||||
// 13.3.1.5p1 & 8.5p16:
|
||||
int i1 = (int)z;
|
||||
int i2 = int(z);
|
||||
|
Loading…
x
Reference in New Issue
Block a user