bkramer created this revision.
bkramer added reviewers: rsmith, rjmccall.
bkramer added a subscriber: cfe-commits.
Also thread -f(no-)delete-null-pointer-checks through to CodeGen and
make it disable this behavior. It's not a full implementation of that
flag but it would be good to stay compatible with GCC. GCC 6 started
deleting null checks for 'this' pointers.

This is going to break code that relies on this undefined behavior,
which is a common pattern. We already have -Wnull-dereference for
obvious cases, ubsan catches it, and there's always the flag to
disable it, so I believe it's time to be more aggressive about this.

http://reviews.llvm.org/D17993

Files:
  include/clang/Driver/Options.td
  include/clang/Frontend/CodeGenOptions.def
  lib/CodeGen/CGCall.cpp
  lib/Driver/Tools.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGenCXX/debug-info-class.cpp
  test/CodeGenCXX/stack-reuse-miscompile.cpp
  test/CodeGenCXX/this-nonnull.cpp
  test/Driver/clang_f_opts.c

Index: test/Driver/clang_f_opts.c
===================================================================
--- test/Driver/clang_f_opts.c
+++ test/Driver/clang_f_opts.c
@@ -406,7 +406,6 @@
 // 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
Index: test/CodeGenCXX/this-nonnull.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/this-nonnull.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NO
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - -fdelete-null-pointer-checks %s | FileCheck %s -check-prefix=CHECK-YES
+
+struct Foo {
+  Foo Bar();
+  void Qux();
+
+  int a, b, c, d, e, f, g;
+};
+
+Foo Foo::Bar() { return Foo(); }
+// CHECK-NO: define void @_ZN3Foo3BarEv(%struct.Foo* noalias sret %agg.result, %struct.Foo* %this)
+// CHECK-YES: define void @_ZN3Foo3BarEv(%struct.Foo* noalias sret %agg.result, %struct.Foo* nonnull %this)
+
+void Bar(Foo &f) {
+  f.Qux();
+  // CHECK-NO: call void @_ZN3Foo3QuxEv(%struct.Foo* %
+  // CHECK-YES: call void @_ZN3Foo3QuxEv(%struct.Foo* nonnull %
+}
+
+// CHECK-NO: declare void @_ZN3Foo3QuxEv(%struct.Foo*)
+// CHECK-YES: declare void @_ZN3Foo3QuxEv(%struct.Foo* nonnull)
Index: test/CodeGenCXX/stack-reuse-miscompile.cpp
===================================================================
--- test/CodeGenCXX/stack-reuse-miscompile.cpp
+++ test/CodeGenCXX/stack-reuse-miscompile.cpp
@@ -26,10 +26,10 @@
 // CHECK: [[T1:%.*]] = alloca %class.T, align 4
 // CHECK: [[T2:%.*]] = alloca %class.T, align 4
 // CHECK: [[T3:%.*]] = alloca %class.T, align 4
-// CHECK: [[T4:%.*]] = call %class.T* @_ZN1TC1EPKc(%class.T* [[T1]], i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i32 0, i32 0))
-// CHECK: [[T5:%.*]] = call %class.T* @_ZN1TC1E1S(%class.T* [[T2]], [2 x i32] %{{.*}})
-// CHECK: call void @_ZNK1T6concatERKS_(%class.T* sret [[T3]], %class.T* [[T1]], %class.T* dereferenceable(16) [[T2]])
-// CHECK: [[T6:%.*]] = call i8* @_ZNK1T3strEv(%class.T* [[T3]])
+// CHECK: [[T4:%.*]] = call %class.T* @_ZN1TC1EPKc(%class.T* nonnull [[T1]], i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i32 0, i32 0))
+// CHECK: [[T5:%.*]] = call %class.T* @_ZN1TC1E1S(%class.T* nonnull [[T2]], [2 x i32] %{{.*}})
+// CHECK: call void @_ZNK1T6concatERKS_(%class.T* sret [[T3]], %class.T* nonnull [[T1]], %class.T* dereferenceable(16) [[T2]])
+// CHECK: [[T6:%.*]] = call i8* @_ZNK1T3strEv(%class.T* nonnull [[T3]])
 // CHECK: ret i8* [[T6]]
 
   return T("[").concat(T(s)).str();
