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 10:56:05 PDT 2018


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-
> 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 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_malfor
>> med);
>> +        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=*/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/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/
>> 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 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/66facac9/attachment-0001.html>


More information about the cfe-commits mailing list