Hello Eric, One of added tests fails on the next builder: http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-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/ > CGBuiltin.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< > FunctionProtoType>(), > - E->getArg(0), false); > + return EmitBuiltinNewDeleteCall( > + E->getCallee()->getType()->castAs<FunctionProtoType>(), E, > false); > case Builtin::BI__builtin_operator_delete: > - return EmitBuiltinNewDeleteCall(FD->getType()->castAs< > FunctionProtoType>(), > - 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/ > CGExprCXX.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/ > CodeGenFunction.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/ > PPMacroExpansion.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/ > SemaChecking.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/ > SemaExprCXX.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. > getCXXOperatorName( > + 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=*/false); > + 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/ > CodeGenCXX/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/builtin-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