Index: include/clang/AST/DataRecursiveASTVisitor.h =================================================================== --- include/clang/AST/DataRecursiveASTVisitor.h +++ include/clang/AST/DataRecursiveASTVisitor.h @@ -2273,6 +2273,7 @@ DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {}) DEF_TRAVERSE_STMT(CXXFoldExpr, {}) DEF_TRAVERSE_STMT(AtomicExpr, {}) +DEF_TRAVERSE_STMT(CallWithStaticChainExpr, {}) // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -4864,6 +4864,50 @@ SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); } SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); } }; + +/// \brief Represents the __builtin_call_with_static_chain expression. +class CallWithStaticChainExpr : public Expr { + enum { CALL, CHAIN, END_EXPR }; + Stmt *SubExprs[END_EXPR]; + SourceLocation BuiltinLoc, RParenLoc; + + friend class ASTStmtReader; + +public: + CallWithStaticChainExpr(CallExpr *Call, Expr *Chain, + SourceLocation BuiltinLoc, SourceLocation RParenLoc) + : Expr(CallWithStaticChainExprClass, Call->getType(), + Call->getValueKind(), OK_Ordinary, Call->isTypeDependent(), + Call->isValueDependent(), Call->isInstantiationDependent() || + Chain->isInstantiationDependent(), + Call->containsUnexpandedParameterPack() || + Chain->containsUnexpandedParameterPack()), + BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) { + SubExprs[CALL] = Call; + SubExprs[CHAIN] = Chain; + } + + explicit CallWithStaticChainExpr(EmptyShell Empty) + : Expr(CallWithStaticChainExprClass, Empty) {} + + CallExpr *getCallExpr() const { return cast(SubExprs[CALL]); } + Expr *getChainExpr() const { return cast(SubExprs[CHAIN]); } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CallWithStaticChainExprClass; + } + + child_range children() { + return child_range(SubExprs, SubExprs+END_EXPR); + } +}; + } // end namespace clang #endif Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2295,6 +2295,7 @@ DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {}) DEF_TRAVERSE_STMT(CXXFoldExpr, {}) DEF_TRAVERSE_STMT(AtomicExpr, {}) +DEF_TRAVERSE_STMT(CallWithStaticChainExpr, {}) // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6891,6 +6891,17 @@ def err_convertvector_incompatible_vector : Error< "first two arguments to __builtin_convertvector must have the same number of elements">; +def err_first_argument_to_cwsc_not_call : Error< + "first argument to __builtin_call_with_static_chain must be a non-member call expression">; +def err_first_argument_to_cwsc_block_call : Error< + "first argument to __builtin_call_with_static_chain must not be a block call">; +def err_first_argument_to_cwsc_builtin_call : Error< + "first argument to __builtin_call_with_static_chain must not be a builtin call">; +def err_first_argument_to_cwsc_pdtor_call : Error< + "first argument to __builtin_call_with_static_chain must not be a pseudo-destructor call">; +def err_second_argument_to_cwsc_not_pointer : Error< + "second argument to __builtin_call_with_static_chain must be of pointer type">; + def err_vector_incorrect_num_initializers : Error< "%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">; def err_altivec_empty_initializer : Error<"expected initializer">; Index: include/clang/Basic/StmtNodes.td =================================================================== --- include/clang/Basic/StmtNodes.td +++ include/clang/Basic/StmtNodes.td @@ -91,6 +91,7 @@ def StmtExpr : DStmt; def ChooseExpr : DStmt; def GNUNullExpr : DStmt; +def CallWithStaticChainExpr : DStmt; // C++ Expressions. def CXXOperatorCallExpr : DStmt; Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -363,6 +363,7 @@ KEYWORD(__thread , KEYALL) KEYWORD(__FUNCTION__ , KEYALL) KEYWORD(__PRETTY_FUNCTION__ , KEYALL) +KEYWORD(__builtin_call_with_static_chain, KEYALL) // GNU Extensions (outside impl-reserved namespace) KEYWORD(typeof , KEYGNU) Index: include/clang/CodeGen/CGFunctionInfo.h =================================================================== --- include/clang/CodeGen/CGFunctionInfo.h +++ include/clang/CodeGen/CGFunctionInfo.h @@ -352,6 +352,9 @@ /// Whether this is an instance method. unsigned InstanceMethod : 1; + /// Whether this is a chain call. + unsigned ChainCall : 1; + /// Whether this function is noreturn. unsigned NoReturn : 1; @@ -360,7 +363,7 @@ /// How many arguments to pass inreg. unsigned HasRegParm : 1; - unsigned RegParm : 4; + unsigned RegParm : 3; RequiredArgs Required; @@ -381,6 +384,7 @@ public: static CGFunctionInfo *create(unsigned llvmCC, bool InstanceMethod, + bool ChainCall, const FunctionType::ExtInfo &extInfo, CanQualType resultType, ArrayRef argTypes, @@ -412,6 +416,8 @@ bool isInstanceMethod() const { return InstanceMethod; } + bool isChainCall() const { return ChainCall; } + bool isNoReturn() const { return NoReturn; } /// In ARC, whether this function retains its return value. This @@ -462,6 +468,7 @@ void Profile(llvm::FoldingSetNodeID &ID) { ID.AddInteger(getASTCallingConvention()); ID.AddBoolean(InstanceMethod); + ID.AddBoolean(ChainCall); ID.AddBoolean(NoReturn); ID.AddBoolean(ReturnsRetained); ID.AddBoolean(HasRegParm); @@ -473,12 +480,14 @@ } static void Profile(llvm::FoldingSetNodeID &ID, bool InstanceMethod, + bool ChainCall, const FunctionType::ExtInfo &info, RequiredArgs required, CanQualType resultType, ArrayRef argTypes) { ID.AddInteger(info.getCC()); ID.AddBoolean(InstanceMethod); + ID.AddBoolean(ChainCall); ID.AddBoolean(info.getNoReturn()); ID.AddBoolean(info.getProducesResult()); ID.AddBoolean(info.getHasRegParm()); Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3795,6 +3795,10 @@ // __null ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc); + // __builtin_call_with_static_chain(call, chain) + ExprResult ActOnCallWithStaticChain(SourceLocation BuiltinLoc, Expr *Call, + Expr *Chain, SourceLocation RPLoc); + bool CheckCaseExpression(Expr *E); /// \brief Describes the result of an "if-exists" condition check. Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -1214,6 +1214,8 @@ EXPR_PSEUDO_OBJECT, /// \brief An AtomicExpr record. EXPR_ATOMIC, + /// \brief A CallWithStaticChainExpr record. + EXPR_CALL_WITH_STATIC_CHAIN, // Objective-C Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -2936,6 +2936,7 @@ case CXXBindTemporaryExprClass: case BlockExprClass: case CUDAKernelCallExprClass: + case CallWithStaticChainExprClass: // These always have a side-effect. return true; Index: lib/AST/ExprClassification.cpp =================================================================== --- lib/AST/ExprClassification.cpp +++ lib/AST/ExprClassification.cpp @@ -394,6 +394,10 @@ assert(cast(E)->getNumInits() == 1 && "Only 1-element init lists can be glvalues."); return ClassifyInternal(Ctx, cast(E)->getInit(0)); + + case Expr::CallWithStaticChainExprClass: + return ClassifyInternal(Ctx, + cast(E)->getCallExpr()); } llvm_unreachable("unhandled expression kind in classification"); Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -8689,6 +8689,7 @@ case Expr::AtomicExprClass: case Expr::LambdaExprClass: case Expr::CXXFoldExprClass: + case Expr::CallWithStaticChainExprClass: return ICEDiag(IK_NotICE, E->getLocStart()); case Expr::InitListExprClass: { Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -2675,6 +2675,7 @@ case Expr::AsTypeExprClass: case Expr::PseudoObjectExprClass: case Expr::AtomicExprClass: + case Expr::CallWithStaticChainExprClass: { // As bad as this diagnostic is, it's better than crashing. DiagnosticsEngine &Diags = Context.getDiags(); Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -1367,6 +1367,14 @@ OS << ")"; } +void StmtPrinter::VisitCallWithStaticChainExpr(CallWithStaticChainExpr *Node) { + OS << "__builtin_call_with_static_chain("; + PrintExpr(Node->getCallExpr()); + OS << ", "; + PrintExpr(Node->getChainExpr()); + OS << ")"; +} + void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { if (Node->getSyntacticForm()) { Visit(Node->getSyntacticForm()); Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -649,6 +649,11 @@ VisitExpr(S); } +void +StmtProfiler::VisitCallWithStaticChainExpr(const CallWithStaticChainExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitChooseExpr(const ChooseExpr *S) { VisitExpr(S); } Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -83,7 +83,7 @@ // When translating an unprototyped function type, always use a // variadic type. return arrangeLLVMFunctionInfo(FTNP->getReturnType().getUnqualifiedType(), - false, None, FTNP->getExtInfo(), + false, false, None, FTNP->getExtInfo(), RequiredArgs(0)); } @@ -98,8 +98,8 @@ for (unsigned i = 0, e = FTP->getNumParams(); i != e; ++i) prefix.push_back(FTP->getParamType(i)); CanQualType resultType = FTP->getReturnType().getUnqualifiedType(); - return CGT.arrangeLLVMFunctionInfo(resultType, IsInstanceMethod, prefix, - FTP->getExtInfo(), required); + return CGT.arrangeLLVMFunctionInfo(resultType, IsInstanceMethod, false, + prefix, FTP->getExtInfo(), required); } /// Arrange the argument and result information for a value of the @@ -219,7 +219,8 @@ : TheCXXABI.hasMostDerivedReturn(GD) ? CGM.getContext().VoidPtrTy : Context.VoidTy; - return arrangeLLVMFunctionInfo(resultType, true, argTypes, extInfo, required); + return arrangeLLVMFunctionInfo(resultType, true, false, argTypes, extInfo, + required); } /// Arrange a call to a C++ method, passing the given arguments. @@ -243,7 +244,8 @@ : Context.VoidTy; FunctionType::ExtInfo Info = FPT->getExtInfo(); - return arrangeLLVMFunctionInfo(ResultType, true, ArgTypes, Info, Required); + return arrangeLLVMFunctionInfo(ResultType, true, false, ArgTypes, Info, + Required); } /// Arrange the argument and result information for the declaration or @@ -262,7 +264,7 @@ // non-variadic type. if (isa(FTy)) { CanQual noProto = FTy.getAs(); - return arrangeLLVMFunctionInfo(noProto->getReturnType(), false, None, + return arrangeLLVMFunctionInfo(noProto->getReturnType(), false, false, None, noProto->getExtInfo(), RequiredArgs::All); } @@ -308,7 +310,7 @@ (MD->isVariadic() ? RequiredArgs(argTys.size()) : RequiredArgs::All); return arrangeLLVMFunctionInfo(GetReturnType(MD->getReturnType()), false, - argTys, einfo, required); + false, argTys, einfo, required); } const CGFunctionInfo & @@ -335,7 +337,7 @@ assert(MD->isVirtual() && "only virtual memptrs have thunks"); CanQual FTP = GetFormalType(MD); CanQualType ArgTys[] = { GetThisType(Context, MD->getParent()) }; - return arrangeLLVMFunctionInfo(Context.VoidTy, false, ArgTys, + return arrangeLLVMFunctionInfo(Context.VoidTy, false, false, ArgTys, FTP->getExtInfo(), RequiredArgs(1)); } @@ -346,7 +348,8 @@ CodeGenModule &CGM, const CallArgList &args, const FunctionType *fnType, - unsigned numExtraRequiredArgs) { + unsigned numExtraRequiredArgs, + bool chainCall) { assert(args.size() >= numExtraRequiredArgs); // In most cases, there are no optional arguments. @@ -368,7 +371,12 @@ required = RequiredArgs(args.size()); } - return CGT.arrangeFreeFunctionCall(fnType->getReturnType(), args, + // FIXME: Kill copy. + SmallVector argTypes; + for (const auto &Arg : args) + argTypes.push_back(CGT.getContext().getCanonicalParamType(Arg.Ty)); + return CGT.arrangeLLVMFunctionInfo(GetReturnType(fnType->getReturnType()), + false, chainCall, argTypes, fnType->getExtInfo(), required); } @@ -378,8 +386,10 @@ /// target-dependent in crazy ways. const CGFunctionInfo & CodeGenTypes::arrangeFreeFunctionCall(const CallArgList &args, - const FunctionType *fnType) { - return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 0); + const FunctionType *fnType, + bool chainCall) { + return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, + chainCall ? 1 : 0, chainCall); } /// A block function call is essentially a free-function call with an @@ -387,7 +397,8 @@ const CGFunctionInfo & CodeGenTypes::arrangeBlockFunctionCall(const CallArgList &args, const FunctionType *fnType) { - return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 1); + return arrangeFreeFunctionLikeCall(*this, CGM, args, fnType, 1, + /*chainCall=*/false); } const CGFunctionInfo & @@ -399,8 +410,8 @@ SmallVector argTypes; for (const auto &Arg : args) argTypes.push_back(Context.getCanonicalParamType(Arg.Ty)); - return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, argTypes, - info, required); + return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, false, + argTypes, info, required); } /// Arrange a call to a C++ method, passing the given arguments. @@ -415,7 +426,7 @@ FunctionType::ExtInfo info = FPT->getExtInfo(); return arrangeLLVMFunctionInfo(GetReturnType(FPT->getReturnType()), true, - argTypes, info, required); + false, argTypes, info, required); } const CGFunctionInfo &CodeGenTypes::arrangeFreeFunctionDeclaration( @@ -428,12 +439,12 @@ RequiredArgs required = (isVariadic ? RequiredArgs(args.size()) : RequiredArgs::All); - return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, argTypes, info, - required); + return arrangeLLVMFunctionInfo(GetReturnType(resultType), false, false, + argTypes, info, required); } const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() { - return arrangeLLVMFunctionInfo(getContext().VoidTy, false, None, + return arrangeLLVMFunctionInfo(getContext().VoidTy, false, false, None, FunctionType::ExtInfo(), RequiredArgs::All); } @@ -443,6 +454,7 @@ const CGFunctionInfo & CodeGenTypes::arrangeLLVMFunctionInfo(CanQualType resultType, bool IsInstanceMethod, + bool IsChainCall, ArrayRef argTypes, FunctionType::ExtInfo info, RequiredArgs required) { @@ -456,8 +468,8 @@ // Lookup or create unique function info. llvm::FoldingSetNodeID ID; - CGFunctionInfo::Profile(ID, IsInstanceMethod, info, required, resultType, - argTypes); + CGFunctionInfo::Profile(ID, IsInstanceMethod, IsChainCall, info, required, + resultType, argTypes); void *insertPos = nullptr; CGFunctionInfo *FI = FunctionInfos.FindNodeOrInsertPos(ID, insertPos); @@ -465,8 +477,8 @@ return *FI; // Construct the function info. We co-allocate the ArgInfos. - FI = CGFunctionInfo::create(CC, IsInstanceMethod, info, resultType, argTypes, - required); + FI = CGFunctionInfo::create(CC, IsInstanceMethod, IsChainCall, info, + resultType, argTypes, required); FunctionInfos.InsertNode(FI, insertPos); bool inserted = FunctionsBeingProcessed.insert(FI).second; @@ -495,6 +507,7 @@ CGFunctionInfo *CGFunctionInfo::create(unsigned llvmCC, bool IsInstanceMethod, + bool IsChainCall, const FunctionType::ExtInfo &info, CanQualType resultType, ArrayRef argTypes, @@ -506,6 +519,7 @@ FI->EffectiveCallingConvention = llvmCC; FI->ASTCallingConvention = info.getCC(); FI->InstanceMethod = IsInstanceMethod; + FI->ChainCall = IsChainCall; FI->NoReturn = info.getNoReturn(); FI->ReturnsRetained = info.getProducesResult(); FI->Required = required; @@ -1493,7 +1507,6 @@ getLLVMContext(), IRFunctionArgs.getInallocaArgNo() + 1, Attrs)); } - unsigned ArgNo = 0; for (CGFunctionInfo::const_arg_iterator I = FI.arg_begin(), E = FI.arg_end(); @@ -1521,7 +1534,9 @@ Attrs.addAttribute(llvm::Attribute::ZExt); // FALL THROUGH case ABIArgInfo::Direct: - if (AI.getInReg()) + if (ArgNo == 0 && FI.isChainCall()) + Attrs.addAttribute(llvm::Attribute::Nest); + else if (AI.getInReg()) Attrs.addAttribute(llvm::Attribute::InReg); break; Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -828,6 +828,8 @@ case Expr::CXXOperatorCallExprClass: case Expr::UserDefinedLiteralClass: return EmitCallExprLValue(cast(E)); + case Expr::CallWithStaticChainExprClass: + return EmitCallWithStaticChainExprLValue(cast(E)); case Expr::VAArgExprClass: return EmitVAArgExprLValue(cast(E)); case Expr::DeclRefExprClass: @@ -3098,6 +3100,16 @@ TargetDecl); } +RValue +CodeGenFunction::EmitCallWithStaticChainExpr(const CallWithStaticChainExpr *E, + ReturnValueSlot ReturnValue) { + CallExpr *Call = E->getCallExpr(); + return EmitCall(Call->getCallee()->getType(), + EmitScalarExpr(Call->getCallee()), Call, ReturnValue, + Call->getCalleeDecl(), + EmitScalarExpr(E->getChainExpr())); +} + LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { // Comma expressions just emit their LHS then their RHS as an l-value. if (E->getOpcode() == BO_Comma) { @@ -3159,6 +3171,20 @@ return MakeAddrLValue(RV.getScalarVal(), E->getType()); } +LValue CodeGenFunction::EmitCallWithStaticChainExprLValue( + const CallWithStaticChainExpr *E) { + RValue RV = EmitCallWithStaticChainExpr(E); + + if (!RV.isScalar()) + return MakeAddrLValue(RV.getAggregateAddr(), E->getType()); + + assert(E->getCallExpr()->getCallReturnType()->isReferenceType() && + "Can't have a scalar return unless the return type is a " + "reference type!"); + + return MakeAddrLValue(RV.getScalarVal(), E->getType()); +} + LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) { // FIXME: This shouldn't require another copy. return EmitAggExprToLValue(E); @@ -3267,7 +3293,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, const CallExpr *E, ReturnValueSlot ReturnValue, - const Decl *TargetDecl) { + const Decl *TargetDecl, llvm::Value *Chain) { // Get the actual function type. The callee type will always be a pointer to // function type or a block pointer type. assert(CalleeType->isFunctionPointerType() && @@ -3332,12 +3358,15 @@ } CallArgList Args; + if (Chain) + Args.add(RValue::get(Builder.CreateBitCast(Chain, CGM.VoidPtrTy)), + CGM.getContext().VoidPtrTy); EmitCallArgs(Args, dyn_cast(FnType), E->arg_begin(), E->arg_end(), E->getDirectCallee(), /*ParamsToSkip*/ 0, ForceColumnInfo); - const CGFunctionInfo &FnInfo = - CGM.getTypes().arrangeFreeFunctionCall(Args, FnType); + const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall( + Args, FnType, /*isChainCall=*/Chain); // C99 6.5.2.2p6: // If the expression that denotes the called function has a type @@ -3356,7 +3385,10 @@ // through an unprototyped function type works like a *non-variadic* // call. The way we make this work is to cast to the exact type // of the promoted arguments. - if (isa(FnType)) { + // + // Chain calls use this same code path to add the invisible chain parameter + // to the function type. + if (isa(FnType) || Chain) { llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo); CalleeTy = CalleeTy->getPointerTo(); Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast"); Index: lib/CodeGen/CGExprAgg.cpp =================================================================== --- lib/CodeGen/CGExprAgg.cpp +++ lib/CodeGen/CGExprAgg.cpp @@ -143,6 +143,7 @@ // Operators. void VisitCastExpr(CastExpr *E); void VisitCallExpr(const CallExpr *E); + void VisitCallWithStaticChainExpr(const CallWithStaticChainExpr *E); void VisitStmtExpr(const StmtExpr *E); void VisitBinaryOperator(const BinaryOperator *BO); void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *BO); @@ -745,6 +746,17 @@ EmitMoveFromReturnSlot(E, RV); } +void +AggExprEmitter::VisitCallWithStaticChainExpr(const CallWithStaticChainExpr *E) { + if (E->getCallExpr()->getCallReturnType()->isReferenceType()) { + EmitAggLoadOfLValue(E); + return; + } + + RValue RV = CGF.EmitCallWithStaticChainExpr(E, getReturnValueSlot()); + EmitMoveFromReturnSlot(E, RV); +} + void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) { RValue RV = CGF.EmitObjCMessageExpr(E, getReturnValueSlot()); EmitMoveFromReturnSlot(E, RV); Index: lib/CodeGen/CGExprCXX.cpp =================================================================== --- lib/CodeGen/CGExprCXX.cpp +++ lib/CodeGen/CGExprCXX.cpp @@ -1028,9 +1028,9 @@ llvm::Instruction *CallOrInvoke; llvm::Value *CalleeAddr = CGF.CGM.GetAddrOfFunction(Callee); RValue RV = - CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(Args, CalleeType), - CalleeAddr, ReturnValueSlot(), Args, - Callee, &CallOrInvoke); + CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall( + Args, CalleeType, /*chainCall=*/false), + CalleeAddr, ReturnValueSlot(), Args, Callee, &CallOrInvoke); /// C++1y [expr.new]p10: /// [In a new-expression,] an implementation is allowed to omit a call Index: lib/CodeGen/CGExprComplex.cpp =================================================================== --- lib/CodeGen/CGExprComplex.cpp +++ lib/CodeGen/CGExprComplex.cpp @@ -156,6 +156,7 @@ return EmitCast(E->getCastKind(), E->getSubExpr(), E->getType()); } ComplexPairTy VisitCallExpr(const CallExpr *E); + ComplexPairTy VisitCallWithStaticChainExpr(const CallWithStaticChainExpr *E); ComplexPairTy VisitStmtExpr(const StmtExpr *E); // Operators. @@ -382,6 +383,14 @@ return CGF.EmitCallExpr(E).getComplexVal(); } +ComplexPairTy ComplexExprEmitter::VisitCallWithStaticChainExpr( + const CallWithStaticChainExpr *E) { + if (E->getCallExpr()->getCallReturnType()->isReferenceType()) + return EmitLoadOfLValue(E); + + return CGF.EmitCallWithStaticChainExpr(E).getComplexVal(); +} + ComplexPairTy ComplexExprEmitter::VisitStmtExpr(const StmtExpr *E) { CodeGenFunction::StmtExprEvaluation eval(CGF); llvm::Value *RetAlloca = CGF.EmitCompoundStmt(*E->getSubStmt(), true); Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -328,6 +328,13 @@ return V; } + Value *VisitCallWithStaticChainExpr(const CallWithStaticChainExpr *E) { + if (E->getCallExpr()->getCallReturnType()->isReferenceType()) + return EmitLoadOfLValue(E); + + return CGF.EmitCallWithStaticChainExpr(E).getScalarVal(); + } + Value *VisitStmtExpr(const StmtExpr *E); // Unary Operators. Index: lib/CodeGen/CGObjCMac.cpp =================================================================== --- lib/CodeGen/CGObjCMac.cpp +++ lib/CodeGen/CGObjCMac.cpp @@ -244,9 +244,9 @@ Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified()); Params.push_back(Ctx.BoolTy); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(IdType, false, Params, - FunctionType::ExtInfo(), - RequiredArgs::All)); + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo( + IdType, false, false, Params, FunctionType::ExtInfo(), + RequiredArgs::All)); return CGM.CreateRuntimeFunction(FTy, "objc_getProperty"); } @@ -264,10 +264,9 @@ Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, - Params, - FunctionType::ExtInfo(), - RequiredArgs::All)); + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo( + Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(), + RequiredArgs::All)); return CGM.CreateRuntimeFunction(FTy, "objc_setProperty"); } @@ -291,10 +290,9 @@ Params.push_back(IdType); Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified()); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, - Params, - FunctionType::ExtInfo(), - RequiredArgs::All)); + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo( + Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(), + RequiredArgs::All)); const char *name; if (atomic && copy) name = "objc_setProperty_atomic_copy"; @@ -319,10 +317,9 @@ Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, - Params, - FunctionType::ExtInfo(), - RequiredArgs::All)); + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo( + Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(), + RequiredArgs::All)); return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct"); } @@ -339,7 +336,7 @@ Params.push_back(Ctx.VoidPtrTy); Params.push_back(Ctx.VoidPtrTy); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(), RequiredArgs::All)); @@ -353,10 +350,9 @@ SmallVector Params; Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType())); llvm::FunctionType *FTy = - Types.GetFunctionType(Types.arrangeLLVMFunctionInfo(Ctx.VoidTy, false, - Params, - FunctionType::ExtInfo(), - RequiredArgs::All)); + Types.GetFunctionType(Types.arrangeLLVMFunctionInfo( + Ctx.VoidTy, false, false, Params, FunctionType::ExtInfo(), + RequiredArgs::All)); return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); } Index: lib/CodeGen/CodeGenABITypes.cpp =================================================================== --- lib/CodeGen/CodeGenABITypes.cpp +++ lib/CodeGen/CodeGenABITypes.cpp @@ -67,5 +67,6 @@ FunctionType::ExtInfo info, RequiredArgs args) { return CGM->getTypes().arrangeLLVMFunctionInfo( - returnType, /*IsInstanceMethod=*/false, argTypes, info, args); + returnType, /*IsInstanceMethod=*/false, /*IsChainCall=*/false, argTypes, + info, args); } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -2174,6 +2174,7 @@ LValue EmitCompoundAssignmentLValue(const CompoundAssignOperator *E); // Note: only available for agg return types LValue EmitCallExprLValue(const CallExpr *E); + LValue EmitCallWithStaticChainExprLValue(const CallWithStaticChainExpr *E); // Note: only available for agg return types LValue EmitVAArgExprLValue(const VAArgExpr *E); LValue EmitDeclRefLValue(const DeclRefExpr *E); @@ -2281,9 +2282,13 @@ RValue EmitCall(QualType FnType, llvm::Value *Callee, const CallExpr *E, ReturnValueSlot ReturnValue, - const Decl *TargetDecl = nullptr); + const Decl *TargetDecl = nullptr, + llvm::Value *Chain = nullptr); RValue EmitCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue = ReturnValueSlot()); + RValue + EmitCallWithStaticChainExpr(const CallWithStaticChainExpr *E, + ReturnValueSlot ReturnValue = ReturnValueSlot()); llvm::CallInst *EmitRuntimeCall(llvm::Value *callee, const Twine &name = ""); Index: lib/CodeGen/CodeGenTypes.h =================================================================== --- lib/CodeGen/CodeGenTypes.h +++ lib/CodeGen/CodeGenTypes.h @@ -248,7 +248,8 @@ CXXCtorType CtorKind, unsigned ExtraArgs); const CGFunctionInfo &arrangeFreeFunctionCall(const CallArgList &Args, - const FunctionType *Ty); + const FunctionType *Ty, + bool ChainCall); const CGFunctionInfo &arrangeFreeFunctionCall(QualType ResTy, const CallArgList &args, FunctionType::ExtInfo info, @@ -274,6 +275,7 @@ /// \param argTypes - must all actually be canonical as params const CGFunctionInfo &arrangeLLVMFunctionInfo(CanQualType returnType, bool IsInstanceMethod, + bool IsChainCall, ArrayRef argTypes, FunctionType::ExtInfo info, RequiredArgs args); Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -1145,6 +1145,10 @@ } } + // The chain argument effectively gives us another free register. + if (FI.isChainCall()) + ++State.FreeRegs; + bool UsedInAlloca = false; for (auto &I : FI.arguments()) { I.info = classifyArgumentType(I.type, State); @@ -2695,6 +2699,10 @@ if (FI.getReturnInfo().isIndirect()) --freeIntRegs; + // The chain argument effectively gives us another free register. + if (FI.isChainCall()) + ++freeIntRegs; + unsigned NumRequiredArgs = FI.getNumRequiredArgs(); // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers // get assigned (in left-to-right order) for passing as follows... Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -940,6 +940,7 @@ case tok::kw___builtin_choose_expr: case tok::kw___builtin_astype: // primary-expression: [OCL] as_type() case tok::kw___builtin_convertvector: + case tok::kw___builtin_call_with_static_chain: return ParseBuiltinPrimaryExpression(); case tok::kw___null: return Actions.ActOnGNUNullExpr(ConsumeToken()); @@ -1981,6 +1982,34 @@ ConsumeParen()); break; } + case tok::kw___builtin_call_with_static_chain: { + ExprResult Call(ParseAssignmentExpression()); + if (Call.isInvalid()) { + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + ExprResult Chain(ParseAssignmentExpression()); + if (Chain.isInvalid()) { + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected) << tok::r_paren; + SkipUntil(tok::r_paren, StopAtSemi); + return ExprError(); + } + + Res = Actions.ActOnCallWithStaticChain(StartLoc, Call.get(), Chain.get(), + ConsumeParen()); + break; + } } if (Res.isInvalid()) Index: lib/Sema/SemaExceptionSpec.cpp =================================================================== --- lib/Sema/SemaExceptionSpec.cpp +++ lib/Sema/SemaExceptionSpec.cpp @@ -1045,6 +1045,7 @@ case Expr::ShuffleVectorExprClass: case Expr::ConvertVectorExprClass: case Expr::VAArgExprClass: + case Expr::CallWithStaticChainExprClass: return canSubExprsThrow(*this, E); // Some might be dependent for other reasons. Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -10839,6 +10839,48 @@ return new (Context) GNUNullExpr(Ty, TokenLoc); } +ExprResult Sema::ActOnCallWithStaticChain(SourceLocation BuiltinLoc, Expr *Call, + Expr *Chain, SourceLocation RPLoc) { + if (Call->getStmtClass() != Stmt::CallExprClass) { + Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_not_call) + << Call->getSourceRange(); + return ExprError(); + } + + auto CE = cast(Call); + if (CE->getCallee()->getType()->isBlockPointerType()) { + Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_block_call) + << Call->getSourceRange(); + return ExprError(); + } + + const Decl *TargetDecl = CE->getCalleeDecl(); + if (const FunctionDecl *FD = dyn_cast_or_null(TargetDecl)) + if (FD->getBuiltinID()) { + Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_builtin_call) + << Call->getSourceRange(); + return ExprError(); + } + + if (isa(CE->getCallee()->IgnoreParens())) { + Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_pdtor_call) + << Call->getSourceRange(); + return ExprError(); + } + + ExprResult ChainResult = UsualUnaryConversions(Chain); + if (ChainResult.isInvalid()) + return ExprError(); + if (!ChainResult.get()->getType()->isPointerType()) { + Diag(BuiltinLoc, diag::err_second_argument_to_cwsc_not_pointer) + << Chain->getSourceRange(); + return ExprError(); + } + + return new (Context) CallWithStaticChainExpr( + cast(Call), ChainResult.get(), BuiltinLoc, RPLoc); +} + bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp) { if (!getLangOpts().ObjC1) Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -2828,6 +2828,13 @@ RParenLoc); } + ExprResult RebuildCallWithStaticChainExpr(SourceLocation BuiltinLoc, + Expr *Call, Expr *Chain, + SourceLocation RParenLoc) { + return getSema().ActOnCallWithStaticChain(BuiltinLoc, Call, Chain, + RParenLoc); + } + private: TypeLoc TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType, @@ -10361,6 +10368,26 @@ RetTy, E->getOp(), E->getRParenLoc()); } +template +ExprResult TreeTransform::TransformCallWithStaticChainExpr( + CallWithStaticChainExpr *E) { + ExprResult Call = getDerived().TransformExpr(E->getCallExpr()); + if (Call.isInvalid()) + return ExprError(); + + ExprResult Chain = getDerived().TransformExpr(E->getChainExpr()); + if (Chain.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + Call.get() == E->getCallExpr() && + Chain.get() == E->getChainExpr()) + return E; + + return getDerived().RebuildCallWithStaticChainExpr( + E->getBuiltinLoc(), Call.get(), Chain.get(), E->getRParenLoc()); +} + //===----------------------------------------------------------------------===// // Type reconstruction //===----------------------------------------------------------------------===// Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -911,6 +911,14 @@ E->RParenLoc = ReadSourceLocation(Record, Idx); } +void ASTStmtReader::VisitCallWithStaticChainExpr(CallWithStaticChainExpr *E) { + VisitExpr(E); + E->SubExprs[CallWithStaticChainExpr::CALL] = Reader.ReadSubExpr(); + E->SubExprs[CallWithStaticChainExpr::CHAIN] = Reader.ReadSubExpr(); + E->BuiltinLoc = ReadSourceLocation(Record, Idx); + E->RParenLoc = ReadSourceLocation(Record, Idx); +} + //===----------------------------------------------------------------------===// // Objective-C Expressions and Statements @@ -2955,6 +2963,10 @@ NumArrayIndexVars); break; } + + case EXPR_CALL_WITH_STATIC_CHAIN: + S = new (Context) CallWithStaticChainExpr(Empty); + break; } // We hit a STMT_STOP, so we're done with this expression. Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -854,6 +854,15 @@ Code = serialization::EXPR_ATOMIC; } +void ASTStmtWriter::VisitCallWithStaticChainExpr(CallWithStaticChainExpr *E) { + VisitExpr(E); + Writer.AddStmt(E->getCallExpr()); + Writer.AddStmt(E->getChainExpr()); + Writer.AddSourceLocation(E->getBuiltinLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = serialization::EXPR_CALL_WITH_STATIC_CHAIN; +} + //===----------------------------------------------------------------------===// // Objective-C Expressions and Statements. //===----------------------------------------------------------------------===// Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -770,7 +770,8 @@ case Stmt::SEHExceptStmtClass: case Stmt::SEHLeaveStmtClass: case Stmt::LambdaExprClass: - case Stmt::SEHFinallyStmtClass: { + case Stmt::SEHFinallyStmtClass: + case Stmt::CallWithStaticChainExprClass: { const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); Engine.addAbortedBlock(node, currBldrCtx->getBlock()); break; Index: test/CodeGenCXX/cwsc.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/cwsc.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK32 %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix=CHECK64 %s + +struct A { + long x, y; +}; + +struct B { + long x, y, z, w; +}; + +extern "C" { + +int f1(A, A, A, A); +B f2(void); +_Complex float f3(void); +A &f4(); + +} + +void test() { + A a; + + // CHECK32: call i32 bitcast (i32 (%struct.A*, %struct.A*, %struct.A*, %struct.A*)* @f1 to i32 (i8*, %struct.A*, %struct.A*, %struct.A*, %struct.A*)*)(i8* nest bitcast (i32 (%struct.A*, %struct.A*, %struct.A*, %struct.A*)* @f1 to i8*) + // CHECK64: call i32 bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i32 (i8*, i64, i64, i64, i64, i64, i64, %struct.A*)*)(i8* nest bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i8*) + __builtin_call_with_static_chain(f1(a, a, a, a), f1); + + // CHECK32: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) + // CHECK64: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) + __builtin_call_with_static_chain(f2(), f2); + + // CHECK32: call i64 bitcast (i64 ()* @f3 to i64 (i8*)*)(i8* nest bitcast (i64 ()* @f3 to i8*)) + // CHECK64: call <2 x float> bitcast (<2 x float> ()* @f3 to <2 x float> (i8*)*)(i8* nest bitcast (<2 x float> ()* @f3 to i8*)) + __builtin_call_with_static_chain(f3(), f3); + + // CHECK32: call dereferenceable(8) %struct.A* bitcast (%struct.A* ()* @f4 to %struct.A* (i8*)*)(i8* nest bitcast (%struct.A* ()* @f4 to i8*)) + // CHECK64: call dereferenceable(16) %struct.A* bitcast (%struct.A* ()* @f4 to %struct.A* (i8*)*)(i8* nest bitcast (%struct.A* ()* @f4 to i8*)) + __builtin_call_with_static_chain(f4(), f4); +} Index: test/Sema/cwsc.c =================================================================== --- /dev/null +++ test/Sema/cwsc.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s + +void f(); + +void g() { + __builtin_call_with_static_chain(f(), f); + __builtin_call_with_static_chain(f, f); // expected-error {{first argument to __builtin_call_with_static_chain must be a non-member call expression}} + __builtin_call_with_static_chain(^{}(), f); // expected-error {{first argument to __builtin_call_with_static_chain must not be a block call}} + __builtin_call_with_static_chain(__builtin_unreachable(), f); // expected-error {{first argument to __builtin_call_with_static_chain must not be a builtin call}} + __builtin_call_with_static_chain(f(), 42); // expected-error {{second argument to __builtin_call_with_static_chain must be of pointer type}} +} Index: test/SemaCXX/cwsc.cpp =================================================================== --- /dev/null +++ test/SemaCXX/cwsc.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +int &f(); + +struct A { + void f(); +}; + +typedef int I; + +void g() { + __builtin_call_with_static_chain(f(), f) = 42; + __builtin_call_with_static_chain(A().f(), f); // expected-error {{first argument to __builtin_call_with_static_chain must be a non-member call expression}} + __builtin_call_with_static_chain((42).~I(), f); // expected-error {{first argument to __builtin_call_with_static_chain must not be a pseudo-destructor call}} +} Index: tools/libclang/CXCursor.cpp =================================================================== --- tools/libclang/CXCursor.cpp +++ tools/libclang/CXCursor.cpp @@ -253,6 +253,7 @@ case Stmt::ObjCDictionaryLiteralClass: case Stmt::ObjCBoxedExprClass: case Stmt::ObjCSubscriptRefExprClass: + case Stmt::CallWithStaticChainExprClass: K = CXCursor_UnexposedExpr; break;