Just waiting on a build. It should be fixed shortly. Sorry about the breakage.
/Eric On Thu, Mar 22, 2018 at 11:56 AM, Eric Fiselier <e...@efcs.ca> wrote: > Sorry, I didn't see the failure yesterday. > > I'll get on it or revert it. > > On Thu, Mar 22, 2018 at 11:51 AM, Galina Kistanova <gkistan...@gmail.com> > wrote: > >> Hello Eric, >> >> One of added tests fails on the next builder: >> http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensiv >> e-checks-win/builds/8624 >> >> . . . >> Failing Tests: >> . . . >> Clang :: SemaCXX/builtin-operator-new-delete.cpp >> >> Please have a look? >> >> It is not good idea to keep the bot red for too long. This hides new >> problem which later hard to track down. >> >> Thanks >> >> Galina >> >> >> On Wed, Mar 21, 2018 at 12:19 PM, Eric Fiselier via cfe-commits < >> cfe-commits@lists.llvm.org> wrote: >> >>> Author: ericwf >>> Date: Wed Mar 21 12:19:48 2018 >>> New Revision: 328134 >>> >>> URL: http://llvm.org/viewvc/llvm-project?rev=328134&view=rev >>> Log: >>> [Builtins] Overload __builtin_operator_new/delete to allow forwarding to >>> usual allocation/deallocation functions. >>> >>> Summary: >>> Libc++'s default allocator uses `__builtin_operator_new` and >>> `__builtin_operator_delete` in order to allow the calls to new/delete to be >>> ellided. However, libc++ now needs to support over-aligned types in the >>> default allocator. In order to support this without disabling the existing >>> optimization Clang needs to support calling the aligned new overloads from >>> the builtins. >>> >>> See llvm.org/PR22634 for more information about the libc++ bug. >>> >>> This patch changes `__builtin_operator_new`/`__builtin_operator_delete` >>> to call any usual `operator new`/`operator delete` function. It does this >>> by performing overload resolution with the arguments passed to the builtin >>> to determine which allocation function to call. If the selected function is >>> not a usual allocation function a diagnostic is issued. >>> >>> One open issue is if the `align_val_t` overloads should be considered >>> "usual" when `LangOpts::AlignedAllocation` is disabled. >>> >>> >>> In order to allow libc++ to detect this new behavior the value for >>> `__has_builtin(__builtin_operator_new)` has been updated to `201802`. >>> >>> Reviewers: rsmith, majnemer, aaron.ballman, erik.pilkington, bogner, >>> ahatanak >>> >>> Reviewed By: rsmith >>> >>> Subscribers: cfe-commits >>> >>> Differential Revision: https://reviews.llvm.org/D43047 >>> >>> Added: >>> cfe/trunk/test/CodeGenCXX/builtin-operator-new-delete.cpp >>> cfe/trunk/test/SemaCXX/builtin-operator-new-delete.cpp >>> Modified: >>> cfe/trunk/include/clang/Basic/Builtins.def >>> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td >>> cfe/trunk/include/clang/Sema/Sema.h >>> cfe/trunk/lib/CodeGen/CGBuiltin.cpp >>> cfe/trunk/lib/CodeGen/CGExprCXX.cpp >>> cfe/trunk/lib/CodeGen/CodeGenFunction.h >>> cfe/trunk/lib/Lex/PPMacroExpansion.cpp >>> cfe/trunk/lib/Sema/SemaChecking.cpp >>> cfe/trunk/lib/Sema/SemaExprCXX.cpp >>> >>> Modified: cfe/trunk/include/clang/Basic/Builtins.def >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ >>> Basic/Builtins.def?rev=328134&r1=328133&r2=328134&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/include/clang/Basic/Builtins.def (original) >>> +++ cfe/trunk/include/clang/Basic/Builtins.def Wed Mar 21 12:19:48 2018 >>> @@ -1371,8 +1371,8 @@ BUILTIN(__builtin_smulll_overflow, "bSLL >>> >>> // 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 >>> >>> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ >>> Basic/DiagnosticSemaKinds.td?rev=328134&r1=328133&r2=328134&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) >>> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Mar 21 >>> 12:19:48 2018 >>> @@ -7627,6 +7627,11 @@ def err_destroying_operator_delete_not_u >>> "alignment parameter">; >>> def note_implicit_delete_this_in_destructor_here : Note< >>> "while checking implicit 'delete this' for virtual destructor">; >>> +def err_builtin_operator_new_delete_not_usual : Error< >>> + "call to '%select{__builtin_operator_new|__builtin_operator_delete}0' >>> " >>> + "selects non-usual %select{allocation|deallocation}0 function">; >>> +def note_non_usual_function_declared_here : Note< >>> + "non-usual %0 declared here">; >>> >>> // C++ literal operators >>> def err_literal_operator_outside_namespace : Error< >>> >>> Modified: cfe/trunk/include/clang/Sema/Sema.h >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ >>> Sema/Sema.h?rev=328134&r1=328133&r2=328134&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/include/clang/Sema/Sema.h (original) >>> +++ cfe/trunk/include/clang/Sema/Sema.h Wed Mar 21 12:19:48 2018 >>> @@ -10376,6 +10376,8 @@ private: >>> 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, >>> >>> Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CG >>> Builtin.cpp?rev=328134&r1=328133&r2=328134&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original) >>> +++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Wed Mar 21 12:19:48 2018 >>> @@ -2611,11 +2611,12 @@ RValue CodeGenFunction::EmitBuiltinExpr( >>> case Builtin::BI__builtin_addressof: >>> return RValue::get(EmitLValue(E->getArg(0)).getPointer()); >>> case Builtin::BI__builtin_operator_new: >>> - return EmitBuiltinNewDeleteCall(FD->getType()->castAs<FunctionProto >>> Type>(), >>> - E->getArg(0), false); >>> + return EmitBuiltinNewDeleteCall( >>> + E->getCallee()->getType()->castAs<FunctionProtoType>(), E, >>> false); >>> case Builtin::BI__builtin_operator_delete: >>> - return EmitBuiltinNewDeleteCall(FD->getType()->castAs<FunctionProto >>> Type>(), >>> - E->getArg(0), true); >>> + return EmitBuiltinNewDeleteCall( >>> + E->getCallee()->getType()->castAs<FunctionProtoType>(), E, >>> true); >>> + >>> case Builtin::BI__noop: >>> // __noop always evaluates to an integer literal zero. >>> return RValue::get(ConstantInt::get(IntTy, 0)); >>> >>> Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CG >>> ExprCXX.cpp?rev=328134&r1=328133&r2=328134&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) >>> +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Wed Mar 21 12:19:48 2018 >>> @@ -1307,19 +1307,19 @@ static RValue EmitNewDeleteCall(CodeGenF >>> } >>> >>> 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<FunctionDecl>(Decl)) >>> if (Ctx.hasSameType(FD->getType(), QualType(Type, 0))) >>> - return EmitNewDeleteCall(*this, cast<FunctionDecl>(Decl), Type, >>> Args); >>> + return EmitNewDeleteCall(*this, FD, Type, Args); >>> llvm_unreachable("predeclared global operator new/delete is missing"); >>> } >>> >>> >>> Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/Co >>> deGenFunction.h?rev=328134&r1=328133&r2=328134&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original) >>> +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Mar 21 12:19:48 2018 >>> @@ -2356,7 +2356,7 @@ public: >>> 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); >>> >>> Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacr >>> oExpansion.cpp?rev=328134&r1=328133&r2=328134&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original) >>> +++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Wed Mar 21 12:19:48 2018 >>> @@ -1801,12 +1801,21 @@ void Preprocessor::ExpandBuiltinMacro(To >>> [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: >>> + // denotes date of behavior change to support calling >>> arbitrary >>> + // usual allocation and deallocation functions. Required by >>> libc++ >>> + return 201802; >>> + default: >>> + return true; >>> + } >>> return true; >>> - else { >>> - const LangOptions &LangOpts = getLangOpts(); >>> + } else { >>> return llvm::StringSwitch<bool>(II->getName()) >>> .Case("__make_integer_seq", LangOpts.CPlusPlus) >>> .Case("__type_pack_element", LangOpts.CPlusPlus) >>> >>> Modified: cfe/trunk/lib/Sema/SemaChecking.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaC >>> hecking.cpp?rev=328134&r1=328133&r2=328134&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) >>> +++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Mar 21 12:19:48 2018 >>> @@ -1097,20 +1097,14 @@ Sema::CheckBuiltinFunctionCall(FunctionD >>> 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: >>> >>> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaE >>> xprCXX.cpp?rev=328134&r1=328133&r2=328134&view=diff >>> ============================================================ >>> ================== >>> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) >>> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Mar 21 12:19:48 2018 >>> @@ -1443,7 +1443,7 @@ namespace { >>> 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 { >>> @@ -2271,7 +2271,6 @@ static bool resolveAllocationOverload( >>> 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, >>> @@ -3343,6 +3342,128 @@ Sema::ActOnCXXDelete(SourceLocation Star >>> return Result; >>> } >>> >>> +static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall, >>> + bool IsDelete, >>> + FunctionDecl *&Operator) { >>> + >>> + DeclarationName NewName = S.Context.DeclarationNames.get >>> CXXOperatorName( >>> + IsDelete ? OO_Delete : OO_New); >>> + >>> + LookupResult R(S, NewName, TheCall->getLocStart(), >>> Sema::LookupOrdinaryName); >>> + S.LookupQualifiedName(R, S.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<Expr *, 8> Args(TheCall->arg_begin(), TheCall->arg_end()); >>> + 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<FunctionTemplateDecl>(D)) { >>> + S.AddTemplateOverloadCandidate(FnTemplate, FnOvl.getPair(), >>> + /*ExplicitTemplateArgs=*/nullptr, >>> Args, >>> + Candidates, >>> + /*SuppressUserConversions=*/f >>> alse); >>> + continue; >>> + } >>> + >>> + FunctionDecl *Fn = cast<FunctionDecl>(D); >>> + S.AddOverloadCandidate(Fn, FnOvl.getPair(), Args, Candidates, >>> + /*SuppressUserConversions=*/false); >>> + } >>> + >>> + SourceRange Range = TheCall->getSourceRange(); >>> + >>> + // Do the resolution. >>> + OverloadCandidateSet::iterator Best; >>> + switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) { >>> + case OR_Success: { >>> + // Got one! >>> + FunctionDecl *FnDecl = Best->Function; >>> + assert(R.getNamingClass() == nullptr && >>> + "class members should not be considered"); >>> + >>> + if (!FnDecl->isReplaceableGlobalAllocationFunction()) { >>> + S.Diag(R.getNameLoc(), diag::err_builtin_operator_new >>> _delete_not_usual) >>> + << (IsDelete ? 1 : 0) << Range; >>> + S.Diag(FnDecl->getLocation(), diag::note_non_usual_function_ >>> declared_here) >>> + << R.getLookupName() << FnDecl->getSourceRange(); >>> + 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<CallExpr>(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(); >>> + >>> + FunctionDecl *OperatorNewOrDelete = nullptr; >>> + if (resolveBuiltinNewDeleteOverload(*this, TheCall, IsDelete, >>> + OperatorNewOrDelete)) >>> + return ExprError(); >>> + assert(OperatorNewOrDelete && "should be found"); >>> + >>> + TheCall->setType(OperatorNewOrDelete->getReturnType()); >>> + 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, TheCall->getArg(i)->getLocStart(), TheCall->getArg(i)); >>> + if (Arg.isInvalid()) >>> + return ExprError(); >>> + TheCall->setArg(i, Arg.get()); >>> + } >>> + auto Callee = dyn_cast<ImplicitCastExpr>(TheCall->getCallee()); >>> + assert(Callee && Callee->getCastKind() == CK_BuiltinFnToFnPtr && >>> + "Callee expected to be implicit cast to a builtin function >>> pointer"); >>> + Callee->setType(OperatorNewOrDelete->getType()); >>> + >>> + return TheCallResult; >>> +} >>> + >>> void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, >>> SourceLocation Loc, >>> bool IsDelete, bool CallCanBeVirtual, >>> bool WarnOnNonAbstractTypes, >>> >>> Added: cfe/trunk/test/CodeGenCXX/builtin-operator-new-delete.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCX >>> X/builtin-operator-new-delete.cpp?rev=328134&view=auto >>> ============================================================ >>> ================== >>> --- cfe/trunk/test/CodeGenCXX/builtin-operator-new-delete.cpp (added) >>> +++ cfe/trunk/test/CodeGenCXX/builtin-operator-new-delete.cpp Wed Mar >>> 21 12:19:48 2018 >>> @@ -0,0 +1,71 @@ >>> +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s \ >>> +// RUN: -faligned-allocation -fsized-deallocation -emit-llvm -o - \ >>> +// RUN: | FileCheck %s >>> + >>> +typedef __SIZE_TYPE__ size_t; >>> + >>> +// Declare an 'operator new' template to tickle a bug in >>> __builtin_operator_new. >>> +template<typename T> void *operator new(size_t, int (*)(T)); >>> + >>> +// Ensure that this declaration doesn't cause operator new to lose its >>> +// 'noalias' attribute. >>> +void *operator new(size_t); >>> + >>> +namespace std { >>> + struct nothrow_t {}; >>> + enum class align_val_t : size_t { __zero = 0, >>> + __max = (size_t)-1 }; >>> +} >>> +std::nothrow_t nothrow; >>> + >>> +// Declare the reserved placement operators. >>> +void *operator new(size_t, void*) throw(); >>> +void operator delete(void*, void*) throw(); >>> +void *operator new[](size_t, void*) throw(); >>> +void operator delete[](void*, void*) throw(); >>> + >>> +// Declare the replaceable global allocation operators. >>> +void *operator new(size_t, const std::nothrow_t &) throw(); >>> +void *operator new[](size_t, const std::nothrow_t &) throw(); >>> +void operator delete(void *, const std::nothrow_t &) throw(); >>> +void operator delete[](void *, const std::nothrow_t &) throw(); >>> + >>> +// Declare some other placement operators. >>> +void *operator new(size_t, void*, bool) throw(); >>> +void *operator new[](size_t, void*, bool) throw(); >>> + >>> + >>> +// CHECK-LABEL: define void @test_basic( >>> +extern "C" void test_basic() { >>> + // CHECK: call i8* @_Znwm(i64 4) [[ATTR_BUILTIN_NEW:#[^ ]*]] >>> + // CHECK: call void @_ZdlPv({{.*}}) [[ATTR_BUILTIN_DELETE:#[^ ]*]] >>> + // CHECK: ret void >>> + __builtin_operator_delete(__builtin_operator_new(4)); >>> +} >>> +// CHECK: declare noalias i8* @_Znwm(i64) [[ATTR_NOBUILTIN:#[^ ]*]] >>> +// CHECK: declare void @_ZdlPv(i8*) [[ATTR_NOBUILTIN_NOUNWIND:#[^ ]*]] >>> + >>> +// CHECK-LABEL: define void @test_aligned_alloc( >>> +extern "C" void test_aligned_alloc() { >>> + // 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, >>> std::align_val_t(4)), std::align_val_t(4)); >>> +} >>> +// CHECK: declare noalias i8* @_ZnwmSt11align_val_t(i64, i64) >>> [[ATTR_NOBUILTIN:#[^ ]*]] >>> +// CHECK: declare void @_ZdlPvSt11align_val_t(i8*, i64) >>> [[ATTR_NOBUILTIN_NOUNWIND:#[^ ]*]] >>> + >>> + >>> +// CHECK-LABEL: define void @test_sized_delete( >>> +extern "C" void test_sized_delete() { >>> + // CHECK: call i8* @_Znwm(i64 4) [[ATTR_BUILTIN_NEW:#[^ ]*]] >>> + // CHECK: call void @_ZdlPvm({{.*}}, i64 4) [[ATTR_BUILTIN_DELETE:#[^ >>> ]*]] >>> + __builtin_operator_delete(__builtin_operator_new(4), 4); >>> +} >>> +// CHECK: declare void @_ZdlPvm(i8*, i64) [[ATTR_NOBUILTIN_UNWIND:#[^ >>> ]*]] >>> + >>> + >>> +// CHECK-DAG: attributes [[ATTR_NOBUILTIN]] = {{[{].*}} nobuiltin >>> {{.*[}]}} >>> +// CHECK-DAG: attributes [[ATTR_NOBUILTIN_NOUNWIND]] = {{[{].*}} >>> nobuiltin nounwind {{.*[}]}} >>> + >>> +// CHECK-DAG: attributes [[ATTR_BUILTIN_NEW]] = {{[{].*}} builtin >>> {{.*[}]}} >>> +// CHECK-DAG: attributes [[ATTR_BUILTIN_DELETE]] = {{[{].*}} builtin >>> {{.*[}]}} >>> >>> Added: cfe/trunk/test/SemaCXX/builtin-operator-new-delete.cpp >>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/b >>> uiltin-operator-new-delete.cpp?rev=328134&view=auto >>> ============================================================ >>> ================== >>> --- cfe/trunk/test/SemaCXX/builtin-operator-new-delete.cpp (added) >>> +++ cfe/trunk/test/SemaCXX/builtin-operator-new-delete.cpp Wed Mar 21 >>> 12:19:48 2018 >>> @@ -0,0 +1,153 @@ >>> +// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s >>> +// 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++11 -fsyntax-only -verify %s >>> +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify >>> -fsized-deallocation %s >>> + >>> +#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 >>> + >>> +typedef __SIZE_TYPE__ size_t; >>> +namespace std { >>> + struct nothrow_t {}; >>> +#if __cplusplus >= 201103L >>> +enum class align_val_t : size_t {}; >>> +#else >>> + enum align_val_t { __zero = 0, >>> + __max = (size_t)-1 }; >>> +#endif >>> +} >>> +std::nothrow_t nothrow; >>> + >>> +void *operator new(size_t); // expected-note 1+ {{candidate function}} >>> +void operator delete(void *); // expected-note 1+ {{candidate function}} >>> + >>> +// Declare the reserved placement operators. >>> +void *operator new(size_t, void*) throw(); // expected-note 1+ >>> {{candidate function}} >>> +void operator delete(void *, void *)throw(); // expected-note 1+ >>> {{candidate function}} >>> +void *operator new[](size_t, void*) throw(); >>> +void operator delete[](void*, void*) throw(); >>> + >>> +// Declare the replaceable global allocation operators. >>> +void *operator new(size_t, const std::nothrow_t &) throw(); // >>> expected-note 1+ {{candidate function}} >>> +void *operator new[](size_t, const std::nothrow_t &) throw(); >>> +void operator delete(void *, const std::nothrow_t &)throw(); // >>> expected-note 1+ {{candidate function}} >>> +void operator delete[](void *, const std::nothrow_t &) throw(); >>> + >>> +// aligned allocation and deallocation functions. >>> +void* operator new ( size_t count, std::align_val_t al); // >>> expected-note 1+ {{candidate function}} >>> +void operator delete(void *, std::align_val_t); // expected-note 1+ >>> {{candidate}} >>> +#ifndef __cpp_aligned_new >>> +// expected-note@-3 1+ {{non-usual 'operator new' declared here}} >>> +// expected-note@-3 1+ {{non-usual 'operator delete' declared here}} >>> +#endif >>> +void *operator new[](size_t count, std::align_val_t al); >>> +void operator delete[](void*, std::align_val_t); >>> + >>> +void operator delete(void *, size_t); // expected-note 1+ {{candidate}} >>> +#ifndef __cpp_sized_deallocation >>> +// expected-note@-2 1+ {{non-usual 'operator delete' declared here}} >>> +#endif >>> +void operator delete[](void*, size_t); >>> + >>> +// Declare some other placemenet operators. >>> +void *operator new(size_t, void*, bool) throw(); // expected-note 1+ >>> {{candidate function}} >>> +void *operator new[](size_t, void*, bool) throw(); >>> + >>> +void *NP = 0; >>> + >>> +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 >>> {{no matching function for call to 'operator new'}} >>> + __builtin_operator_new(NP, std::align_val_t(0)); // expected-error >>> {{no matching function for call to 'operator new'}}} >>> +} >>> +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 y = __builtin_operator_delete(NP); // expected-error >>> {{cannot initialize a variable of type 'int' with an rvalue of type 'void'}} >>> +} >>> + >>> +void test_aligned_new() { >>> +#ifdef __cpp_aligned_new >>> + void *p = __builtin_operator_new(42, std::align_val_t(2)); >>> + __builtin_operator_delete(p, std::align_val_t(2)); >>> +#else >>> + // FIXME: We've manually declared the aligned new/delete overloads, >>> + // but LangOpts::AlignedAllocation is false. Should our overloads be >>> considered >>> + // usual allocation/deallocation functions? >>> + void *p = __builtin_operator_new(42, std::align_val_t(2)); // >>> expected-error {{call to '__builtin_operator_new' selects non-usual >>> allocation function}} >>> + __builtin_operator_delete(p, std::align_val_t(2)); // >>> expected-error {{call to '__builtin_operator_delete' selects non-usual >>> deallocation function}} >>> +#endif >>> +} >>> + >>> +void test_sized_delete() { >>> +#ifdef __cpp_sized_deallocation >>> + __builtin_operator_delete(NP, 4); >>> +#else >>> + __builtin_operator_delete(NP, 4); // expected-error {{call to >>> '__builtin_operator_delete' selects non-usual deallocation function}} >>> +#endif >>> +} >>> + >>> +void *operator new(size_t, bool); // expected-note 1+ {{candidate}} >>> +// expected-note@-1 {{non-usual 'operator new' declared here}} >>> +void operator delete(void *, bool); // expected-note 1+ {{candidate}} >>> +// expected-note@-1 {{non-usual 'operator delete' declared here}} >>> + >>> +void test_non_usual() { >>> + __builtin_operator_new(42, true); // expected-error {{call to >>> '__builtin_operator_new' selects non-usual allocation function}} >>> + __builtin_operator_delete(NP, false); // expected-error {{call to >>> '__builtin_operator_delete' selects non-usual deallocation function}} >>> +} >>> + >>> +template <int ID> >>> +struct Tag {}; >>> +struct ConvertsToTypes { >>> + operator std::align_val_t() const; >>> + operator Tag<0>() const; >>> +}; >>> + >>> +void *operator new(size_t, Tag<0>); // expected-note 0+ {{candidate}} >>> +void operator delete(void *, Tag<0>); // expected-note 0+ {{candidate}} >>> + >>> +void test_ambiguous() { >>> +#ifdef __cpp_aligned_new >>> + ConvertsToTypes cvt; >>> + __builtin_operator_new(42, cvt); // expected-error {{call to >>> 'operator new' is ambiguous}} >>> + __builtin_operator_delete(NP, cvt); // expected-error {{call to >>> 'operator delete' is ambiguous}} >>> +#endif >>> +} >>> + >>> +void test_no_args() { >>> + __builtin_operator_new(); // expected-error {{no matching function >>> for call to 'operator new'}} >>> + __builtin_operator_delete(); // expected-error {{no matching function >>> for call to 'operator delete'}} >>> +} >>> + >>> +void test_no_matching_fn() { >>> + Tag<1> tag; >>> + __builtin_operator_new(42, tag); // expected-error {{no matching >>> function for call to 'operator new'}} >>> + __builtin_operator_delete(NP, tag); // expected-error {{no matching >>> function for call to 'operator delete'}} >>> +} >>> + >>> +template <class Tp, class Up, class RetT> >>> +void test_dependent_call(Tp new_arg, Up delete_arg, RetT) { >>> + RetT ret = __builtin_operator_new(new_arg); >>> + __builtin_operator_delete(delete_arg); >>> +} >>> +template void test_dependent_call(int, int*, void*); >>> + >>> +void test_const_attribute() { >>> + __builtin_operator_new(42); // expected-warning {{ignoring return >>> value of function declared with const attribute}} >>> +#ifdef __cpp_aligned_new >>> + __builtin_operator_new(42, std::align_val_t(8)); // expected-warning >>> {{ignoring return value of function declared with const attribute}} >>> +#endif >>> +} >>> >>> >>> _______________________________________________ >>> cfe-commits mailing list >>> cfe-commits@lists.llvm.org >>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >>> >> >> >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits