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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits