]> granicus.if.org Git - clang/commitdiff
[clang]: Add support for "-fno-delete-null-pointer-checks"
authorManoj Gupta <manojgupta@google.com>
Thu, 19 Jul 2018 00:44:52 +0000 (00:44 +0000)
committerManoj Gupta <manojgupta@google.com>
Thu, 19 Jul 2018 00:44:52 +0000 (00:44 +0000)
Summary:
Support for this option is needed for building Linux kernel.
This is a very frequently requested feature by kernel developers.

More details : https://lkml.org/lkml/2018/4/4/601

GCC option description for -fdelete-null-pointer-checks:
This Assume that programs cannot safely dereference null pointers,
and that no code or data element resides at address zero.

-fno-delete-null-pointer-checks is the inverse of this implying that
null pointer dereferencing is not undefined.

This feature is implemented in as the function attribute
"null-pointer-is-valid"="true".
This CL only adds the attribute on the function.
It also strips "nonnull" attributes from function arguments but
keeps the related warnings unchanged.

Corresponding LLVM change rL336613 already updated the
optimizations to not treat null pointer dereferencing
as undefined if the attribute is present.

Reviewers: t.p.northover, efriedma, jyknight, chandlerc, rnk, srhines, void, george.burgess.iv

Reviewed By: jyknight

Subscribers: drinkcat, xbolva00, cfe-commits

Differential Revision: https://reviews.llvm.org/D47894

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@337433 91177308-0d34-0410-b5e6-96231b3b80d8

14 files changed:
docs/ClangCommandLineReference.rst
include/clang/Driver/Options.td
include/clang/Frontend/CodeGenOptions.def
lib/CodeGen/CGCall.cpp
lib/Driver/ToolChains/Clang.cpp
lib/Frontend/CompilerInvocation.cpp
test/CodeGen/delete-null-pointer-checks.c [new file with mode: 0644]
test/CodeGen/nonnull.c
test/CodeGen/vla.c
test/CodeGenCXX/address-space-ref.cpp
test/CodeGenCXX/constructors.cpp
test/CodeGenCXX/temporaries.cpp
test/Driver/clang_f_opts.c
test/Sema/nonnull.c

index 513128119e25fde3e979c357b49d31c02c526416..87c7896ba70c8b1c0d245833fbfd6a75ea4df68b 100644 (file)
@@ -1543,6 +1543,14 @@ Specifies the largest alignment guaranteed by '::operator new(size\_t)'
 
 Disable implicit builtin knowledge of a specific function
 
+.. option:: -fdelete-null-pointer-checks, -fno-delete-null-pointer-checks
+
+When enabled, treat null pointer dereference, creation of a reference to null,
+or passing a null pointer to a function parameter annotated with the "nonnull"
+attribute as undefined behavior. (And, thus the optimizer may assume that any
+pointer used in such a way must not have been null and optimize away the
+branches accordingly.) On by default.
+
 .. option:: -fno-elide-type
 
 Do not elide types when printing diagnostics
index b71d1e15ae89ed6c1a3394579f638084831df050..605160844894d20b4ac7239fc030ca99dc2f2cd2 100644 (file)
@@ -1080,6 +1080,13 @@ def frewrite_imports : Flag<["-"], "frewrite-imports">, Group<f_Group>,
   Flags<[CC1Option]>;
 def fno_rewrite_imports : Flag<["-"], "fno-rewrite-imports">, Group<f_Group>;
 
+def fdelete_null_pointer_checks : Flag<["-"],
+  "fdelete-null-pointer-checks">, Group<f_Group>,
+  HelpText<"Treat usage of null pointers as undefined behavior.">;
+def fno_delete_null_pointer_checks : Flag<["-"],
+  "fno-delete-null-pointer-checks">, Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Do not treat usage of null pointers as undefined behavior.">;
+
 def frewrite_map_file : Separate<["-"], "frewrite-map-file">,
                         Group<f_Group>,
                         Flags<[ DriverOption, CC1Option ]>;
@@ -2855,8 +2862,6 @@ defm reorder_blocks : BooleanFFlag<"reorder-blocks">, Group<clang_ignored_gcc_op
 defm eliminate_unused_debug_types : BooleanFFlag<"eliminate-unused-debug-types">, Group<clang_ignored_f_Group>;
 defm branch_count_reg : BooleanFFlag<"branch-count-reg">, Group<clang_ignored_gcc_optimization_f_Group>;
 defm default_inline : BooleanFFlag<"default-inline">, Group<clang_ignored_gcc_optimization_f_Group>;
-defm delete_null_pointer_checks : BooleanFFlag<"delete-null-pointer-checks">,
-    Group<clang_ignored_gcc_optimization_f_Group>;
 defm fat_lto_objects : BooleanFFlag<"fat-lto-objects">, Group<clang_ignored_gcc_optimization_f_Group>;
 defm float_store : BooleanFFlag<"float-store">, Group<clang_ignored_gcc_optimization_f_Group>;
 defm friend_injection : BooleanFFlag<"friend-injection">, Group<clang_ignored_f_Group>;
index c199b5428ea304ed19019e35a135c79b946a0a23..2ed96d43279c2f62fe8c555d18db5a76687c661c 100644 (file)
@@ -130,6 +130,7 @@ CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled.
 CODEGENOPT(NoImplicitFloat   , 1, 0) ///< Set when -mno-implicit-float is enabled.
 CODEGENOPT(NoInfsFPMath      , 1, 0) ///< Assume FP arguments, results not +-Inf.
 CODEGENOPT(NoSignedZeros     , 1, 0) ///< Allow ignoring the signedness of FP zero
+CODEGENOPT(NullPointerIsValid , 1, 0) ///< Assume Null pointer deference is defined.
 CODEGENOPT(Reassociate       , 1, 0) ///< Allow reassociation of FP math ops
 CODEGENOPT(ReciprocalMath    , 1, 0) ///< Allow FP divisions to be reassociated.
 CODEGENOPT(NoTrappingMath    , 1, 0) ///< Set when -fno-trapping-math is enabled.
index 07fb6d56dd737f666aa7759f3130ace040a8dde0..fcc8a3e5f644898074bfb5f51076843af3b69148 100644 (file)
@@ -1734,6 +1734,8 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
     FuncAttrs.addAttribute("less-precise-fpmad",
                            llvm::toStringRef(CodeGenOpts.LessPreciseFPMAD));
 
+    if (CodeGenOpts.NullPointerIsValid)
+      FuncAttrs.addAttribute("null-pointer-is-valid", "true");
     if (!CodeGenOpts.FPDenormalMode.empty())
       FuncAttrs.addAttribute("denormal-fp-math", CodeGenOpts.FPDenormalMode);
 
@@ -1867,7 +1869,8 @@ void CodeGenModule::ConstructAttributeList(
     }
     if (TargetDecl->hasAttr<RestrictAttr>())
       RetAttrs.addAttribute(llvm::Attribute::NoAlias);
-    if (TargetDecl->hasAttr<ReturnsNonNullAttr>())
+    if (TargetDecl->hasAttr<ReturnsNonNullAttr>() &&
+        !CodeGenOpts.NullPointerIsValid)
       RetAttrs.addAttribute(llvm::Attribute::NonNull);
     if (TargetDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>())
       FuncAttrs.addAttribute("no_caller_saved_registers");
@@ -1974,7 +1977,8 @@ void CodeGenModule::ConstructAttributeList(
     if (!PTy->isIncompleteType() && PTy->isConstantSizeType())
       RetAttrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy)
                                         .getQuantity());
-    else if (getContext().getTargetAddressSpace(PTy) == 0)
+    else if (getContext().getTargetAddressSpace(PTy) == 0 &&
+             !CodeGenOpts.NullPointerIsValid)
       RetAttrs.addAttribute(llvm::Attribute::NonNull);
   }
 
@@ -2083,7 +2087,8 @@ void CodeGenModule::ConstructAttributeList(
       if (!PTy->isIncompleteType() && PTy->isConstantSizeType())
         Attrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy)
                                        .getQuantity());
-      else if (getContext().getTargetAddressSpace(PTy) == 0)
+      else if (getContext().getTargetAddressSpace(PTy) == 0 &&
+               !CodeGenOpts.NullPointerIsValid)
         Attrs.addAttribute(llvm::Attribute::NonNull);
     }
 
@@ -2343,7 +2348,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
 
         if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Arg)) {
           if (getNonNullAttr(CurCodeDecl, PVD, PVD->getType(),
-                             PVD->getFunctionScopeIndex()))
+                             PVD->getFunctionScopeIndex()) &&
+              !CGM.getCodeGenOpts().NullPointerIsValid)
             AI->addAttr(llvm::Attribute::NonNull);
 
           QualType OTy = PVD->getOriginalType();
@@ -2362,7 +2368,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
                 Attrs.addDereferenceableAttr(
                   getContext().getTypeSizeInChars(ETy).getQuantity()*ArrSize);
                 AI->addAttrs(Attrs);
-              } else if (getContext().getTargetAddressSpace(ETy) == 0) {
+              } else if (getContext().getTargetAddressSpace(ETy) == 0 &&
+                         !CGM.getCodeGenOpts().NullPointerIsValid) {
                 AI->addAttr(llvm::Attribute::NonNull);
               }
             }
@@ -2372,7 +2379,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
             // we can't use the dereferenceable attribute, but in addrspace(0)
             // we know that it must be nonnull.
             if (ArrTy->getSizeModifier() == VariableArrayType::Static &&
-                !getContext().getTargetAddressSpace(ArrTy->getElementType()))
+                !getContext().getTargetAddressSpace(ArrTy->getElementType()) &&
+                !CGM.getCodeGenOpts().NullPointerIsValid)
               AI->addAttr(llvm::Attribute::NonNull);
           }
 
index 4db4dc19a8b41749e782ed5f6a58a30368a0cc74..e23ff16699f4c393293f2e513af42f163591b46e 100644 (file)
@@ -3348,6 +3348,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                    options::OPT_fno_merge_all_constants, false))
     CmdArgs.push_back("-fmerge-all-constants");
 
+  if (Args.hasFlag(options::OPT_fno_delete_null_pointer_checks,
+                   options::OPT_fdelete_null_pointer_checks, false))
+    CmdArgs.push_back("-fno-delete-null-pointer-checks");
+
   // LLVM Code Generator Options.
 
   if (Args.hasArg(options::OPT_frewrite_map_file) ||
index c26d5fb79b3985445b20ff84e0ed7a1e578cf4a6..9bb673d1e776a9bac98906cb7721e852762c13b5 100644 (file)
@@ -746,6 +746,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
 
   Opts.NoUseJumpTables = Args.hasArg(OPT_fno_jump_tables);
 
+  Opts.NullPointerIsValid = Args.hasArg(OPT_fno_delete_null_pointer_checks);
+
   Opts.ProfileSampleAccurate = Args.hasArg(OPT_fprofile_sample_accurate);
 
   Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ);
diff --git a/test/CodeGen/delete-null-pointer-checks.c b/test/CodeGen/delete-null-pointer-checks.c
new file mode 100644 (file)
index 0000000..a3c1460
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown-linux-gnu -O2 -o - %s | FileCheck -check-prefix=NULL-POINTER-INVALID  %s
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-unknown-linux-gnu -O2 -o - %s -fno-delete-null-pointer-checks | FileCheck -check-prefix=NULL-POINTER-VALID  %s
+
+// Test that clang does not remove the null pointer check with
+// -fno-delete-null-pointer-checks.
+int null_check(int *P) {
+// NULL-POINTER-VALID: %[[TOBOOL:.*]] = icmp eq i32* %P, null
+// NULL-POINTER-INVALID-NOT: icmp eq
+// NULL-POINTER-VALID: %[[SEL:.*]] = select i1 %[[TOBOOL:.*]], i32* null, i32*
+// NULL-POINTER-INVALID-NOT: select i1
+// NULL-POINTER-VALID: load i32, i32* %[[SEL:.*]]
+  int *Q = P;
+  if (P) {
+    Q = P + 2;
+  }
+  return *Q;
+}
+
+// NULL-POINTER-INVALID-NOT: attributes #0 = {{.*}} "null-pointer-is-valid"="true"
+// NULL-POINTER-VALID: attributes #0 = {{.*}} "null-pointer-is-valid"="true"
index 7c33e6329fddff8e07fd98ef03a99b7d9dca70dc..30162441cf4c45d34418f9240b9953e34f3c757f 100644 (file)
@@ -1,32 +1,39 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm < %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm < %s | FileCheck -check-prefix=NULL-INVALID %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -fno-delete-null-pointer-checks < %s | FileCheck -check-prefix=NULL-VALID %s
 
-// CHECK: define void @foo(i32* nonnull %x)
+// NULL-INVALID: define void @foo(i32* nonnull %x)
+// NULL-VALID: define void @foo(i32* %x)
 void foo(int * __attribute__((nonnull)) x) {
   *x = 0;
 }
 
-// CHECK: define void @bar(i32* nonnull %x)
+// NULL-INVALID: define void @bar(i32* nonnull %x)
+// NULL-VALID: define void @bar(i32* %x)
 void bar(int * x) __attribute__((nonnull(1)))  {
   *x = 0;
 }
 
-// CHECK: define void @bar2(i32* %x, i32* nonnull %y)
+// NULL-INVALID: define void @bar2(i32* %x, i32* nonnull %y)
+// NULL-VALID: define void @bar2(i32* %x, i32* %y)
 void bar2(int * x, int * y) __attribute__((nonnull(2)))  {
   *x = 0;
 }
 
 static int a;
-// CHECK: define nonnull i32* @bar3()
+// NULL-INVALID: define nonnull i32* @bar3()
+// NULL-VALID: define i32* @bar3()
 int * bar3() __attribute__((returns_nonnull))  {
   return &a;
 }
 
-// CHECK: define i32 @bar4(i32 %n, i32* nonnull %p)
+// NULL-INVALID: define i32 @bar4(i32 %n, i32* nonnull %p)
+// NULL-VALID: define i32 @bar4(i32 %n, i32* %p)
 int bar4(int n, int *p) __attribute__((nonnull)) {
   return n + *p;
 }
 
-// CHECK: define i32 @bar5(i32 %n, i32* nonnull %p)
+// NULL-INVALID: define i32 @bar5(i32 %n, i32* nonnull %p)
+// NULL-VALID: define i32 @bar5(i32 %n, i32* %p)
 int bar5(int n, int *p) __attribute__((nonnull(1, 2))) {
   return n + *p;
 }
@@ -37,15 +44,18 @@ typedef union {
   double d;
 } TransparentUnion __attribute__((transparent_union));
 
-// CHECK: define i32 @bar6(i64 %
+// NULL-INVALID: define i32 @bar6(i64 %
+// NULL-VALID: define i32 @bar6(i64 %
 int bar6(TransparentUnion tu) __attribute__((nonnull(1))) {
   return *tu.p;
 }
 
-// CHECK: define void @bar7(i32* nonnull %a, i32* nonnull %b)
+// NULL-INVALID: define void @bar7(i32* nonnull %a, i32* nonnull %b)
+// NULL-VALID: define void @bar7(i32* %a, i32* %b)
 void bar7(int *a, int *b) __attribute__((nonnull(1)))
 __attribute__((nonnull(2))) {}
 
-// CHECK: define void @bar8(i32* nonnull %a, i32* nonnull %b)
+// NULL-INVALID: define void @bar8(i32* nonnull %a, i32* nonnull %b)
+// NULL-VALID: define void @bar8(i32* %a, i32* %b)
 void bar8(int *a, int *b) __attribute__((nonnull))
 __attribute__((nonnull(1))) {}
index 0f2e2cdc669dc604b936c2b1d3b96edff14225ec..37243cd1729057d9670d094753ed6f7a43bc7fa3 100644 (file)
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,NULL-INVALID
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -fno-delete-null-pointer-checks -o - | FileCheck %s -check-prefixes=CHECK,NULL-VALID
 
 int b(char* x);
 
@@ -202,5 +203,6 @@ void test8(int a[static 3]) { }
 // CHECK: define void @test8(i32* dereferenceable(12) %a)
 
 void test9(int n, int a[static n]) { }
-// CHECK: define void @test9(i32 %n, i32* nonnull %a)
+// NULL-INVALID: define void @test9(i32 %n, i32* nonnull %a)
+// NULL-VALID: define void @test9(i32 %n, i32* %a)
 
index de6bddca66a7281cfe6ac29cb27ddb7f45caff8e..5f0a42950328d1df9a7e545474b88aa05d35788b 100644 (file)
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,NULL-INVALID
+// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -fno-delete-null-pointer-checks -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,NULL-VALID
 
 // For a reference to a complete type, output the dereferenceable attribute (in
 // any address space).
@@ -29,6 +30,7 @@ bc & bar2(bc &x, bc & y) {
   return x;
 }
 
-// CHECK: define nonnull %class.bc* @_Z4bar2R2bcS0_(%class.bc* nonnull %x, %class.bc* nonnull %y)
+// NULL-INVALID: define nonnull %class.bc* @_Z4bar2R2bcS0_(%class.bc* nonnull %x, %class.bc* nonnull %y)
+// NULL-VALID: define %class.bc* @_Z4bar2R2bcS0_(%class.bc* %x, %class.bc* %y)
 
 
index a89814038340736153f246ae402816a8a84b6d02..9322c410f272bbe74c68719506812ba967c8f23b 100644 (file)
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s --implicit-check-not=should_not_appear_in_output
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s --implicit-check-not=should_not_appear_in_output --check-prefixes=CHECK,NULL-INVALID
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -fno-delete-null-pointer-checks -o - | FileCheck %s --implicit-check-not=should_not_appear_in_output --check-prefixes=CHECK,NULL-VALID
 
 struct Member { int x; Member(); Member(int); Member(const Member &); };
 struct VBase { int x; VBase(); VBase(int); VBase(const VBase &); };