Index: test/CodeGenCXX/debug-info-class.cpp
===================================================================
--- test/CodeGenCXX/debug-info-class.cpp
+++ test/CodeGenCXX/debug-info-class.cpp
@@ -87,7 +87,7 @@
 // RUN: %clang -target i686-cygwin -emit-llvm -g -S %s -o - | FileCheck %s
 // RUN: %clang -target armv7l-unknown-linux-gnueabihf -emit-llvm -g -S %s -o - | FileCheck %s
 
-// CHECK: invoke {{.+}} @_ZN1BD1Ev(%class.B* %b)
+// CHECK: invoke {{.+}} @_ZN1BD1Ev(%class.B* nonnull %b)
 // CHECK-NEXT: unwind label %{{.+}}, !dbg ![[EXCEPTLOC:.*]]
 // CHECK: store i32 0, i32* %{{.+}}, !dbg ![[RETLOC:.*]]
 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -484,6 +484,7 @@
   Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables);
   Opts.WholeProgramVTablesBlacklistFiles =
       Args.getAllArgValues(OPT_fwhole_program_vtables_blacklist_EQ);
+  Opts.DeleteNullPointerChecks = Args.hasArg(OPT_fdelete_null_pointer_checks);
   Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
   Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs);
   Opts.DebugExplicitImport = Triple.isPS4CPU(); 
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -4381,6 +4381,11 @@
     CmdArgs.push_back("-fdata-sections");
   }
 
+  if (Args.hasFlag(options::OPT_fdelete_null_pointer_checks,
+                   options::OPT_fno_delete_null_pointer_checks, true)) {
+    CmdArgs.push_back("-fdelete-null-pointer-checks");
+  }
+
   if (!Args.hasFlag(options::OPT_funique_section_names,
                     options::OPT_fno_unique_section_names, true))
     CmdArgs.push_back("-fno-unique-section-names");
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -1669,6 +1669,18 @@
         getLLVMContext(), IRFunctionArgs.getInallocaArgNo() + 1, Attrs));
   }
 
+  // Apply nonnull to the 'this' argument.
+  if (FI.isInstanceMethod() && CodeGenOpts.DeleteNullPointerChecks) {
+    auto IRArgs = IRFunctionArgs.getIRArgs(0);
+    assert(IRArgs.second == 1 && "Multiple 'this' arguments?");
+    assert(getContext().getTargetAddressSpace(FI.arg_begin()->type) == 0 &&
+           "'this' pointer with address space attribute?");
+    llvm::AttrBuilder Attrs;
+    Attrs.addAttribute(llvm::Attribute::NonNull);
+    PAL.push_back(
+        llvm::AttributeSet::get(getLLVMContext(), IRArgs.first + 1, Attrs));
+  }
+
   unsigned ArgNo = 0;
   for (CGFunctionInfo::const_arg_iterator I = FI.arg_begin(),
                                           E = FI.arg_end();
Index: include/clang/Frontend/CodeGenOptions.def
===================================================================
--- include/clang/Frontend/CodeGenOptions.def
+++ include/clang/Frontend/CodeGenOptions.def
@@ -184,6 +184,10 @@
 CODEGENOPT(WholeProgramVTables, 1, 0) ///< Whether to apply whole-program
                                       ///  vtable optimization.
 
+CODEGENOPT(DeleteNullPointerChecks, 1, 0) ///< Whether to delete null pointer
+                                          ///< checks based on undefined
+					  ///< behavior.
+
 /// The user specified number of registers to be used for integral arguments,
 /// or 0 if unspecified.
 VALUE_CODEGENOPT(NumRegisterParameters, 32, 0)
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -1151,6 +1151,10 @@
  Flags<[CC1Option]>, HelpText<"Place each data in its own section (ELF Only)">;
 def fno_data_sections : Flag <["-"], "fno-data-sections">, Group<f_Group>,
   Flags<[CC1Option]>;
+def fdelete_null_pointer_checks : Flag<["-"], "fdelete-null-pointer-checks">,
+  Group<f_clang_Group>, Flags<[CC1Option]>;
+def fno_delete_null_pointer_checks : Flag<["-"], "fno-delete-null-pointer-checks">,
+  Group<f_clang_Group>, Flags<[CC1Option]>;
 
 def funique_section_names : Flag <["-"], "funique-section-names">,
   Group<f_Group>, Flags<[CC1Option]>,
@@ -2004,8 +2008,6 @@
 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>;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to