Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -1371,8 +1371,9 @@ // Clang builtins (not available in GCC). BUILTIN(__builtin_addressof, "v*v&", "nct") -BUILTIN(__builtin_operator_new, "v*z", "c") -BUILTIN(__builtin_operator_delete, "vv*", "n") +BUILTIN(__builtin_operator_new, "v*z", "tc") +BUILTIN(__builtin_operator_delete, "vv*", "tn") + BUILTIN(__builtin_char_memchr, "c*cC*iz", "n") // Safestack builtins Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -10363,6 +10363,8 @@ ExprResult SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult); ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op); + ExprResult SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, + bool IsDelete); bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -2611,11 +2611,12 @@ case Builtin::BI__builtin_addressof: return RValue::get(EmitLValue(E->getArg(0)).getPointer()); case Builtin::BI__builtin_operator_new: - return EmitBuiltinNewDeleteCall(FD->getType()->castAs(), - E->getArg(0), false); + return EmitBuiltinNewDeleteCall( + E->getCallee()->getType()->castAs(), E, false); case Builtin::BI__builtin_operator_delete: - return EmitBuiltinNewDeleteCall(FD->getType()->castAs(), - E->getArg(0), true); + return EmitBuiltinNewDeleteCall( + E->getCallee()->getType()->castAs(), E, true); + case Builtin::BI__noop: // __noop always evaluates to an integer literal zero. return RValue::get(ConstantInt::get(IntTy, 0)); Index: lib/CodeGen/CGExprCXX.cpp =================================================================== --- lib/CodeGen/CGExprCXX.cpp +++ lib/CodeGen/CGExprCXX.cpp @@ -1307,19 +1307,19 @@ } RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type, - const Expr *Arg, + const CallExpr *TheCall, bool IsDelete) { CallArgList Args; - const Stmt *ArgS = Arg; - EmitCallArgs(Args, *Type->param_type_begin(), llvm::makeArrayRef(ArgS)); + EmitCallArgs(Args, Type->getParamTypes(), TheCall->arguments()); // Find the allocation or deallocation function that we're calling. ASTContext &Ctx = getContext(); DeclarationName Name = Ctx.DeclarationNames .getCXXOperatorName(IsDelete ? OO_Delete : OO_New); + for (auto *Decl : Ctx.getTranslationUnitDecl()->lookup(Name)) if (auto *FD = dyn_cast(Decl)) if (Ctx.hasSameType(FD->getType(), QualType(Type, 0))) - return EmitNewDeleteCall(*this, cast(Decl), Type, Args); + return EmitNewDeleteCall(*this, FD, Type, Args); llvm_unreachable("predeclared global operator new/delete is missing"); } Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -2346,7 +2346,7 @@ CharUnits CookieSize = CharUnits()); RValue EmitBuiltinNewDeleteCall(const FunctionProtoType *Type, - const Expr *Arg, bool IsDelete); + const CallExpr *TheCallExpr, bool IsDelete); llvm::Value *EmitCXXTypeidExpr(const CXXTypeidExpr *E); llvm::Value *EmitDynamicCast(Address V, const CXXDynamicCastExpr *DCE); Index: lib/Lex/PPMacroExpansion.cpp =================================================================== --- lib/Lex/PPMacroExpansion.cpp +++ lib/Lex/PPMacroExpansion.cpp @@ -1800,12 +1800,20 @@ [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, diag::err_feature_check_malformed); + const LangOptions &LangOpts = getLangOpts(); if (!II) return false; - else if (II->getBuiltinID() != 0) + else if (II->getBuiltinID() != 0) { + switch (II->getBuiltinID()) { + case Builtin::BI__builtin_operator_new: + case Builtin::BI__builtin_operator_delete: { + return 201802; + } + default: + return true; + } return true; - else { - const LangOptions &LangOpts = getLangOpts(); + } else { return llvm::StringSwitch(II->getName()) .Case("__make_integer_seq", LangOpts.CPlusPlus) .Case("__type_pack_element", LangOpts.CPlusPlus) Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -1097,20 +1097,14 @@ return ExprError(); break; case Builtin::BI__builtin_operator_new: - case Builtin::BI__builtin_operator_delete: - if (!getLangOpts().CPlusPlus) { - Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) - << (BuiltinID == Builtin::BI__builtin_operator_new - ? "__builtin_operator_new" - : "__builtin_operator_delete") - << "C++"; - return ExprError(); - } - // CodeGen assumes it can find the global new and delete to call, - // so ensure that they are declared. - DeclareGlobalNewDelete(); - break; - + case Builtin::BI__builtin_operator_delete: { + bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete; + ExprResult Res = + SemaBuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); + if (Res.isInvalid()) + CorrectDelayedTyposInExpr(TheCallResult.get()); + return Res; + } // check secure string manipulation functions where overflows // are detectable at compile time case Builtin::BI__builtin___memcpy_chk: Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -1442,7 +1442,7 @@ CUDAPref = S.IdentifyCUDAPreference(Caller, FD); } - operator bool() const { return FD; } + explicit operator bool() const { return FD; } bool isBetterThan(const UsualDeallocFnInfo &Other, bool WantSize, bool WantAlign) const { @@ -2266,7 +2266,6 @@ llvm_unreachable("Unreachable, bad result from BestViableFunction"); } - /// FindAllocationFunctions - Finds the overloads of operator new and delete /// that are appropriate for the allocation. bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, @@ -3336,6 +3335,142 @@ return Result; } +static bool resolveBuiltinNewDeleteOverload(Sema &S, LookupResult &R, + SourceRange Range, + SmallVectorImpl &Args, + FunctionDecl *&Operator) { + OverloadCandidateSet Candidates(R.getNameLoc(), + OverloadCandidateSet::CSK_Normal); + for (LookupResult::iterator FnOvl = R.begin(), FnOvlEnd = R.end(); + FnOvl != FnOvlEnd; ++FnOvl) { + // Even member operator new/delete are implicitly treated as + // static, so don't use AddMemberCandidate. + NamedDecl *D = (*FnOvl)->getUnderlyingDecl(); + + if (FunctionTemplateDecl *FnTemplate = dyn_cast(D)) { + S.AddTemplateOverloadCandidate(FnTemplate, FnOvl.getPair(), + /*ExplicitTemplateArgs=*/nullptr, Args, + Candidates, + /*SuppressUserConversions=*/false); + continue; + } + + FunctionDecl *Fn = cast(D); + S.AddOverloadCandidate(Fn, FnOvl.getPair(), Args, Candidates, + /*SuppressUserConversions=*/false); + } + + // Do the resolution. + OverloadCandidateSet::iterator Best; + switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) { + case OR_Success: { + // Got one! + FunctionDecl *FnDecl = Best->Function; + if (S.CheckAllocationAccess(R.getNameLoc(), Range, R.getNamingClass(), + Best->FoundDecl) == Sema::AR_inaccessible) + return true; + + if (!FnDecl->isReplaceableGlobalAllocationFunction()) { + S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) + << R.getLookupName() << Range; + return true; + } + + Operator = FnDecl; + return false; + } + + case OR_No_Viable_Function: + S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) + << R.getLookupName() << Range; + Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + return true; + + case OR_Ambiguous: + S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) + << R.getLookupName() << Range; + Candidates.NoteCandidates(S, OCD_ViableCandidates, Args); + return true; + + case OR_Deleted: { + S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call) + << Best->Function->isDeleted() << R.getLookupName() + << S.getDeletedOrUnavailableSuffix(Best->Function) << Range; + Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + return true; + } + } + llvm_unreachable("Unreachable, bad result from BestViableFunction"); +} + +ExprResult +Sema::SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, + bool IsDelete) { + CallExpr *TheCall = cast(TheCallResult.get()); + if (!getLangOpts().CPlusPlus) { + Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) + << (IsDelete ? "__builtin_operator_delete" : "__builtin_operator_new") + << "C++"; + return ExprError(); + } + // CodeGen assumes it can find the global new and delete to call, + // so ensure that they are declared. + DeclareGlobalNewDelete(); + + TheCall->setType(IsDelete ? Context.VoidTy : Context.VoidPtrTy); + + if (TheCall->getNumArgs() < 1) { + Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 << 1 << TheCall->getNumArgs() + << TheCall->getCallee()->getSourceRange(); + return ExprError(); + } else if (TheCall->getNumArgs() > 2) { + Diag(TheCall->getArg(2)->getLocStart(), + diag::err_typecheck_call_too_many_args) + << 0 << 2 << TheCall->getNumArgs() + << TheCall->getCallee()->getSourceRange(); + return ExprError(); + } + + llvm::SmallVector ArgTypes; + ArgTypes.push_back(IsDelete ? Context.VoidPtrTy : Context.getSizeType()); + + + DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( + IsDelete ? OO_Delete : OO_New); + + FunctionDecl *OperatorNewOrDelete = nullptr; + { + LookupResult R(*this, NewName, TheCall->getLocStart(), LookupOrdinaryName); + LookupQualifiedName(R, Context.getTranslationUnitDecl()); + assert(!R.empty() && "implicitly declared allocation functions not found"); + assert(!R.isAmbiguous() && "global allocation functions are ambiguous"); + + // We do our own custom access checks below. + R.suppressDiagnostics(); + + SmallVector Args(TheCall->arg_begin(), TheCall->arg_end()); + if (resolveBuiltinNewDeleteOverload(*this, R, TheCall->getSourceRange(), + Args, OperatorNewOrDelete)) + return ExprError(); + assert(OperatorNewOrDelete && "should be found"); + + TheCall->getCallee()->setType(OperatorNewOrDelete->getType()); + for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) { + QualType ParamTy = OperatorNewOrDelete->getParamDecl(i)->getType(); + InitializedEntity Entity = + InitializedEntity::InitializeParameter(Context, ParamTy, false); + ExprResult Arg = PerformCopyInitialization(Entity, SourceLocation(), + TheCall->getArg(i)); + if (Arg.isInvalid()) + return ExprError(); + TheCall->setArg(i, Arg.get()); + } + } + + return TheCallResult; +} + void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, Index: test/CodeGenCXX/new.cpp =================================================================== --- test/CodeGenCXX/new.cpp +++ test/CodeGenCXX/new.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -verify -faligned-allocation \ +// RUN: -emit-llvm -o - | FileCheck %s typedef __typeof__(sizeof(0)) size_t; @@ -363,6 +364,12 @@ // CHECK: call void @_ZdlPv({{.*}}) [[ATTR_BUILTIN_DELETE]] __builtin_operator_delete(__builtin_operator_new(4)); } + // CHECK-LABEL: define void @_ZN8builtins1gEv + void g() { + // CHECK: call i8* @_ZnwmSt11align_val_t(i64 4, i64 4) [[ATTR_BUILTIN_NEW]] + // CHECK: call void @_ZdlPvSt11align_val_t({{.*}}, i64 4) [[ATTR_BUILTIN_DELETE]] + __builtin_operator_delete(__builtin_operator_new(4, 4), 4); + } } // CHECK-DAG: attributes [[ATTR_NOBUILTIN]] = {{[{].*}} nobuiltin {{.*[}]}} Index: test/Preprocessor/builtin_operator_new_delete.cpp =================================================================== --- /dev/null +++ test/Preprocessor/builtin_operator_new_delete.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 %s -fsyntax-only -verify +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 %s -fsyntax-only -verify +// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 %s -fsyntax-only -verify + +// expected-no-diagnostics + +#if __has_builtin(__builtin_operator_new) != __has_builtin(__builtin_operator_delete) +#error builtins should report same value +#endif + +#if !__has_builtin(__builtin_operator_new) || !__has_builtin(__builtin_operator_delete) +#error builtins should always be available +#endif + +#if __has_builtin(__builtin_operator_new) != 201802L || \ + __has_builtin(__builtin_operator_delete) != 201802L +#error builtin should report updated value +#endif + Index: test/SemaCXX/builtin-operator-new-delete-alignment-disabled.cpp =================================================================== --- /dev/null +++ test/SemaCXX/builtin-operator-new-delete-alignment-disabled.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -std=c++03 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++03 -faligned-allocation -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++1z -fno-aligned-allocation -fsyntax-only -verify %s + +void test_disabled() { +#ifdef __cpp_aligned_new + // expected-no-diagnostics +#else + // expected-error@+3 {{__builtin_operator_new with alignment requires aligned allocation support; use -faligned-allocation to enable}} + // expected-error@+3 {{__builtin_operator_delete with alignment requires aligned allocation support; use -faligned-allocation to enable}} +#endif + (void)__builtin_operator_new(1, 2); + __builtin_operator_delete((void *)0, 2); +} Index: test/SemaCXX/builtin-operator-new-delete.cpp =================================================================== --- /dev/null +++ test/SemaCXX/builtin-operator-new-delete.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++03 -faligned-allocation -fsyntax-only -verify %s + +void *NP = 0; + +void test_signature() { + __builtin_operator_new(); // expected-error {{too few arguments to function call, expected 1, have 0}} + __builtin_operator_new(0, 0, 0); // expected-error {{too many arguments to function call, expected 2, have 3}} + __builtin_operator_delete(); // expected-error {{too few arguments to function call, expected 1, have 0}} + __builtin_operator_delete(0, 0, 0); // expected-error {{too many arguments to function call, expected 2, have 3}} +} + +void test_typo_in_args() { + __builtin_operator_new(DNE); // expected-error {{undeclared identifier 'DNE'}} + __builtin_operator_new(DNE, DNE2); // expected-error {{undeclared identifier 'DNE'}} expected-error {{'DNE2'}} + __builtin_operator_delete(DNE); // expected-error {{'DNE'}} + __builtin_operator_delete(DNE, DNE2); // expected-error {{'DNE'}} expected-error {{'DNE2'}} +} + +void test_arg_types() { + __builtin_operator_new(NP); // expected-error {{cannot initialize a parameter of type 'unsigned long' with an lvalue of type 'void *'}} + __builtin_operator_new(NP, 0); // expected-error {{cannot initialize a parameter of type 'unsigned long' with an lvalue of type 'void *'}} +} + +void test_return_type() { + int w = __builtin_operator_new(42); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}} + int x = __builtin_operator_new(42, 42); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}} + int y = __builtin_operator_delete(NP); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void'}} + int z = __builtin_operator_delete(NP, 42); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void'}} +}