diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2014-12-12 23:41:25 +0000 |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2014-12-12 23:41:25 +0000 |
commit | f770683f14f98eae7c64b942c1e6c3470ec0c81b (patch) | |
tree | c49c70db436ff0782689c19eae57f4ee135655cb /clang/lib/Sema/SemaChecking.cpp | |
parent | 620fb2206d28e78aa2549f37264d49108166c83c (diff) | |
download | bcm5719-llvm-f770683f14f98eae7c64b942c1e6c3470ec0c81b.tar.gz bcm5719-llvm-f770683f14f98eae7c64b942c1e6c3470ec0c81b.zip |
Implement the __builtin_call_with_static_chain GNU extension.
The extension has the following syntax:
__builtin_call_with_static_chain(Call, Chain)
where Call must be a function call expression and Chain must be of pointer type
This extension performs a function call Call with a static chain pointer
Chain passed to the callee in a designated register. This is useful for
calling foreign language functions whose ABI uses static chain pointers
(e.g. to implement closures).
Differential Revision: http://reviews.llvm.org/D6332
llvm-svn: 224167
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 57fc14e786c..9c56bec7771 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -139,6 +139,69 @@ static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl, S.Diag(SL, diag::warn_memcpy_chk_overflow) << SR << FnName; } +static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { + if (checkArgCount(S, BuiltinCall, 2)) + return true; + + SourceLocation BuiltinLoc = BuiltinCall->getLocStart(); + Expr *Builtin = BuiltinCall->getCallee()->IgnoreImpCasts(); + Expr *Call = BuiltinCall->getArg(0); + Expr *Chain = BuiltinCall->getArg(1); + + if (Call->getStmtClass() != Stmt::CallExprClass) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_not_call) + << Call->getSourceRange(); + return true; + } + + auto CE = cast<CallExpr>(Call); + if (CE->getCallee()->getType()->isBlockPointerType()) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_block_call) + << Call->getSourceRange(); + return true; + } + + const Decl *TargetDecl = CE->getCalleeDecl(); + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl)) + if (FD->getBuiltinID()) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_builtin_call) + << Call->getSourceRange(); + return true; + } + + if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) { + S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_pdtor_call) + << Call->getSourceRange(); + return true; + } + + ExprResult ChainResult = S.UsualUnaryConversions(Chain); + if (ChainResult.isInvalid()) + return true; + if (!ChainResult.get()->getType()->isPointerType()) { + S.Diag(BuiltinLoc, diag::err_second_argument_to_cwsc_not_pointer) + << Chain->getSourceRange(); + return true; + } + + QualType ReturnTy = CE->getCallReturnType(); + QualType ArgTys[2] = { ReturnTy, ChainResult.get()->getType() }; + QualType BuiltinTy = S.Context.getFunctionType( + ReturnTy, ArgTys, FunctionProtoType::ExtProtoInfo()); + QualType BuiltinPtrTy = S.Context.getPointerType(BuiltinTy); + + Builtin = + S.ImpCastExprToType(Builtin, BuiltinPtrTy, CK_BuiltinFnToFnPtr).get(); + + BuiltinCall->setType(CE->getType()); + BuiltinCall->setValueKind(CE->getValueKind()); + BuiltinCall->setObjectKind(CE->getObjectKind()); + BuiltinCall->setCallee(Builtin); + BuiltinCall->setArg(1, ChainResult.get()); + + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -393,6 +456,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin___vsnprintf_chk: SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3); break; + + case Builtin::BI__builtin_call_with_static_chain: + if (SemaBuiltinCallWithStaticChain(*this, TheCall)) + return ExprError(); + break; } // Since the target specific builtins for each arch overlap, only check those |