================
@@ -647,6 +647,198 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction
&cgf, const CXXNewExpr *e,
return size;
}
+/// Emit a call to an operator new or operator delete function, as implicitly
+/// created by new-expressions and delete-expressions.
+static RValue emitNewDeleteCall(CIRGenFunction &cgf,
+ const FunctionDecl *calleeDecl,
+ const FunctionProtoType *calleeType,
+ const CallArgList &args) {
+ cir::CIRCallOpInterface callOrTryCall;
+ cir::FuncOp calleePtr = cgf.cgm.getAddrOfFunction(calleeDecl);
+ CIRGenCallee callee =
+ CIRGenCallee::forDirect(calleePtr, GlobalDecl(calleeDecl));
+ RValue rv =
+ cgf.emitCall(cgf.cgm.getTypes().arrangeFreeFunctionCall(args,
calleeType),
+ callee, ReturnValueSlot(), args, &callOrTryCall);
+
+ /// 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.
+ assert(!cir::MissingFeatures::attributeBuiltin());
+ return rv;
+}
+
+RValue CIRGenFunction::emitNewOrDeleteBuiltinCall(const FunctionProtoType
*type,
+ const CallExpr *callExpr,
+ OverloadedOperatorKind op) {
+ CallArgList args;
+ emitCallArgs(args, type, callExpr->arguments());
+ // Find the allocation or deallocation function that we're calling.
+ ASTContext &astContext = getContext();
+ assert(op == OO_New || op == OO_Delete);
+ DeclarationName name = astContext.DeclarationNames.getCXXOperatorName(op);
+
+ clang::DeclContextLookupResult lookupResult =
+ astContext.getTranslationUnitDecl()->lookup(name);
+ for (const auto *decl : lookupResult) {
+ if (const auto *funcDecl = dyn_cast<FunctionDecl>(decl)) {
+ if (astContext.hasSameType(funcDecl->getType(), QualType(type, 0))) {
+ if (sanOpts.has(SanitizerKind::AllocToken)) {
+ // TODO: Set !alloc_token metadata.
+ assert(!cir::MissingFeatures::allocToken());
+ cgm.errorNYI("Alloc token sanitizer not yet supported!");
+ }
+
+ // Emit the call to operator new/delete.
+ return emitNewDeleteCall(*this, funcDecl, type, args);
+ }
+ }
+ }
+
+ llvm_unreachable("predeclared global operator new/delete is missing");
+}
+
+namespace {
+/// A cleanup to call the given 'operator delete' function upon abnormal
+/// exit from a new expression. Templated on a traits type that deals with
+/// ensuring that the arguments dominate the cleanup if necessary.
+template <typename Traits>
+class CallDeleteDuringNew final : public EHScopeStack::Cleanup {
+ /// Type used to hold llvm::Value*s.
+ typedef typename Traits::ValueTy ValueTy;
+ /// Type used to hold RValues.
+ typedef typename Traits::RValueTy RValueTy;
+ struct PlacementArg {
+ RValueTy argValue;
+ QualType argType;
+ };
+
+ unsigned numPlacementArgs : 30;
+ LLVM_PREFERRED_TYPE(AlignedAllocationMode)
+ unsigned passAlignmentToPlacementDelete : 1;
+ const FunctionDecl *operatorDelete;
+ ValueTy ptr;
+ ValueTy allocSize;
+ CharUnits allocAlign;
+
+ PlacementArg *getPlacementArgs() {
+ return reinterpret_cast<PlacementArg *>(this + 1);
----------------
erichkeane wrote:
Ooof... this is frightening to see. Any way we can use trailing storage or
something like that?
https://github.com/llvm/llvm-project/pull/184707
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits