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);
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:
case CK_MemberPointerToBoolean:
case CK_AnyPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
+ case CK_ObjCObjectLValueCast:
assert(path_empty() && "Cast kind should not have a base path!");
break;
}
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
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();
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
return "AnyPointerToObjCPointerCast";
case CastExpr::CK_AnyPointerToBlockPointerCast:
return "AnyPointerToBlockPointerCast";
+ case CastExpr::CK_ObjCObjectLValueCast:
+ return "ObjCObjectLValueCast";
}
assert(0 && "Unhandled cast kind!");
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;
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?");
//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)));
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: {
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++.
// 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;
case SK_ZeroInitialization:
case SK_CAssignment:
case SK_StringInit:
+ case SK_ObjCObjectConversion:
break;
case SK_ConversionSequence:
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;
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.
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
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);
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
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() &&
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
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())
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;
}
}
case SK_StringInit:
OS << "string initialization";
break;
+
+ case SK_ObjCObjectConversion:
+ OS << "Objective-C object conversion";
+ break;
}
}
}
/// \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.
/// \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;
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");
// 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;
// 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:
// 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);
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);
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);
+}
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);
+}