зеркало из https://github.com/microsoft/clang-1.git
More type checking for blocks. Still incomplete (will hopefully finish up this weekend).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55862 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
2b345eb783
Коммит
dd972f20dc
|
@ -1022,8 +1022,14 @@ DIAG(err_typecheck_call_not_function, ERROR,
|
|||
"called object is not a function or function pointer")
|
||||
DIAG(err_typecheck_call_too_few_args, ERROR,
|
||||
"too few arguments to function")
|
||||
DIAG(err_typecheck_block_too_few_args, ERROR,
|
||||
"too few arguments to block")
|
||||
DIAG(err_typecheck_call_too_many_args, ERROR,
|
||||
"too many arguments to function")
|
||||
DIAG(err_typecheck_block_too_many_args, ERROR,
|
||||
"too many arguments to block call")
|
||||
DIAG(err_typecheck_closure_too_many_args, ERROR,
|
||||
"too many arguments to closure call")
|
||||
DIAG(err_typecheck_call_invalid_ordered_compare, ERROR,
|
||||
"ordered compare requires two args of floating point type ('%0' and '%1')")
|
||||
DIAG(err_typecheck_cond_expect_scalar, ERROR,
|
||||
|
@ -1145,6 +1151,9 @@ DIAG(err_goto_in_block, ERROR,
|
|||
DIAG(err_return_in_block_expression, ERROR,
|
||||
"return not allowed in block expression literal")
|
||||
|
||||
DIAG(err_ret_local_block, ERROR,
|
||||
"returning block that lives on the local stack")
|
||||
|
||||
// CFString checking
|
||||
DIAG(err_cfstring_literal_not_string_constant, ERROR,
|
||||
"CFString literal is not a string constant")
|
||||
|
|
|
@ -1781,7 +1781,19 @@ bool ASTContext::isObjCObjectPointerType(QualType Ty) const {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// typesAreBlockCompatible - This routine is called when comparing two
|
||||
/// block types. Types must be strictly compatible here.
|
||||
/// block types. Types must be strictly compatible here. For example,
|
||||
/// C unfortunately doesn't produce an error for the following:
|
||||
///
|
||||
/// int (*emptyArgFunc)();
|
||||
/// int (*intArgList)(int) = emptyArgFunc;
|
||||
///
|
||||
/// For blocks, we will produce an error for the following (similar to C++):
|
||||
///
|
||||
/// int (^emptyArgBlock)();
|
||||
/// int (^intArgBlock)(int) = emptyArgBlock;
|
||||
///
|
||||
/// FIXME: When the dust settles on this integration, fold this into mergeTypes.
|
||||
///
|
||||
bool ASTContext::typesAreBlockCompatible(QualType lhs, QualType rhs) {
|
||||
if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers())
|
||||
return false;
|
||||
|
|
|
@ -423,6 +423,12 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
|
|||
return LV_Valid;
|
||||
break;
|
||||
}
|
||||
case BlockDeclRefExprClass: {
|
||||
const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this);
|
||||
if (BDR->isByRef() && isa<VarDecl>(BDR->getDecl()))
|
||||
return LV_Valid;
|
||||
break;
|
||||
}
|
||||
case MemberExprClass: { // C99 6.5.2.3p4
|
||||
const MemberExpr *m = cast<MemberExpr>(this);
|
||||
return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx);
|
||||
|
@ -1453,4 +1459,6 @@ Stmt::child_iterator BlockExprExpr::child_begin() {
|
|||
Stmt::child_iterator BlockExprExpr::child_end() {
|
||||
return reinterpret_cast<Stmt**>(&BodyExpr)+1;
|
||||
}
|
||||
Stmt::child_iterator BlockDeclRefExpr::child_begin(){return child_iterator();}
|
||||
Stmt::child_iterator BlockDeclRefExpr::child_end() { return child_iterator();}
|
||||
|
||||
|
|
|
@ -711,11 +711,15 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
|
|||
SourceLocation ReturnLoc) {
|
||||
|
||||
// Perform checking for returned stack addresses.
|
||||
if (lhsType->isPointerType()) {
|
||||
if (lhsType->isPointerType() || lhsType->isBlockPointerType()) {
|
||||
if (DeclRefExpr *DR = EvalAddr(RetValExp))
|
||||
Diag(DR->getLocStart(), diag::warn_ret_stack_addr,
|
||||
DR->getDecl()->getIdentifier()->getName(),
|
||||
RetValExp->getSourceRange());
|
||||
|
||||
if (BlockExpr *C = dyn_cast_or_null<BlockExpr>(EvalAddr(RetValExp)))
|
||||
Diag(C->getLocStart(), diag::err_ret_local_block,
|
||||
C->getSourceRange());
|
||||
}
|
||||
// Perform checking for stack values returned by reference.
|
||||
else if (lhsType->isReferenceType()) {
|
||||
|
@ -751,7 +755,8 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
|
|||
/// * taking the address of an array element where the array is on the stack
|
||||
static DeclRefExpr* EvalAddr(Expr *E) {
|
||||
// We should only be called for evaluating pointer expressions.
|
||||
assert((E->getType()->isPointerType() ||
|
||||
assert((E->getType()->isPointerType() ||
|
||||
E->getType()->isBlockPointerType() ||
|
||||
E->getType()->isObjCQualifiedIdType()) &&
|
||||
"EvalAddr only works on pointers");
|
||||
|
||||
|
@ -814,7 +819,9 @@ static DeclRefExpr* EvalAddr(Expr *E) {
|
|||
Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
|
||||
QualType T = SubExpr->getType();
|
||||
|
||||
if (T->isPointerType() || T->isObjCQualifiedIdType())
|
||||
if (SubExpr->getType()->isPointerType() ||
|
||||
SubExpr->getType()->isBlockPointerType() ||
|
||||
SubExpr->getType()->isObjCQualifiedIdType())
|
||||
return EvalAddr(SubExpr);
|
||||
else if (T->isArrayType())
|
||||
return EvalVal(SubExpr);
|
||||
|
@ -832,7 +839,7 @@ static DeclRefExpr* EvalAddr(Expr *E) {
|
|||
|
||||
if (C->getOpcode() == CXXCastExpr::ReinterpretCast) {
|
||||
Expr *S = C->getSubExpr();
|
||||
if (S->getType()->isPointerType())
|
||||
if (S->getType()->isPointerType() || S->getType()->isBlockPointerType())
|
||||
return EvalAddr(S);
|
||||
else
|
||||
return NULL;
|
||||
|
|
|
@ -299,6 +299,24 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
|
|||
StringToks[NumStringToks-1].getLocation());
|
||||
}
|
||||
|
||||
/// DeclDefinedWithinScope - Return true if the specified decl is defined at or
|
||||
/// within the 'Within' scope. The current Scope is CurScope.
|
||||
///
|
||||
/// NOTE: This method is extremely inefficient (linear scan), this should not be
|
||||
/// used in common cases.
|
||||
///
|
||||
static bool DeclDefinedWithinScope(ScopedDecl *D, Scope *Within,
|
||||
Scope *CurScope) {
|
||||
while (1) {
|
||||
assert(CurScope && "CurScope not nested within 'Within'?");
|
||||
|
||||
// Check this scope for the decl.
|
||||
if (CurScope->isDeclScope(D)) return true;
|
||||
|
||||
if (CurScope == Within) return false;
|
||||
CurScope = CurScope->getParent();
|
||||
}
|
||||
}
|
||||
|
||||
/// ActOnIdentifierExpr - The parser read an identifier in expression context,
|
||||
/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this
|
||||
|
@ -350,17 +368,6 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
|||
}
|
||||
}
|
||||
|
||||
if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
|
||||
// check if referencing an identifier with __attribute__((deprecated)).
|
||||
if (VD->getAttr<DeprecatedAttr>())
|
||||
Diag(Loc, diag::warn_deprecated, VD->getName());
|
||||
|
||||
// Only create DeclRefExpr's for valid Decl's.
|
||||
if (VD->isInvalidDecl())
|
||||
return true;
|
||||
return new DeclRefExpr(VD, VD->getType(), Loc);
|
||||
}
|
||||
|
||||
if (CXXFieldDecl *FD = dyn_cast<CXXFieldDecl>(D)) {
|
||||
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
|
||||
if (MD->isStatic())
|
||||
|
@ -383,7 +390,6 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
|||
|
||||
return Diag(Loc, diag::err_invalid_non_static_member_use, FD->getName());
|
||||
}
|
||||
|
||||
if (isa<TypedefDecl>(D))
|
||||
return Diag(Loc, diag::err_unexpected_typedef, II.getName());
|
||||
if (isa<ObjCInterfaceDecl>(D))
|
||||
|
@ -391,8 +397,36 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
|
|||
if (isa<NamespaceDecl>(D))
|
||||
return Diag(Loc, diag::err_unexpected_namespace, II.getName());
|
||||
|
||||
assert(0 && "Invalid decl");
|
||||
abort();
|
||||
// Make the DeclRefExpr or BlockDeclRefExpr for the decl.
|
||||
ValueDecl *VD = cast<ValueDecl>(D);
|
||||
|
||||
// check if referencing an identifier with __attribute__((deprecated)).
|
||||
if (VD->getAttr<DeprecatedAttr>())
|
||||
Diag(Loc, diag::warn_deprecated, VD->getName());
|
||||
|
||||
// Only create DeclRefExpr's for valid Decl's.
|
||||
if (VD->isInvalidDecl())
|
||||
return true;
|
||||
|
||||
// If this reference is not in a block or if the referenced variable is
|
||||
// within the block, create a normal DeclRefExpr.
|
||||
//
|
||||
// FIXME: This will create BlockDeclRefExprs for global variables,
|
||||
// function references, enums constants, etc which is suboptimal :) and breaks
|
||||
// things like "integer constant expression" tests.
|
||||
//
|
||||
if (!CurBlock || DeclDefinedWithinScope(VD, CurBlock->TheScope, S))
|
||||
return new DeclRefExpr(VD, VD->getType(), Loc);
|
||||
|
||||
// If we are in a block and the variable is outside the current block,
|
||||
// bind the variable reference with a BlockDeclRefExpr.
|
||||
|
||||
// If the variable is in the byref set, bind it directly, otherwise it will be
|
||||
// bound by-copy, thus we make it const within the closure.
|
||||
if (!CurBlock->ByRefVars.count(VD))
|
||||
VD->getType().addConst();
|
||||
|
||||
return new BlockDeclRefExpr(VD, VD->getType(), Loc, false);
|
||||
}
|
||||
|
||||
Sema::ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
|
||||
|
@ -983,14 +1017,19 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
|
|||
// of arguments and function on error.
|
||||
llvm::OwningPtr<CallExpr> TheCall(new CallExpr(Fn, Args, NumArgs,
|
||||
Context.BoolTy, RParenLoc));
|
||||
|
||||
// C99 6.5.2.2p1 - "The expression that denotes the called function shall have
|
||||
// type pointer to function".
|
||||
const PointerType *PT = Fn->getType()->getAsPointerType();
|
||||
if (PT == 0)
|
||||
return Diag(LParenLoc, diag::err_typecheck_call_not_function,
|
||||
Fn->getSourceRange());
|
||||
const FunctionType *FuncT = PT->getPointeeType()->getAsFunctionType();
|
||||
const FunctionType *FuncT;
|
||||
if (!Fn->getType()->isBlockPointerType()) {
|
||||
// C99 6.5.2.2p1 - "The expression that denotes the called function shall
|
||||
// have type pointer to function".
|
||||
const PointerType *PT = Fn->getType()->getAsPointerType();
|
||||
if (PT == 0)
|
||||
return Diag(LParenLoc, diag::err_typecheck_call_not_function,
|
||||
Fn->getSourceRange());
|
||||
FuncT = PT->getPointeeType()->getAsFunctionType();
|
||||
} else { // This is a block call.
|
||||
FuncT = Fn->getType()->getAsBlockPointerType()->getPointeeType()->
|
||||
getAsFunctionType();
|
||||
}
|
||||
if (FuncT == 0)
|
||||
return Diag(LParenLoc, diag::err_typecheck_call_not_function,
|
||||
Fn->getSourceRange());
|
||||
|
@ -1012,7 +1051,10 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
|
|||
NumArgsToCheck = NumArgsInProto;
|
||||
TheCall->setNumArgs(NumArgsInProto);
|
||||
} else
|
||||
return Diag(RParenLoc, diag::err_typecheck_call_too_few_args,
|
||||
return Diag(RParenLoc,
|
||||
!Fn->getType()->isBlockPointerType()
|
||||
? diag::err_typecheck_call_too_few_args
|
||||
: diag::err_typecheck_block_too_few_args,
|
||||
Fn->getSourceRange());
|
||||
}
|
||||
|
||||
|
@ -1021,7 +1063,10 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
|
|||
if (NumArgs > NumArgsInProto) {
|
||||
if (!Proto->isVariadic()) {
|
||||
Diag(Args[NumArgsInProto]->getLocStart(),
|
||||
diag::err_typecheck_call_too_many_args, Fn->getSourceRange(),
|
||||
!Fn->getType()->isBlockPointerType()
|
||||
? diag::err_typecheck_call_too_many_args
|
||||
: diag::err_typecheck_block_too_many_args,
|
||||
Fn->getSourceRange(),
|
||||
SourceRange(Args[NumArgsInProto]->getLocStart(),
|
||||
Args[NumArgs-1]->getLocEnd()));
|
||||
// This deletes the extra arguments.
|
||||
|
@ -1529,8 +1574,8 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
|
|||
if (isa<PointerType>(rhsType))
|
||||
return CheckPointerTypesForAssignment(lhsType, rhsType);
|
||||
|
||||
if (const BlockPointerType *BPT = rhsType->getAsBlockPointerType())
|
||||
if (BPT->getPointeeType()->isVoidType())
|
||||
if (rhsType->getAsBlockPointerType())
|
||||
if (lhsType->getAsPointerType()->getPointeeType()->isVoidType())
|
||||
return BlockVoidPointer;
|
||||
|
||||
return Incompatible;
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
// RUN: clang -fsyntax-only -verify %s
|
||||
|
||||
int (*FP)();
|
||||
int (^IFP) ();
|
||||
int (^II) (int);
|
||||
int main() {
|
||||
int (*FPL) (int) = FP; // C doesn't consider this an error.
|
||||
|
||||
// For Blocks, the ASTContext::typesAreBlockCompatible() makes sure this is an error.
|
||||
int (^PFR) (int) = IFP; // expected-error {{incompatible block pointer types initializing 'int (^)()', expected 'int (^)(int)'}}
|
||||
PFR = II; // OK
|
||||
|
||||
int (^IFP) () = PFR; // expected-error {{incompatible block pointer types initializing 'int (^)(int)', expected 'int (^)()'}}
|
||||
|
||||
|
||||
const int (^CIC) () = IFP; // expected-error {{incompatible block pointer types initializing 'int (^)()', expected 'int const (^)()'}}
|
||||
|
||||
|
||||
const int (^CICC) () = CIC;
|
||||
|
||||
int * const (^IPCC) () = 0;
|
||||
|
||||
int * const (^IPCC1) () = IPCC;
|
||||
|
||||
int * (^IPCC2) () = IPCC; // expected-error {{incompatible block pointer types initializing 'int *const (^)()', expected 'int *(^)()'}}
|
||||
|
||||
int (^IPCC3) (const int) = PFR; // expected-error {{incompatible block pointer types initializing 'int (^)(int)', expected 'int (^)(int const)'}}
|
||||
|
||||
|
||||
int (^IPCC4) (int, char (^CArg) (double));
|
||||
|
||||
|
||||
int (^IPCC5) (int, char (^CArg) (double)) = IPCC4;
|
||||
|
||||
int (^IPCC6) (int, char (^CArg) (float)) = IPCC4; // expected-error {{incompatible block pointer types initializing 'int (^)(int, char (^)(double))', expected 'int (^)(int, char (^)(float))'}}
|
||||
|
||||
IPCC2 = 0;
|
||||
IPCC2 = 1; // expected-error {{invalid conversion assigning integer 'int', expected block pointer 'int *(^)()'}}
|
||||
int (^x)() = 0;
|
||||
int (^y)() = 3; // expected-error {{invalid conversion initializing integer 'int', expected block pointer 'int (^)()'}}
|
||||
int a = 1;
|
||||
int (^z)() = a+4; // expected-error {{invalid conversion initializing integer 'int', expected block pointer 'int (^)()'}}
|
||||
}
|
||||
|
||||
int blah() {
|
||||
int (^IFP) (float);
|
||||
char (^PCP)(double, double, char);
|
||||
|
||||
IFP(1.0);
|
||||
IFP (1.0, 2.0); // expected-error {{too many arguments to block call}}
|
||||
|
||||
char ch = PCP(1.0, 2.0, 'a');
|
||||
return PCP(1.0, 2.0); // expected-error {{too few arguments to block}}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// RUN: clang -fsyntax-only -verify %s
|
||||
void donotwarn();
|
||||
|
||||
int (^IFP) ();
|
||||
int (^II) (int);
|
||||
int test1() {
|
||||
int (^PFR) (int) = 0; // OK
|
||||
PFR = II; // OK
|
||||
|
||||
if (PFR == II) // OK
|
||||
donotwarn();
|
||||
|
||||
if (PFR == IFP) // expected-error {{comparison of distinct block types}}
|
||||
donotwarn();
|
||||
|
||||
if (PFR == (int (^) (int))IFP) // OK
|
||||
donotwarn();
|
||||
|
||||
if (PFR == 0) // OK
|
||||
donotwarn();
|
||||
|
||||
if (PFR) // OK
|
||||
donotwarn();
|
||||
|
||||
if (!PFR) // OK
|
||||
donotwarn();
|
||||
|
||||
return PFR != IFP; // expected-error {{comparison of distinct block types}}
|
||||
}
|
||||
|
||||
int test2(double (^S)()) {
|
||||
double (^I)(int) = (void*) S;
|
||||
(void*)I = (void *)S; // expected-error {{expression is not assignable}}
|
||||
|
||||
void *pv = I;
|
||||
|
||||
pv = S;
|
||||
|
||||
I(1);
|
||||
|
||||
return (void*)I == (void *)S;
|
||||
}
|
||||
|
||||
int^ x; // expected-error {{block pointer to non-function type is invalid}}
|
||||
int^^ x1; // expected-error {{block pointer to non-function type is invalid}}
|
||||
|
||||
int test3() {
|
||||
char *^ y; // expected-error {{block pointer to non-function type is invalid}}
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче