diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Decl.cpp | 50 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprCXX.cpp | 53 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 6 |
3 files changed, 91 insertions, 18 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 0ad15fc683e..4ecb41b3f0b 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2132,13 +2132,18 @@ void FunctionDecl::setPure(bool P) { Parent->markedVirtualFunctionPure(); } +template<std::size_t Len> +static bool isNamed(const NamedDecl *ND, const char (&Str)[Len]) { + IdentifierInfo *II = ND->getIdentifier(); + return II && II->isStr(Str); +} + bool FunctionDecl::isMain() const { const TranslationUnitDecl *tunit = dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()); return tunit && !tunit->getASTContext().getLangOpts().Freestanding && - getIdentifier() && - getIdentifier()->isStr("main"); + isNamed(this, "main"); } bool FunctionDecl::isReservedGlobalPlacementOperator() const { @@ -2163,6 +2168,47 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const { return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy); } +static bool isNamespaceStd(const DeclContext *DC) { + const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC->getRedeclContext()); + return ND && isNamed(ND, "std") && + ND->getParent()->getRedeclContext()->isTranslationUnit(); +} + +bool FunctionDecl::isReplaceableGlobalAllocationFunction() const { + if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName) + return false; + if (getDeclName().getCXXOverloadedOperator() != OO_New && + getDeclName().getCXXOverloadedOperator() != OO_Delete && + getDeclName().getCXXOverloadedOperator() != OO_Array_New && + getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) + return false; + + if (isa<CXXRecordDecl>(getDeclContext())) + return false; + assert(getDeclContext()->getRedeclContext()->isTranslationUnit()); + + const FunctionProtoType *FPT = getType()->castAs<FunctionProtoType>(); + if (FPT->getNumArgs() > 2 || FPT->isVariadic()) + return false; + + // If this is a single-parameter function, it must be a replaceable global + // allocation or deallocation function. + if (FPT->getNumArgs() == 1) + return true; + + // Otherwise, we're looking for a second parameter whose type is + // 'const std::nothrow_t &'. + QualType Ty = FPT->getArgType(1); + if (!Ty->isReferenceType()) + return false; + Ty = Ty->getPointeeType(); + if (Ty.getCVRQualifiers() != Qualifiers::Const) + return false; + // FIXME: Recognise nothrow_t in an inline namespace inside std? + const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + return RD && isNamed(RD, "nothrow_t") && isNamespaceStd(RD->getDeclContext()); +} + LanguageLinkage FunctionDecl::getLanguageLinkage() const { // Users expect to be able to write // extern "C" void *__builtin_alloca (size_t); diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 672e86d0d8f..1520656c9b8 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -1002,6 +1002,38 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr); } +/// Emit a call to an operator new or operator delete function, as implicitly +/// created by new-expressions and delete-expressions. +static RValue EmitNewDeleteCall(CodeGenFunction &CGF, + const FunctionDecl *Callee, + const FunctionProtoType *CalleeType, + const CallArgList &Args) { + llvm::Instruction *CallOrInvoke; + RValue RV = + CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(Args, CalleeType), + CGF.CGM.GetAddrOfFunction(Callee), ReturnValueSlot(), Args, + Callee, &CallOrInvoke); + + /// C++1y [expr.new]p10: + /// [In a new-expression,] an implementation is allowed to omit a call + /// to a replaceable global allocation function. + /// + /// We model such elidable calls with the 'builtin' attribute. + if (Callee->isReplaceableGlobalAllocationFunction()) { + // FIXME: Add addAttribute to CallSite. + if (llvm::CallInst *CI = dyn_cast<llvm::CallInst>(CallOrInvoke)) + CI->addAttribute(llvm::AttributeSet::FunctionIndex, + llvm::Attribute::Builtin); + else if (llvm::InvokeInst *II = dyn_cast<llvm::InvokeInst>(CallOrInvoke)) + II->addAttribute(llvm::AttributeSet::FunctionIndex, + llvm::Attribute::Builtin); + else + llvm_unreachable("unexpected kind of call instruction"); + } + + return RV; +} + namespace { /// A cleanup to call the given 'operator delete' function upon /// abnormal exit from a new expression. @@ -1051,9 +1083,7 @@ namespace { DeleteArgs.add(getPlacementArgs()[I], *AI++); // Call 'operator delete'. - CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(DeleteArgs, FPT), - CGF.CGM.GetAddrOfFunction(OperatorDelete), - ReturnValueSlot(), DeleteArgs, OperatorDelete); + EmitNewDeleteCall(CGF, OperatorDelete, FPT, DeleteArgs); } }; @@ -1112,9 +1142,7 @@ namespace { } // Call 'operator delete'. - CGF.EmitCall(CGF.CGM.getTypes().arrangeFreeFunctionCall(DeleteArgs, FPT), - CGF.CGM.GetAddrOfFunction(OperatorDelete), - ReturnValueSlot(), DeleteArgs, OperatorDelete); + EmitNewDeleteCall(CGF, OperatorDelete, FPT, DeleteArgs); } }; } @@ -1227,10 +1255,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // TODO: kill any unnecessary computations done for the size // argument. } else { - RV = EmitCall(CGM.getTypes().arrangeFreeFunctionCall(allocatorArgs, - allocatorType), - CGM.GetAddrOfFunction(allocator), ReturnValueSlot(), - allocatorArgs, allocator); + RV = EmitNewDeleteCall(*this, allocator, allocatorType, allocatorArgs); } // Emit a null check on the allocation result if the allocation @@ -1350,9 +1375,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, DeleteArgs.add(RValue::get(Size), SizeTy); // Emit the call to delete. - EmitCall(CGM.getTypes().arrangeFreeFunctionCall(DeleteArgs, DeleteFTy), - CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(), - DeleteArgs, DeleteFD); + EmitNewDeleteCall(*this, DeleteFD, DeleteFTy, DeleteArgs); } namespace { @@ -1508,9 +1531,7 @@ namespace { } // Emit the call to delete. - CGF.EmitCall(CGF.getTypes().arrangeFreeFunctionCall(Args, DeleteFTy), - CGF.CGM.GetAddrOfFunction(OperatorDelete), - ReturnValueSlot(), Args, OperatorDelete); + EmitNewDeleteCall(CGF, OperatorDelete, DeleteFTy, Args); } }; } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index af6a0113f2d..53efaa6349f 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -744,6 +744,12 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, if (const SectionAttr *SA = FD->getAttr<SectionAttr>()) F->setSection(SA->getName()); + + // A replaceable global allocation function does not act like a builtin by + // default, only if it is invoked by a new-expression or delete-expression. + if (FD->isReplaceableGlobalAllocationFunction()) + F->addAttribute(llvm::AttributeSet::FunctionIndex, + llvm::Attribute::NoBuiltin); } void CodeGenModule::AddUsedGlobal(llvm::GlobalValue *GV) { |