r328134 - [Builtins] Overload __builtin_operator_new/delete to allow forwarding to usual allocation/deallocation functions.
Eric Fiselier via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 22 13:16:04 PDT 2018
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 <eric at 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 <gkistanova at 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 at 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 at -3 1+ {{non-usual 'operator new' declared here}}
>>> +// expected-note at -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 at -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 at -1 {{non-usual 'operator new' declared here}}
>>> +void operator delete(void *, bool); // expected-note 1+ {{candidate}}
>>> +// expected-note at -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 at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180322/3e9baed4/attachment-0001.html>
More information about the cfe-commits
mailing list