зеркало из 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.
|
/// Compatibility predicates used to check assignment expressions.
|
||||||
bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
|
bool typesAreCompatible(QualType, QualType); // C99 6.2.7p1
|
||||||
|
bool typesAreBlockCompatible(QualType lhs, QualType rhs);
|
||||||
|
|
||||||
bool isObjCIdType(QualType T) const {
|
bool isObjCIdType(QualType T) const {
|
||||||
if (!IdStructType) // ObjC isn't enabled
|
if (!IdStructType) // ObjC isn't enabled
|
||||||
|
|
|
@ -998,6 +998,14 @@ DIAG(ext_typecheck_convert_incompatible_pointer, EXTWARN,
|
||||||
"incompatible pointer types %2 '%1', expected '%0'")
|
"incompatible pointer types %2 '%1', expected '%0'")
|
||||||
DIAG(ext_typecheck_convert_discards_qualifiers, EXTWARN,
|
DIAG(ext_typecheck_convert_discards_qualifiers, EXTWARN,
|
||||||
"%2 '%1' discards qualifiers, expected '%0'")
|
"%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,
|
DIAG(err_typecheck_array_not_modifiable_lvalue, ERROR,
|
||||||
"array type '%0' is not assignable")
|
"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,
|
DIAG(err_expected_block_lbrace, ERROR,
|
||||||
"expected '{' in block literal")
|
"expected '{' in block literal")
|
||||||
DIAG(err_goto_in_block, ERROR,
|
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,
|
DIAG(err_return_in_block_expression, ERROR,
|
||||||
"return not allowed in block expression literal")
|
"return not allowed in block expression literal")
|
||||||
|
|
||||||
|
|
|
@ -1767,6 +1767,52 @@ bool ASTContext::isObjCObjectPointerType(QualType Ty) const {
|
||||||
// Type Compatibility Testing
|
// 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
|
/// areCompatVectorTypes - Return true if the two specified vector types are
|
||||||
/// compatible.
|
/// compatible.
|
||||||
static bool areCompatVectorTypes(const VectorType *LHS,
|
static bool areCompatVectorTypes(const VectorType *LHS,
|
||||||
|
|
|
@ -817,6 +817,18 @@ private:
|
||||||
/// c/v/r qualifiers, which we accept as an extension.
|
/// c/v/r qualifiers, which we accept as an extension.
|
||||||
CompatiblePointerDiscardsQualifiers,
|
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
|
/// Incompatible - We reject this conversion outright, it is invalid to
|
||||||
/// represent it in the AST.
|
/// represent it in the AST.
|
||||||
Incompatible
|
Incompatible
|
||||||
|
@ -850,6 +862,11 @@ private:
|
||||||
AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
|
AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
|
||||||
QualType rhsType);
|
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
|
/// the following "Check" methods will return a valid/converted QualType
|
||||||
/// or a null QualType (indicating an error diagnostic was issued).
|
/// or a null QualType (indicating an error diagnostic was issued).
|
||||||
|
|
||||||
|
|
|
@ -1431,6 +1431,34 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
|
||||||
return ConvTy;
|
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
|
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
|
||||||
/// has code to accommodate several GCC extensions when type checking
|
/// has code to accommodate several GCC extensions when type checking
|
||||||
/// pointers. Here are some objectionable examples that GCC considers warnings:
|
/// pointers. Here are some objectionable examples that GCC considers warnings:
|
||||||
|
@ -1500,6 +1528,25 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
||||||
|
|
||||||
if (isa<PointerType>(rhsType))
|
if (isa<PointerType>(rhsType))
|
||||||
return CheckPointerTypesForAssignment(lhsType, 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;
|
return Incompatible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1513,6 +1560,10 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
||||||
|
|
||||||
if (isa<PointerType>(lhsType))
|
if (isa<PointerType>(lhsType))
|
||||||
return CheckPointerTypesForAssignment(lhsType, rhsType);
|
return CheckPointerTypesForAssignment(lhsType, rhsType);
|
||||||
|
|
||||||
|
if (isa<BlockPointerType>(lhsType) &&
|
||||||
|
rhsType->getAsPointerType()->getPointeeType()->isVoidType())
|
||||||
|
return BlockVoidPointer;
|
||||||
return Incompatible;
|
return Incompatible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1532,6 +1583,11 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
|
||||||
ImpCastExprToType(rExpr, lhsType);
|
ImpCastExprToType(rExpr, lhsType);
|
||||||
return Compatible;
|
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
|
// This check seems unnatural, however it is necessary to ensure the proper
|
||||||
// conversion of functions/arrays. If the conversion were done for all
|
// conversion of functions/arrays. If the conversion were done for all
|
||||||
// DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary
|
// 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
|
ImpCastExprToType(rex, lType); // promote the pointer to pointer
|
||||||
return Context.IntTy;
|
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 ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
|
||||||
if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
|
if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
|
||||||
ImpCastExprToType(rex, lType);
|
ImpCastExprToType(rex, lType);
|
||||||
|
@ -2875,6 +2946,15 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
||||||
case CompatiblePointerDiscardsQualifiers:
|
case CompatiblePointerDiscardsQualifiers:
|
||||||
DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
|
DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
|
||||||
break;
|
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:
|
case Incompatible:
|
||||||
DiagKind = diag::err_typecheck_convert_incompatible;
|
DiagKind = diag::err_typecheck_convert_incompatible;
|
||||||
isInvalid = true;
|
isInvalid = true;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче