diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 14 | ||||
| -rw-r--r-- | clang/lib/AST/Expr.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 15 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 97 |
4 files changed, 103 insertions, 31 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4caf16c4b09..62364bab318 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -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; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index f72ff4f6ca9..9452db4677a 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -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();} diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 1c1c594edc4..8c59039ac2e 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -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; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 02169e6db84..8a297ac1d7b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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; |

