forked from OSchip/llvm-project
Allow reference binding of a reference of Objective-C object type to
an lvalue of another, compatible Objective-C object type (e.g., a subclass). Introduce a new initialization sequence step kind to describe this binding, along with a new cast kind. Fixes PR7741. llvm-svn: 110513
This commit is contained in:
parent
be05173105
commit
8b2d2fe234
|
@ -1251,7 +1251,8 @@ public:
|
|||
bool areComparableObjCPointerTypes(QualType LHS, QualType RHS);
|
||||
QualType areCommonBaseCompatible(const ObjCObjectPointerType *LHSOPT,
|
||||
const ObjCObjectPointerType *RHSOPT);
|
||||
|
||||
bool canBindObjCObjectType(QualType To, QualType From);
|
||||
|
||||
// Functions for calculating composite types
|
||||
QualType mergeTypes(QualType, QualType, bool OfBlockPointer=false,
|
||||
bool Unqualified = false);
|
||||
|
|
|
@ -1927,8 +1927,12 @@ public:
|
|||
CK_AnyPointerToObjCPointerCast,
|
||||
/// CK_AnyPointerToBlockPointerCast - Casting any pointer to block
|
||||
/// pointer
|
||||
CK_AnyPointerToBlockPointerCast
|
||||
CK_AnyPointerToBlockPointerCast,
|
||||
|
||||
/// \brief Converting between two Objective-C object types, which
|
||||
/// can occur when performing reference binding to an Objective-C
|
||||
/// object.
|
||||
CK_ObjCObjectLValueCast
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -1970,6 +1974,7 @@ private:
|
|||
case CK_MemberPointerToBoolean:
|
||||
case CK_AnyPointerToObjCPointerCast:
|
||||
case CK_AnyPointerToBlockPointerCast:
|
||||
case CK_ObjCObjectLValueCast:
|
||||
assert(path_empty() && "Cast kind should not have a base path!");
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -917,6 +917,7 @@ public:
|
|||
bool isObjCQualifiedInterfaceType() const; // NSString<foo>
|
||||
bool isObjCQualifiedIdType() const; // id<foo>
|
||||
bool isObjCQualifiedClassType() const; // Class<foo>
|
||||
bool isObjCObjectOrInterfaceType() const;
|
||||
bool isObjCIdType() const; // id
|
||||
bool isObjCClassType() const; // Class
|
||||
bool isObjCSelType() const; // Class
|
||||
|
@ -3506,6 +3507,11 @@ inline bool Type::isObjCObjectPointerType() const {
|
|||
inline bool Type::isObjCObjectType() const {
|
||||
return isa<ObjCObjectType>(CanonicalType);
|
||||
}
|
||||
inline bool Type::isObjCObjectOrInterfaceType() const {
|
||||
return isa<ObjCInterfaceType>(CanonicalType) ||
|
||||
isa<ObjCObjectType>(CanonicalType);
|
||||
}
|
||||
|
||||
inline bool Type::isObjCQualifiedIdType() const {
|
||||
if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>())
|
||||
return OPT->isObjCQualifiedIdType();
|
||||
|
|
|
@ -4560,6 +4560,12 @@ bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
|
|||
canAssignObjCInterfaces(RHSOPT, LHSOPT);
|
||||
}
|
||||
|
||||
bool ASTContext::canBindObjCObjectType(QualType To, QualType From) {
|
||||
return canAssignObjCInterfaces(
|
||||
getObjCObjectPointerType(To)->getAs<ObjCObjectPointerType>(),
|
||||
getObjCObjectPointerType(From)->getAs<ObjCObjectPointerType>());
|
||||
}
|
||||
|
||||
/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible,
|
||||
/// both shall have the identically qualified version of a compatible type.
|
||||
/// C99 6.2.7p1: Two types have compatible types if their types are the
|
||||
|
|
|
@ -717,6 +717,8 @@ const char *CastExpr::getCastKindName() const {
|
|||
return "AnyPointerToObjCPointerCast";
|
||||
case CastExpr::CK_AnyPointerToBlockPointerCast:
|
||||
return "AnyPointerToBlockPointerCast";
|
||||
case CastExpr::CK_ObjCObjectLValueCast:
|
||||
return "ObjCObjectLValueCast";
|
||||
}
|
||||
|
||||
assert(0 && "Unhandled cast kind!");
|
||||
|
|
|
@ -2514,7 +2514,8 @@ void GRExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
case CastExpr::CK_AnyPointerToObjCPointerCast:
|
||||
case CastExpr::CK_AnyPointerToBlockPointerCast:
|
||||
case CastExpr::CK_DerivedToBase:
|
||||
case CastExpr::CK_UncheckedDerivedToBase: {
|
||||
case CastExpr::CK_UncheckedDerivedToBase:
|
||||
case CastExpr::CK_ObjCObjectLValueCast: {
|
||||
// Delegate to SValuator to process.
|
||||
for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
|
||||
ExplodedNode* N = *I;
|
||||
|
|
|
@ -1851,6 +1851,13 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
|
|||
ConvertType(CE->getTypeAsWritten()));
|
||||
return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
|
||||
}
|
||||
case CastExpr::CK_ObjCObjectLValueCast: {
|
||||
LValue LV = EmitLValue(E->getSubExpr());
|
||||
QualType ToType = getContext().getLValueReferenceType(E->getType());
|
||||
llvm::Value *V = Builder.CreateBitCast(LV.getAddress(),
|
||||
ConvertType(ToType));
|
||||
return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
|
||||
}
|
||||
}
|
||||
|
||||
llvm_unreachable("Unhandled lvalue cast kind?");
|
||||
|
|
|
@ -925,7 +925,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
|
|||
//assert(0 && "Unknown cast kind!");
|
||||
break;
|
||||
|
||||
case CastExpr::CK_LValueBitCast: {
|
||||
case CastExpr::CK_LValueBitCast:
|
||||
case CastExpr::CK_ObjCObjectLValueCast: {
|
||||
Value *V = EmitLValue(E).getAddress();
|
||||
V = Builder.CreateBitCast(V,
|
||||
ConvertType(CGF.getContext().getPointerType(DestTy)));
|
||||
|
@ -1044,7 +1045,10 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
|
|||
return Builder.CreatePtrToInt(Src, ConvertType(DestTy));
|
||||
}
|
||||
case CastExpr::CK_ToVoid: {
|
||||
CGF.EmitAnyExpr(E, 0, false, true);
|
||||
if (E->Classify(CGF.getContext()).isGLValue())
|
||||
CGF.EmitLValue(E);
|
||||
else
|
||||
CGF.EmitAnyExpr(E, 0, false, true);
|
||||
return 0;
|
||||
}
|
||||
case CastExpr::CK_VectorSplat: {
|
||||
|
|
|
@ -4517,7 +4517,8 @@ public:
|
|||
|
||||
ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc,
|
||||
QualType T1, QualType T2,
|
||||
bool& DerivedToBase);
|
||||
bool &DerivedToBase,
|
||||
bool &ObjCConversion);
|
||||
|
||||
/// CheckCastTypes - Check type constraints for casting between types under
|
||||
/// C semantics, or forward to CXXCheckCStyleCast in C++.
|
||||
|
|
|
@ -646,9 +646,10 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,
|
|||
// this is the only cast possibility, so we issue an error if we fail now.
|
||||
// FIXME: Should allow casting away constness if CStyle.
|
||||
bool DerivedToBase;
|
||||
bool ObjCConversion;
|
||||
if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(),
|
||||
SrcExpr->getType(), R->getPointeeType(),
|
||||
DerivedToBase) <
|
||||
DerivedToBase, ObjCConversion) <
|
||||
Sema::Ref_Compatible_With_Added_Qualification) {
|
||||
msg = diag::err_bad_lvalue_to_rvalue_cast;
|
||||
return TC_Failed;
|
||||
|
|
|
@ -2035,6 +2035,7 @@ void InitializationSequence::Step::Destroy() {
|
|||
case SK_ZeroInitialization:
|
||||
case SK_CAssignment:
|
||||
case SK_StringInit:
|
||||
case SK_ObjCObjectConversion:
|
||||
break;
|
||||
|
||||
case SK_ConversionSequence:
|
||||
|
@ -2201,6 +2202,13 @@ void InitializationSequence::AddStringInitStep(QualType T) {
|
|||
Steps.push_back(S);
|
||||
}
|
||||
|
||||
void InitializationSequence::AddObjCObjectConversionStep(QualType T) {
|
||||
Step S;
|
||||
S.Kind = SK_ObjCObjectConversion;
|
||||
S.Type = T;
|
||||
Steps.push_back(S);
|
||||
}
|
||||
|
||||
void InitializationSequence::SetOverloadFailure(FailureKind Failure,
|
||||
OverloadingResult Result) {
|
||||
SequenceKind = FailedSequence;
|
||||
|
@ -2275,10 +2283,13 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
|
|||
QualType T2 = cv2T2.getUnqualifiedType();
|
||||
|
||||
bool DerivedToBase;
|
||||
bool ObjCConversion;
|
||||
assert(!S.CompareReferenceRelationship(Initializer->getLocStart(),
|
||||
T1, T2, DerivedToBase) &&
|
||||
T1, T2, DerivedToBase,
|
||||
ObjCConversion) &&
|
||||
"Must have incompatible references when binding via conversion");
|
||||
(void)DerivedToBase;
|
||||
(void)ObjCConversion;
|
||||
|
||||
// Build the candidate set directly in the initialization sequence
|
||||
// structure, so that it will persist if we fail.
|
||||
|
@ -2400,10 +2411,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
|
|||
ImplicitCastExpr::LValue : ImplicitCastExpr::XValue;
|
||||
|
||||
bool NewDerivedToBase = false;
|
||||
bool NewObjCConversion = false;
|
||||
Sema::ReferenceCompareResult NewRefRelationship
|
||||
= S.CompareReferenceRelationship(DeclLoc, T1,
|
||||
T2.getNonLValueExprType(S.Context),
|
||||
NewDerivedToBase);
|
||||
NewDerivedToBase, NewObjCConversion);
|
||||
if (NewRefRelationship == Sema::Ref_Incompatible) {
|
||||
// If the type we've converted to is not reference-related to the
|
||||
// type we're looking for, then there is another conversion step
|
||||
|
@ -2418,8 +2430,12 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
|
|||
Sequence.AddDerivedToBaseCastStep(
|
||||
S.Context.getQualifiedType(T1,
|
||||
T2.getNonReferenceType().getQualifiers()),
|
||||
Category);
|
||||
|
||||
Category);
|
||||
else if (NewObjCConversion)
|
||||
Sequence.AddObjCObjectConversionStep(
|
||||
S.Context.getQualifiedType(T1,
|
||||
T2.getNonReferenceType().getQualifiers()));
|
||||
|
||||
if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers())
|
||||
Sequence.AddQualificationConversionStep(cv1T1, Category);
|
||||
|
||||
|
@ -2467,9 +2483,11 @@ static void TryReferenceInitialization(Sema &S,
|
|||
bool isLValueRef = DestType->isLValueReferenceType();
|
||||
bool isRValueRef = !isLValueRef;
|
||||
bool DerivedToBase = false;
|
||||
bool ObjCConversion = false;
|
||||
Expr::Classification InitCategory = Initializer->Classify(S.Context);
|
||||
Sema::ReferenceCompareResult RefRelationship
|
||||
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase);
|
||||
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase,
|
||||
ObjCConversion);
|
||||
|
||||
// C++0x [dcl.init.ref]p5:
|
||||
// A reference to type "cv1 T1" is initialized by an expression of type
|
||||
|
@ -2497,6 +2515,10 @@ static void TryReferenceInitialization(Sema &S,
|
|||
Sequence.AddDerivedToBaseCastStep(
|
||||
S.Context.getQualifiedType(T1, T2Quals),
|
||||
ImplicitCastExpr::LValue);
|
||||
else if (ObjCConversion)
|
||||
Sequence.AddObjCObjectConversionStep(
|
||||
S.Context.getQualifiedType(T1, T2Quals));
|
||||
|
||||
if (T1Quals != T2Quals)
|
||||
Sequence.AddQualificationConversionStep(cv1T1,ImplicitCastExpr::LValue);
|
||||
bool BindingTemporary = T1Quals.hasConst() && !T1Quals.hasVolatile() &&
|
||||
|
@ -2577,6 +2599,10 @@ static void TryReferenceInitialization(Sema &S,
|
|||
S.Context.getQualifiedType(T1, T2Quals),
|
||||
isXValue ? ImplicitCastExpr::XValue
|
||||
: ImplicitCastExpr::RValue);
|
||||
else if (ObjCConversion)
|
||||
Sequence.AddObjCObjectConversionStep(
|
||||
S.Context.getQualifiedType(T1, T2Quals));
|
||||
|
||||
if (T1Quals != T2Quals)
|
||||
Sequence.AddQualificationConversionStep(cv1T1,
|
||||
isXValue ? ImplicitCastExpr::XValue
|
||||
|
@ -3546,6 +3572,7 @@ InitializationSequence::Perform(Sema &S,
|
|||
case SK_ListInitialization:
|
||||
case SK_CAssignment:
|
||||
case SK_StringInit:
|
||||
case SK_ObjCObjectConversion:
|
||||
assert(Args.size() == 1);
|
||||
CurInit = Sema::OwningExprResult(S, ((Expr **)(Args.get()))[0]->Retain());
|
||||
if (CurInit.isInvalid())
|
||||
|
@ -3926,6 +3953,14 @@ InitializationSequence::Perform(Sema &S,
|
|||
CheckStringInit(CurInitExpr, ResultType ? *ResultType : Ty, S);
|
||||
break;
|
||||
}
|
||||
|
||||
case SK_ObjCObjectConversion:
|
||||
S.ImpCastExprToType(CurInitExpr, Step->Type,
|
||||
CastExpr::CK_ObjCObjectLValueCast,
|
||||
S.CastCategory(CurInitExpr));
|
||||
CurInit.release();
|
||||
CurInit = S.Owned(CurInitExpr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4392,6 +4427,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
|
|||
case SK_StringInit:
|
||||
OS << "string initialization";
|
||||
break;
|
||||
|
||||
case SK_ObjCObjectConversion:
|
||||
OS << "Objective-C object conversion";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -479,7 +479,10 @@ public:
|
|||
/// \brief C assignment
|
||||
SK_CAssignment,
|
||||
/// \brief Initialization by string
|
||||
SK_StringInit
|
||||
SK_StringInit,
|
||||
/// \brief An initialization that "converts" an Objective-C object
|
||||
/// (not a point to an object) to another Objective-C object type.
|
||||
SK_ObjCObjectConversion
|
||||
};
|
||||
|
||||
/// \brief A single step in the initialization sequence.
|
||||
|
@ -737,6 +740,10 @@ public:
|
|||
/// \brief Add a string init step.
|
||||
void AddStringInitStep(QualType T);
|
||||
|
||||
/// \brief Add an Objective-C object conversion step, which is
|
||||
/// always a no-op.
|
||||
void AddObjCObjectConversionStep(QualType T);
|
||||
|
||||
/// \brief Note that this initialization sequence failed.
|
||||
void SetFailed(FailureKind Failure) {
|
||||
SequenceKind = FailedSequence;
|
||||
|
|
|
@ -2575,7 +2575,8 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
|
|||
Sema::ReferenceCompareResult
|
||||
Sema::CompareReferenceRelationship(SourceLocation Loc,
|
||||
QualType OrigT1, QualType OrigT2,
|
||||
bool& DerivedToBase) {
|
||||
bool &DerivedToBase,
|
||||
bool &ObjCConversion) {
|
||||
assert(!OrigT1->isReferenceType() &&
|
||||
"T1 must be the pointee type of the reference type");
|
||||
assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
|
||||
|
@ -2590,11 +2591,17 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
|
|||
// Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
|
||||
// reference-related to "cv2 T2" if T1 is the same type as T2, or
|
||||
// T1 is a base class of T2.
|
||||
if (UnqualT1 == UnqualT2)
|
||||
DerivedToBase = false;
|
||||
else if (!RequireCompleteType(Loc, OrigT2, PDiag()) &&
|
||||
DerivedToBase = false;
|
||||
ObjCConversion = false;
|
||||
if (UnqualT1 == UnqualT2) {
|
||||
// Nothing to do.
|
||||
} else if (!RequireCompleteType(Loc, OrigT2, PDiag()) &&
|
||||
IsDerivedFrom(UnqualT2, UnqualT1))
|
||||
DerivedToBase = true;
|
||||
else if (UnqualT1->isObjCObjectOrInterfaceType() &&
|
||||
UnqualT2->isObjCObjectOrInterfaceType() &&
|
||||
Context.canBindObjCObjectType(UnqualT1, UnqualT2))
|
||||
ObjCConversion = true;
|
||||
else
|
||||
return Ref_Incompatible;
|
||||
|
||||
|
@ -2741,9 +2748,11 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
|
|||
// Compute some basic properties of the types and the initializer.
|
||||
bool isRValRef = DeclType->isRValueReferenceType();
|
||||
bool DerivedToBase = false;
|
||||
bool ObjCConversion = false;
|
||||
Expr::Classification InitCategory = Init->Classify(S.Context);
|
||||
Sema::ReferenceCompareResult RefRelationship
|
||||
= S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase);
|
||||
= S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase,
|
||||
ObjCConversion);
|
||||
|
||||
|
||||
// C++0x [dcl.init.ref]p5:
|
||||
|
@ -2769,7 +2778,9 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
|
|||
// derived-to-base Conversion (13.3.3.1).
|
||||
ICS.setStandard();
|
||||
ICS.Standard.First = ICK_Identity;
|
||||
ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
|
||||
ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
|
||||
: ObjCConversion? ICK_Compatible_Conversion
|
||||
: ICK_Identity;
|
||||
ICS.Standard.Third = ICK_Identity;
|
||||
ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
|
||||
ICS.Standard.setToType(0, T2);
|
||||
|
@ -2857,7 +2868,9 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,
|
|||
RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {
|
||||
ICS.setStandard();
|
||||
ICS.Standard.First = ICK_Identity;
|
||||
ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
|
||||
ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
|
||||
: ObjCConversion? ICK_Compatible_Conversion
|
||||
: ICK_Identity;
|
||||
ICS.Standard.Third = ICK_Identity;
|
||||
ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
|
||||
ICS.Standard.setToType(0, T2);
|
||||
|
|
|
@ -24,3 +24,22 @@ struct A { ~A(); };
|
|||
void f(B* b) {
|
||||
(void)[b getA];
|
||||
}
|
||||
|
||||
// PR7741
|
||||
@protocol P1 @end
|
||||
@protocol P2 @end
|
||||
@protocol P3 @end
|
||||
@interface foo<P1> {} @end
|
||||
@interface bar : foo <P1, P2> {} @end
|
||||
typedef bar baz;
|
||||
void f5(foo&);
|
||||
void f5b(foo<P1>&);
|
||||
void f5c(foo<P2>&);
|
||||
void f5d(foo<P3>&);
|
||||
void f6(baz* x) {
|
||||
f5(*x);
|
||||
f5b(*x);
|
||||
f5c(*x);
|
||||
f5d(*x);
|
||||
(void)((foo&)*x);
|
||||
}
|
||||
|
|
|
@ -31,3 +31,22 @@ void f3(id);
|
|||
void f4(NSString &tmpstr) {
|
||||
f3(&tmpstr);
|
||||
}
|
||||
|
||||
// PR7741
|
||||
@protocol P1 @end
|
||||
@protocol P2 @end
|
||||
@protocol P3 @end
|
||||
@interface foo<P1> {} @end
|
||||
@interface bar : foo <P1, P2> {} @end
|
||||
typedef bar baz;
|
||||
void f5(foo&);
|
||||
void f5b(foo<P1>&);
|
||||
void f5c(foo<P2>&);
|
||||
void f5d(foo<P3>&);
|
||||
void f6(baz* x) {
|
||||
f5(*x);
|
||||
f5b(*x);
|
||||
f5c(*x);
|
||||
f5d(*x);
|
||||
(void)((foo&)*x);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue