[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
This commit is contained in:
parent
ee2bf319bc
commit
52c8f0bb20
@ -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
|
||||
|
||||
@ -487,6 +487,10 @@ public:
|
||||
/// 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
|
||||
|
||||
@ -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>;
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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()));
|
||||
|
||||
|
||||
30
clang/test/CodeGenCXX/fcheck-new.cpp
Normal file
30
clang/test/CodeGenCXX/fcheck-new.cpp
Normal file
@ -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;
|
||||
}
|
||||
@ -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 \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user