Author: Pedro Falcato Date: 2023-06-23T22:45:17-07:00 New Revision: 52c8f0bb20eb9e7b1b54ffdddf6da77b53caeb3a
URL: https://github.com/llvm/llvm-project/commit/52c8f0bb20eb9e7b1b54ffdddf6da77b53caeb3a DIFF: https://github.com/llvm/llvm-project/commit/52c8f0bb20eb9e7b1b54ffdddf6da77b53caeb3a.diff LOG: [clang] Add -fcheck-new support Add -fcheck-new and -fno-check-new, from GCC, which make the compiler not assume pointers returned from operator new are non-null. Fixes #16931. Reviewed By: MaskRay Differential Revision: https://reviews.llvm.org/D125272 Added: clang/test/CodeGenCXX/fcheck-new.cpp Modified: clang/include/clang/Basic/LangOptions.def clang/include/clang/Basic/LangOptions.h clang/include/clang/Driver/Options.td clang/lib/AST/ExprCXX.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaExprCXX.cpp clang/test/Driver/clang_f_opts.c Removed: ################################################################################ diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index d4ee06b66d9a5..1cb9b27c7e9eb 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -466,6 +466,8 @@ LANGOPT(IncrementalExtensions, 1, 0, " True if we want to process statements" "avoid tearing the Lexer and etc. down). Controlled by " "-fincremental-extensions.") +BENIGN_LANGOPT(CheckNew, 1, 0, "Do not assume C++ operator new may not return NULL") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 1c98e28231b57..3ef68ca8af668 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -487,6 +487,10 @@ class LangOptions : public LangOptionsBase { /// forward slash (/) elsewhere. bool UseTargetPathSeparator = false; + // Indicates whether we should keep all nullptr checks for pointers + // received as a result of a standard operator new (-fcheck-new) + bool CheckNew = false; + LangOptions(); /// Set language defaults for the given input language and diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index b90d6763d6f3c..bb3d487886eb7 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5101,7 +5101,11 @@ def falign_jumps_EQ : Joined<["-"], "falign-jumps=">, Group<clang_ignored_gcc_op // ignore it for now to avoid breaking builds that use it. def fdiagnostics_show_location_EQ : Joined<["-"], "fdiagnostics-show-location=">, Group<clang_ignored_f_Group>; -defm fcheck_new : BooleanFFlag<"check-new">, Group<clang_ignored_f_Group>; +defm check_new : BoolOption<"f", "check-new", + LangOpts<"CheckNew">, DefaultFalse, + PosFlag<SetTrue, [], "Do not assume C++ operator new may not return NULL">, + NegFlag<SetFalse>, BothFlags<[CC1Option]>>; + defm caller_saves : BooleanFFlag<"caller-saves">, Group<clang_ignored_gcc_optimization_f_Group>; defm reorder_blocks : BooleanFFlag<"reorder-blocks">, Group<clang_ignored_gcc_optimization_f_Group>; defm branch_count_reg : BooleanFFlag<"branch-count-reg">, Group<clang_ignored_gcc_optimization_f_Group>; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 09e64b8c82c8e..8c061b0ad9316 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -276,6 +276,8 @@ CXXNewExpr *CXXNewExpr::CreateEmpty(const ASTContext &Ctx, bool IsArray, } bool CXXNewExpr::shouldNullCheckAllocation() const { + if (getOperatorNew()->getLangOpts().CheckNew) + return true; return !getOperatorNew()->hasAttr<ReturnsNonNullAttr>() && getOperatorNew() ->getType() diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 883544b9e37ec..de22ea4455fa7 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6157,6 +6157,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Triple.hasDefaultEmulatedTLS())) CmdArgs.push_back("-femulated-tls"); + Args.addOptInFlag(CmdArgs, options::OPT_fcheck_new, + options::OPT_fno_check_new); + if (Arg *A = Args.getLastArg(options::OPT_fzero_call_used_regs_EQ)) { // FIXME: There's no reason for this to be restricted to X86. The backend // code needs to be changed to include the appropriate function calls diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 698f57f0245b0..d72d4e097879f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16146,7 +16146,11 @@ void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction( // indicates failure by returning a null pointer value. Any other allocation // function never returns a null pointer value and indicates failure only by // throwing an exception [...] - if (!IsNothrow && !FD->hasAttr<ReturnsNonNullAttr>()) + // + // However, -fcheck-new invalidates this possible assumption, so don't add + // NonNull when that is enabled. + if (!IsNothrow && !FD->hasAttr<ReturnsNonNullAttr>() && + !getLangOpts().CheckNew) FD->addAttr(ReturnsNonNullAttr::CreateImplicit(Context, FD->getLocation())); // C++2a [basic.stc.dynamic.allocation]p2: diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index f2ff924bc7dea..817fd2d2d7d3f 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -3157,7 +3157,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, // Global allocation functions should always be visible. Alloc->setVisibleDespiteOwningModule(); - if (HasBadAllocExceptionSpec && getLangOpts().NewInfallible) + if (HasBadAllocExceptionSpec && getLangOpts().NewInfallible && + !getLangOpts().CheckNew) Alloc->addAttr( ReturnsNonNullAttr::CreateImplicit(Context, Alloc->getLocation())); diff --git a/clang/test/CodeGenCXX/fcheck-new.cpp b/clang/test/CodeGenCXX/fcheck-new.cpp new file mode 100644 index 0000000000000..d5800cc73bb9a --- /dev/null +++ b/clang/test/CodeGenCXX/fcheck-new.cpp @@ -0,0 +1,30 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -fcheck-new -triple x86_64-linux-gnu -disable-O0-optnone \ +// RUN: -emit-llvm -o - %s | FileCheck %s + +struct A { A(); }; + +// CHECK-LABEL: @_Z5test0v( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call noalias noundef ptr @_Znwm(i64 noundef 1) #[[ATTR3:[0-9]+]] +// CHECK-NEXT: [[NEW_ISNULL:%.*]] = icmp eq ptr [[CALL]], null +// CHECK-NEXT: br i1 [[NEW_ISNULL]], label [[NEW_CONT:%.*]], label [[NEW_NOTNULL:%.*]] +// CHECK: new.notnull: +// CHECK-NEXT: call void @_ZN1AC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[CALL]]) +// CHECK-NEXT: br label [[NEW_CONT]] +// CHECK: new.cont: +// CHECK-NEXT: [[TMP0:%.*]] = phi ptr [ [[CALL]], [[NEW_NOTNULL]] ], [ null, [[ENTRY:%.*]] ] +// CHECK-NEXT: ret ptr [[TMP0]] +// +A *test0() { + return new A(); +} + +// CHECK-LABEL: @_Z5test1v( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call noalias noundef ptr @_Znwm(i64 noundef 4) #[[ATTR3]] +// CHECK-NEXT: ret ptr [[CALL]] +// +int *test1() { + return new int; +} diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index 8060e52d5e8fd..65ba66fa325f5 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -302,7 +302,6 @@ // RUN: -fno-reorder-blocks -freorder-blocks \ // RUN: -fno-schedule-insns2 -fschedule-insns2 \ // RUN: -fno-stack-check \ -// RUN: -fno-check-new -fcheck-new \ // RUN: -ffriend-injection \ // RUN: -fno-implement-inlines -fimplement-inlines \ // RUN: -fstack-check \ _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits