зеркало из https://github.com/microsoft/clang-1.git
Support more implicit conversions for Objective-C types. Addresses <rdar://problem/6458293>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61255 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
e4bb68a475
Коммит
c788751123
|
@ -383,6 +383,8 @@ public:
|
||||||
bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
|
bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
|
||||||
bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
|
bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
|
||||||
QualType& ConvertedType, bool &IncompatibleObjC);
|
QualType& ConvertedType, bool &IncompatibleObjC);
|
||||||
|
bool isObjCPointerConversion(QualType FromType, QualType ToType,
|
||||||
|
QualType& ConvertedType, bool &IncompatibleObjC);
|
||||||
bool CheckPointerConversion(Expr *From, QualType ToType);
|
bool CheckPointerConversion(Expr *From, QualType ToType);
|
||||||
bool IsQualificationConversion(QualType FromType, QualType ToType);
|
bool IsQualificationConversion(QualType FromType, QualType ToType);
|
||||||
bool IsUserDefinedConversion(Expr *From, QualType ToType,
|
bool IsUserDefinedConversion(Expr *From, QualType ToType,
|
||||||
|
|
|
@ -763,6 +763,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
|
||||||
bool &IncompatibleObjC)
|
bool &IncompatibleObjC)
|
||||||
{
|
{
|
||||||
IncompatibleObjC = false;
|
IncompatibleObjC = false;
|
||||||
|
if (isObjCPointerConversion(FromType, ToType, ConvertedType, IncompatibleObjC))
|
||||||
|
return true;
|
||||||
|
|
||||||
// Blocks: Block pointers can be converted to void*.
|
// Blocks: Block pointers can be converted to void*.
|
||||||
if (FromType->isBlockPointerType() && ToType->isPointerType() &&
|
if (FromType->isBlockPointerType() && ToType->isPointerType() &&
|
||||||
|
@ -777,13 +779,6 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conversions with Objective-C's id<...>.
|
|
||||||
if ((FromType->isObjCQualifiedIdType() || ToType->isObjCQualifiedIdType()) &&
|
|
||||||
ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
|
|
||||||
ConvertedType = ToType;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PointerType* ToTypePtr = ToType->getAsPointerType();
|
const PointerType* ToTypePtr = ToType->getAsPointerType();
|
||||||
if (!ToTypePtr)
|
if (!ToTypePtr)
|
||||||
return false;
|
return false;
|
||||||
|
@ -805,7 +800,8 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
|
||||||
// An rvalue of type "pointer to cv T," where T is an object type,
|
// An rvalue of type "pointer to cv T," where T is an object type,
|
||||||
// can be converted to an rvalue of type "pointer to cv void" (C++
|
// can be converted to an rvalue of type "pointer to cv void" (C++
|
||||||
// 4.10p2).
|
// 4.10p2).
|
||||||
if (FromPointeeType->isIncompleteOrObjectType() && ToPointeeType->isVoidType()) {
|
if (FromPointeeType->isIncompleteOrObjectType() &&
|
||||||
|
ToPointeeType->isVoidType()) {
|
||||||
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
|
ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
|
||||||
ToPointeeType,
|
ToPointeeType,
|
||||||
ToType, Context);
|
ToType, Context);
|
||||||
|
@ -833,6 +829,37 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// isObjCPointerConversion - Determines whether this is an
|
||||||
|
/// Objective-C pointer conversion. Subroutine of IsPointerConversion,
|
||||||
|
/// with the same arguments and return values.
|
||||||
|
bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
|
||||||
|
QualType& ConvertedType,
|
||||||
|
bool &IncompatibleObjC) {
|
||||||
|
if (!getLangOptions().ObjC1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Conversions with Objective-C's id<...>.
|
||||||
|
if ((FromType->isObjCQualifiedIdType() || ToType->isObjCQualifiedIdType()) &&
|
||||||
|
ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
|
||||||
|
ConvertedType = ToType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PointerType* ToTypePtr = ToType->getAsPointerType();
|
||||||
|
if (!ToTypePtr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Beyond this point, both types need to be pointers.
|
||||||
|
const PointerType *FromTypePtr = FromType->getAsPointerType();
|
||||||
|
if (!FromTypePtr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QualType FromPointeeType = FromTypePtr->getPointeeType();
|
||||||
|
QualType ToPointeeType = ToTypePtr->getPointeeType();
|
||||||
|
|
||||||
// Objective C++: We're able to convert from a pointer to an
|
// Objective C++: We're able to convert from a pointer to an
|
||||||
// interface to a pointer to a different interface.
|
// interface to a pointer to a different interface.
|
||||||
const ObjCInterfaceType* FromIface = FromPointeeType->getAsObjCInterfaceType();
|
const ObjCInterfaceType* FromIface = FromPointeeType->getAsObjCInterfaceType();
|
||||||
|
@ -877,7 +904,81 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
// If we have pointers to pointers, recursively check whether this
|
||||||
|
// is an Objective-C conversion.
|
||||||
|
if (FromPointeeType->isPointerType() && ToPointeeType->isPointerType() &&
|
||||||
|
isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
|
||||||
|
IncompatibleObjC)) {
|
||||||
|
// We always complain about this conversion.
|
||||||
|
IncompatibleObjC = true;
|
||||||
|
ConvertedType = ToType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have pointers to functions, check whether the only
|
||||||
|
// differences in the argument and result types are in Objective-C
|
||||||
|
// pointer conversions. If so, we permit the conversion (but
|
||||||
|
// complain about it).
|
||||||
|
const FunctionTypeProto *FromFunctionType
|
||||||
|
= FromPointeeType->getAsFunctionTypeProto();
|
||||||
|
const FunctionTypeProto *ToFunctionType
|
||||||
|
= ToPointeeType->getAsFunctionTypeProto();
|
||||||
|
if (FromFunctionType && ToFunctionType) {
|
||||||
|
// If the function types are exactly the same, this isn't an
|
||||||
|
// Objective-C pointer conversion.
|
||||||
|
if (Context.getCanonicalType(FromPointeeType)
|
||||||
|
== Context.getCanonicalType(ToPointeeType))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Perform the quick checks that will tell us whether these
|
||||||
|
// function types are obviously different.
|
||||||
|
if (FromFunctionType->getNumArgs() != ToFunctionType->getNumArgs() ||
|
||||||
|
FromFunctionType->isVariadic() != ToFunctionType->isVariadic() ||
|
||||||
|
FromFunctionType->getTypeQuals() != ToFunctionType->getTypeQuals())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool HasObjCConversion = false;
|
||||||
|
if (Context.getCanonicalType(FromFunctionType->getResultType())
|
||||||
|
== Context.getCanonicalType(ToFunctionType->getResultType())) {
|
||||||
|
// Okay, the types match exactly. Nothing to do.
|
||||||
|
} else if (isObjCPointerConversion(FromFunctionType->getResultType(),
|
||||||
|
ToFunctionType->getResultType(),
|
||||||
|
ConvertedType, IncompatibleObjC)) {
|
||||||
|
// Okay, we have an Objective-C pointer conversion.
|
||||||
|
HasObjCConversion = true;
|
||||||
|
} else {
|
||||||
|
// Function types are too different. Abort.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check argument types.
|
||||||
|
for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs();
|
||||||
|
ArgIdx != NumArgs; ++ArgIdx) {
|
||||||
|
QualType FromArgType = FromFunctionType->getArgType(ArgIdx);
|
||||||
|
QualType ToArgType = ToFunctionType->getArgType(ArgIdx);
|
||||||
|
if (Context.getCanonicalType(FromArgType)
|
||||||
|
== Context.getCanonicalType(ToArgType)) {
|
||||||
|
// Okay, the types match exactly. Nothing to do.
|
||||||
|
} else if (isObjCPointerConversion(FromArgType, ToArgType,
|
||||||
|
ConvertedType, IncompatibleObjC)) {
|
||||||
|
// Okay, we have an Objective-C pointer conversion.
|
||||||
|
HasObjCConversion = true;
|
||||||
|
} else {
|
||||||
|
// Argument types are too different. Abort.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasObjCConversion) {
|
||||||
|
// We had an Objective-C conversion. Allow this pointer
|
||||||
|
// conversion, but complain about it.
|
||||||
|
ConvertedType = ToType;
|
||||||
|
IncompatibleObjC = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CheckPointerConversion - Check the pointer conversion from the
|
/// CheckPointerConversion - Check the pointer conversion from the
|
||||||
|
|
|
@ -45,9 +45,12 @@ void test(A* a, B* b, id val) {
|
||||||
// int& i3 = h(b); FIXME: we match GCC here, but shouldn't this work?
|
// int& i3 = h(b); FIXME: we match GCC here, but shouldn't this work?
|
||||||
}
|
}
|
||||||
|
|
||||||
void downcast_test(A* a) {
|
void downcast_test(A* a, A** ap) {
|
||||||
B* b = a; // expected-warning{{incompatible pointer types initializing 'B *', expected 'A *'}}
|
B* b = a; // expected-warning{{incompatible pointer types initializing 'B *', expected 'A *'}}
|
||||||
b = a; // expected-warning{{incompatible pointer types assigning 'B *', expected 'A *'}}
|
b = a; // expected-warning{{incompatible pointer types assigning 'B *', expected 'A *'}}
|
||||||
|
|
||||||
|
B** bp = ap; // expected-warning{{incompatible pointer types initializing 'B **', expected 'A **'}}
|
||||||
|
bp = ap; // expected-warning{{incompatible pointer types assigning 'B **', expected 'A **'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
int& cv(A*);
|
int& cv(A*);
|
||||||
|
@ -73,3 +76,15 @@ void qualid_test(A *a, B *b, C *c) {
|
||||||
int& i2 = qualid(b);
|
int& i2 = qualid(b);
|
||||||
float& f1 = qualid(c);
|
float& f1 = qualid(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@class NSException;
|
||||||
|
typedef struct {
|
||||||
|
void (*throw_exc)(id);
|
||||||
|
}
|
||||||
|
objc_exception_functions_t;
|
||||||
|
|
||||||
|
void (*_NSExceptionRaiser(void))(NSException *) {
|
||||||
|
objc_exception_functions_t exc_funcs;
|
||||||
|
return exc_funcs.throw_exc; // expected-warning{{incompatible pointer types returning 'void (*)(NSException *)', expected 'void (*)(id)'}}
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче