зеркало из https://github.com/microsoft/clang-1.git
Add type checking for blocks.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55767 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
3a2c7449e3
Коммит
1c7d067550
|
@ -416,6 +416,7 @@ public:
|
|||
|
||||
/// Compatibility predicates used to check assignment expressions.
|
||||
bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
|
||||
bool typesAreBlockCompatible(QualType lhs, QualType rhs);
|
||||
|
||||
bool isObjCIdType(QualType T) const {
|
||||
if (!IdStructType) // ObjC isn't enabled
|
||||
|
|
|
@ -998,6 +998,14 @@ DIAG(ext_typecheck_convert_incompatible_pointer, EXTWARN,
|
|||
"incompatible pointer types %2 '%1', expected '%0'")
|
||||
DIAG(ext_typecheck_convert_discards_qualifiers, EXTWARN,
|
||||
"%2 '%1' discards qualifiers, expected '%0'")
|
||||
DIAG(err_int_to_block_pointer, ERROR,
|
||||
"invalid conversion %2 integer '%1', expected block pointer '%0'")
|
||||
DIAG(err_typecheck_comparison_of_distinct_blocks, ERROR,
|
||||
"comparison of distinct block types ('%0' and '%1')")
|
||||
DIAG(err_typecheck_convert_incompatible_block_pointer, ERROR,
|
||||
"incompatible block pointer types %2 '%1', expected '%0'")
|
||||
DIAG(ext_typecheck_convert_pointer_void_block, EXTENSION,
|
||||
"%2 '%1' converts between void* and block pointer, expected '%0'")
|
||||
|
||||
DIAG(err_typecheck_array_not_modifiable_lvalue, ERROR,
|
||||
"array type '%0' is not assignable")
|
||||
|
@ -1133,7 +1141,7 @@ DIAG(warn_uninit_val, WARNING, "use of uninitialized variable")
|
|||
DIAG(err_expected_block_lbrace, ERROR,
|
||||
"expected '{' in block literal")
|
||||
DIAG(err_goto_in_block, ERROR,
|
||||
"goto not allowed in closure literal")
|
||||
"goto not allowed in block literal")
|
||||
DIAG(err_return_in_block_expression, ERROR,
|
||||
"return not allowed in block expression literal")
|
||||
|
||||
|
|
|
@ -1767,6 +1767,52 @@ bool ASTContext::isObjCObjectPointerType(QualType Ty) const {
|
|||
// Type Compatibility Testing
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// typesAreBlockCompatible - This routine is called when comparing two
|
||||
/// closure types. Types must be strictly compatible here.
|
||||
bool ASTContext::typesAreBlockCompatible(QualType lhs, QualType rhs) {
|
||||
if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers())
|
||||
return false;
|
||||
|
||||
QualType lcanon = getCanonicalType(lhs);
|
||||
QualType rcanon = getCanonicalType(rhs);
|
||||
|
||||
// If two types are identical, they are are compatible
|
||||
if (lcanon == rcanon)
|
||||
return true;
|
||||
if (isa<FunctionType>(lcanon) && isa<FunctionType>(rcanon)) {
|
||||
const FunctionType *lbase = cast<FunctionType>(lcanon);
|
||||
const FunctionType *rbase = cast<FunctionType>(rcanon);
|
||||
|
||||
// First check the return types.
|
||||
if (!typesAreBlockCompatible(lbase->getResultType(),rbase->getResultType()))
|
||||
return false;
|
||||
|
||||
// Return types matched, now check the argument types.
|
||||
const FunctionTypeProto *lproto = dyn_cast<FunctionTypeProto>(lbase);
|
||||
const FunctionTypeProto *rproto = dyn_cast<FunctionTypeProto>(rbase);
|
||||
|
||||
if (lproto && rproto) { // two C99 style function prototypes
|
||||
unsigned lproto_nargs = lproto->getNumArgs();
|
||||
unsigned rproto_nargs = rproto->getNumArgs();
|
||||
|
||||
if (lproto_nargs != rproto_nargs)
|
||||
return false;
|
||||
|
||||
if (lproto->isVariadic() || rproto->isVariadic())
|
||||
return false;
|
||||
|
||||
// The use of ellipsis agree...now check the argument types.
|
||||
for (unsigned i = 0; i < lproto_nargs; i++)
|
||||
if (!typesAreBlockCompatible(lproto->getArgType(i),
|
||||
rproto->getArgType(i)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return (!lproto && !rproto); // two K&R style function decls match.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// areCompatVectorTypes - Return true if the two specified vector types are
|
||||
/// compatible.
|
||||
static bool areCompatVectorTypes(const VectorType *LHS,
|
||||
|
|
|
@ -816,6 +816,18 @@ private:
|
|||
/// CompatiblePointerDiscardsQualifiers - The assignment discards
|
||||
/// c/v/r qualifiers, which we accept as an extension.
|
||||
CompatiblePointerDiscardsQualifiers,
|
||||
|
||||
/// IntToBlockPointer - The assignment converts an int to a closure
|
||||
/// pointer. We disallow this.
|
||||
IntToBlockPointer,
|
||||
|
||||
/// IncompatibleBlockPointer - The assignment is between two closure
|
||||
/// pointers types that are not compatible.
|
||||
IncompatibleBlockPointer,
|
||||
|
||||
/// BlockVoidPointer - The assignment is between a closure pointer and
|
||||
/// void*, we accept for now.
|
||||
BlockVoidPointer,
|
||||
|
||||
/// Incompatible - We reject this conversion outright, it is invalid to
|
||||
/// represent it in the AST.
|
||||
|
@ -849,6 +861,11 @@ private:
|
|||
// Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1)
|
||||
AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
|
||||
QualType rhsType);
|
||||
|
||||
// Helper function for CheckAssignmentConstraints involving two
|
||||
// blcok pointer types.
|
||||
AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType,
|
||||
QualType rhsType);
|
||||
|
||||
/// the following "Check" methods will return a valid/converted QualType
|
||||
/// or a null QualType (indicating an error diagnostic was issued).
|
||||
|
|
|
@ -1431,6 +1431,34 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
|
|||
return ConvTy;
|
||||
}
|
||||
|
||||
/// CheckBlockPointerTypesForAssignment - This routine determines whether two
|
||||
/// block pointer types are compatible or whether a block and normal pointer
|
||||
/// are compatible. It is more restrict than comparing two function pointer
|
||||
// types.
|
||||
Sema::AssignConvertType
|
||||
Sema::CheckBlockPointerTypesForAssignment(QualType lhsType,
|
||||
QualType rhsType) {
|
||||
QualType lhptee, rhptee;
|
||||
|
||||
// get the "pointed to" type (ignoring qualifiers at the top level)
|
||||
lhptee = lhsType->getAsBlockPointerType()->getPointeeType();
|
||||
rhptee = rhsType->getAsBlockPointerType()->getPointeeType();
|
||||
|
||||
// make sure we operate on the canonical type
|
||||
lhptee = Context.getCanonicalType(lhptee);
|
||||
rhptee = Context.getCanonicalType(rhptee);
|
||||
|
||||
AssignConvertType ConvTy = Compatible;
|
||||
|
||||
// For blocks we enforce that qualifiers are identical.
|
||||
if (lhptee.getCVRQualifiers() != rhptee.getCVRQualifiers())
|
||||
ConvTy = CompatiblePointerDiscardsQualifiers;
|
||||
|
||||
if (!Context.typesAreBlockCompatible(lhptee, rhptee))
|
||||
return IncompatibleBlockPointer;
|
||||
return ConvTy;
|
||||
}
|
||||
|
||||
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
|
||||
/// has code to accommodate several GCC extensions when type checking
|
||||
/// pointers. Here are some objectionable examples that GCC considers warnings:
|
||||
|
@ -1500,6 +1528,25 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
|||
|
||||
if (isa<PointerType>(rhsType))
|
||||
return CheckPointerTypesForAssignment(lhsType, rhsType);
|
||||
|
||||
if (const BlockPointerType *BPT = rhsType->getAsBlockPointerType())
|
||||
if (BPT->getPointeeType()->isVoidType())
|
||||
return BlockVoidPointer;
|
||||
|
||||
return Incompatible;
|
||||
}
|
||||
|
||||
if (isa<BlockPointerType>(lhsType)) {
|
||||
if (rhsType->isIntegerType())
|
||||
return IntToPointer;
|
||||
|
||||
if (rhsType->isBlockPointerType())
|
||||
return CheckBlockPointerTypesForAssignment(lhsType, rhsType);
|
||||
|
||||
if (const PointerType *RHSPT = rhsType->getAsPointerType()) {
|
||||
if (RHSPT->getPointeeType()->isVoidType())
|
||||
return BlockVoidPointer;
|
||||
}
|
||||
return Incompatible;
|
||||
}
|
||||
|
||||
|
@ -1513,6 +1560,10 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
|||
|
||||
if (isa<PointerType>(lhsType))
|
||||
return CheckPointerTypesForAssignment(lhsType, rhsType);
|
||||
|
||||
if (isa<BlockPointerType>(lhsType) &&
|
||||
rhsType->getAsPointerType()->getPointeeType()->isVoidType())
|
||||
return BlockVoidPointer;
|
||||
return Incompatible;
|
||||
}
|
||||
|
||||
|
@ -1532,6 +1583,11 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
|
|||
ImpCastExprToType(rExpr, lhsType);
|
||||
return Compatible;
|
||||
}
|
||||
|
||||
// We don't allow conversion of non-null-pointer constants to integers.
|
||||
if (lhsType->isBlockPointerType() && rExpr->getType()->isIntegerType())
|
||||
return IntToBlockPointer;
|
||||
|
||||
// This check seems unnatural, however it is necessary to ensure the proper
|
||||
// conversion of functions/arrays. If the conversion were done for all
|
||||
// DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary
|
||||
|
@ -1849,6 +1905,21 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation loc,
|
|||
ImpCastExprToType(rex, lType); // promote the pointer to pointer
|
||||
return Context.IntTy;
|
||||
}
|
||||
// Handle block pointer types.
|
||||
if (lType->isBlockPointerType() && rType->isBlockPointerType()) {
|
||||
QualType lpointee = lType->getAsBlockPointerType()->getPointeeType();
|
||||
QualType rpointee = rType->getAsBlockPointerType()->getPointeeType();
|
||||
|
||||
if (!LHSIsNull && !RHSIsNull &&
|
||||
!Context.typesAreBlockCompatible(lpointee, rpointee)) {
|
||||
Diag(loc, diag::err_typecheck_comparison_of_distinct_blocks,
|
||||
lType.getAsString(), rType.getAsString(),
|
||||
lex->getSourceRange(), rex->getSourceRange());
|
||||
}
|
||||
ImpCastExprToType(rex, lType); // promote the pointer to pointer
|
||||
return Context.IntTy;
|
||||
}
|
||||
|
||||
if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
|
||||
if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
|
||||
ImpCastExprToType(rex, lType);
|
||||
|
@ -2875,6 +2946,15 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|||
case CompatiblePointerDiscardsQualifiers:
|
||||
DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
|
||||
break;
|
||||
case IntToBlockPointer:
|
||||
DiagKind = diag::err_int_to_block_pointer;
|
||||
break;
|
||||
case IncompatibleBlockPointer:
|
||||
DiagKind = diag::err_typecheck_convert_incompatible_block_pointer;
|
||||
break;
|
||||
case BlockVoidPointer:
|
||||
DiagKind = diag::ext_typecheck_convert_pointer_void_block;
|
||||
break;
|
||||
case Incompatible:
|
||||
DiagKind = diag::err_typecheck_convert_incompatible;
|
||||
isInvalid = true;
|
||||
|
|
Загрузка…
Ссылка в новой задаче