@@ -21,10 +22,12 @@ struct A {
 A::A(struct Undeclared &ref) : mem(0) {}
 
 // Check that delegation works.
-// CHECK-LABEL: define void @_ZN1AC2ER10Undeclared(%struct.A* %this, %struct.Undeclared* nonnull %ref) unnamed_addr
+// NULL-INVALID-LABEL: define void @_ZN1AC2ER10Undeclared(%struct.A* %this, %struct.Undeclared* nonnull %ref) unnamed_addr
+// NULL-VALID-LABEL: define void @_ZN1AC2ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr
 // CHECK: call void @_ZN6MemberC1Ei(
 
-// CHECK-LABEL: define void @_ZN1AC1ER10Undeclared(%struct.A* %this, %struct.Undeclared* nonnull %ref) unnamed_addr
+// NULL-INVALID-LABEL: define void @_ZN1AC1ER10Undeclared(%struct.A* %this, %struct.Undeclared* nonnull %ref) unnamed_addr
+// NULL-VALID-LABEL: define void @_ZN1AC1ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr
 // CHECK: call void @_ZN1AC2ER10Undeclared(
 
 A::A(ValueClass v) : mem(v.y - v.x) {}
@@ -43,11 +46,13 @@ struct B : A {
 
 B::B(struct Undeclared &ref) : A(ref), mem(1) {}
 
-// CHECK-LABEL: define void @_ZN1BC2ER10Undeclared(%struct.B* %this, %struct.Undeclared* nonnull %ref) unnamed_addr
+// NULL-INVALID-LABEL: define void @_ZN1BC2ER10Undeclared(%struct.B* %this, %struct.Undeclared* nonnull %ref) unnamed_addr
+// NULL-VALID-LABEL: define void @_ZN1BC2ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr
 // CHECK: call void @_ZN1AC2ER10Undeclared(
 // CHECK: call void @_ZN6MemberC1Ei(
 
-// CHECK-LABEL: define void @_ZN1BC1ER10Undeclared(%struct.B* %this, %struct.Undeclared* nonnull %ref) unnamed_addr
+// NULL-INVALID-LABEL: define void @_ZN1BC1ER10Undeclared(%struct.B* %this, %struct.Undeclared* nonnull %ref) unnamed_addr
+// NULL-VALID-LABEL: define void @_ZN1BC1ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr
 // CHECK: call void @_ZN1BC2ER10Undeclared(
 
 
index 21372effbcf142c3ef52b402a9ecd5d40f061bb4..2eb27e71cb1329aa59edfd3741169dbc72b43cd4 100644 (file)
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++11 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++11 | FileCheck %s -check-prefixes=CHECK,NULL-INVALID
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++11 -fno-delete-null-pointer-checks | FileCheck %s -check-prefixes=CHECK,NULL-VALID
 
 namespace PR16263 {
   const unsigned int n = 1234;
@@ -333,7 +334,8 @@ namespace PR6648 {
   struct D;
   D& zed(B);
   void foobar() {
-    // CHECK: call nonnull %"struct.PR6648::D"* @_ZN6PR66483zedENS_1BE
+    // NULL-INVALID: call nonnull %"struct.PR6648::D"* @_ZN6PR66483zedENS_1BE
+    // NULL-VALID: call %"struct.PR6648::D"* @_ZN6PR66483zedENS_1BE
     zed(foo);
   }
 }
index be9ca2c93d61e729df08185ccb37d4a3ecc5de0e..9208d6b71bb521df6eff397ad0334dc414e4715d 100644 (file)
 // RUN: -fwhole-program                                                       \
 // RUN: -fcaller-saves                                                        \
 // RUN: -freorder-blocks                                                      \
-// RUN: -fdelete-null-pointer-checks                                          \
 // RUN: -ffat-lto-objects                                                     \
 // RUN: -fmerge-constants                                                     \
 // RUN: -finline-small-functions                                              \
 // CHECK-WARNING-DAG: optimization flag '-fwhole-program' is not supported
 // CHECK-WARNING-DAG: optimization flag '-fcaller-saves' is not supported
 // CHECK-WARNING-DAG: optimization flag '-freorder-blocks' is not supported
-// CHECK-WARNING-DAG: optimization flag '-fdelete-null-pointer-checks' is not supported
 // CHECK-WARNING-DAG: optimization flag '-ffat-lto-objects' is not supported
 // CHECK-WARNING-DAG: optimization flag '-fmerge-constants' is not supported
 // CHECK-WARNING-DAG: optimization flag '-finline-small-functions' is not supported
 // RUN: %clang -### -S -fno-merge-all-constants -fmerge-all-constants %s 2>&1 | FileCheck -check-prefix=CHECK-MERGE-ALL-CONSTANTS %s
 // CHECK-NO-MERGE-ALL-CONSTANTS-NOT: "-fmerge-all-constants"
 // CHECK-MERGE-ALL-CONSTANTS: "-fmerge-all-constants"
+
+// RUN: %clang -### -S -fdelete-null-pointer-checks %s 2>&1 | FileCheck -check-prefix=CHECK-NULL-POINTER-CHECKS %s
+// RUN: %clang -### -S -fno-delete-null-pointer-checks %s 2>&1 | FileCheck -check-prefix=CHECK-NO-NULL-POINTER-CHECKS %s
+// RUN: %clang -### -S -fdelete-null-pointer-checks -fno-delete-null-pointer-checks %s 2>&1 | FileCheck -check-prefix=CHECK-NO-NULL-POINTER-CHECKS %s
+// RUN: %clang -### -S -fno-delete-null-pointer-checks -fdelete-null-pointer-checks %s 2>&1 | FileCheck -check-prefix=CHECK-NULL-POINTER-CHECKS %s
+// CHECK-NO-NULL-POINTER-CHECKS: "-fno-delete-null-pointer-checks"
+// CHECK-NULL-POINTER-CHECKS-NOT: "-fno-delete-null-pointer-checks"
index b589bb3d1ffdab4277ced3c9bd40f3e9f644688f..3410d36ddfbc96960b22961fee62bac13d7e66ab 100644 (file)
@@ -1,5 +1,9 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 // rdar://9584012
+//
+// Verify All warnings are still issued with the option -fno-delete-null-pointer-checks
+// if nullptr is passed to function with nonnull attribute.
+// RUN: %clang_cc1 -fsyntax-only -fno-delete-null-pointer-checks -verify %s
 
 typedef struct {
        char *str;