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, Flags<[CC1Option]>; +def fdelete_null_pointer_checks : Flag<["-"], "fdelete-null-pointer-checks">, + Group, Flags<[CC1Option]>; +def fno_delete_null_pointer_checks : Flag<["-"], "fno-delete-null-pointer-checks">, + Group, Flags<[CC1Option]>; def funique_section_names : Flag <["-"], "funique-section-names">, Group, Flags<[CC1Option]>, @@ -2004,8 +2008,6 @@ defm eliminate_unused_debug_types : BooleanFFlag<"eliminate-unused-debug-types">, Group; defm branch_count_reg : BooleanFFlag<"branch-count-reg">, Group; defm default_inline : BooleanFFlag<"default-inline">, Group; -defm delete_null_pointer_checks : BooleanFFlag<"delete-null-pointer-checks">, - Group; defm fat_lto_objects : BooleanFFlag<"fat-lto-objects">, Group; defm float_store : BooleanFFlag<"float-store">, Group; defm friend_injection : BooleanFFlag<"friend-injection">, Group; 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: 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: 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/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: 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: 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/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/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