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:
Douglas Gregor 2008-12-19 19:13:09 +00:00
Родитель e4bb68a475
Коммит c788751123
3 изменённых файлов: 128 добавлений и 10 удалений

Просмотреть файл

@ -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)'}}
}