summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2014-12-12 23:41:25 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2014-12-12 23:41:25 +0000
commitf770683f14f98eae7c64b942c1e6c3470ec0c81b (patch)
treec49c70db436ff0782689c19eae57f4ee135655cb /clang/lib/Sema/SemaChecking.cpp
parent620fb2206d28e78aa2549f37264d49108166c83c (diff)
downloadbcm5719-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.cpp68
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
OpenPOWER on IntegriCloud