diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst --- a/clang/docs/ClangCommandLineReference.rst +++ b/clang/docs/ClangCommandLineReference.rst @@ -1941,6 +1941,10 @@ Specifies the largest alignment guaranteed by '::operator new(size\_t)' +.. option:: -fnew-infallible + +Treats throwing global C++ operator new as always returning valid memory (annotates with \_\_attribute\_\_((returns\_nonnull)) and throw()). This is detectable in source. + .. option:: -fnext-runtime .. option:: -fno-builtin- diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -280,6 +280,7 @@ "hidden visibility for static local variables in inline C++ " "methods when -fvisibility-inlines hidden is enabled") LANGOPT(GlobalAllocationFunctionVisibilityHidden , 1, 0, "hidden visibility for global operator new and delete declaration") +LANGOPT(NewInfallible , 1, 0, "Treats throwing global C++ operator new as always returning valid memory (annotates with __attribute__((returns_nonnull)) and throw()). This is detectable in source.") BENIGN_LANGOPT(ParseUnknownAnytype, 1, 0, "__unknown_anytype") BENIGN_LANGOPT(DebuggerSupport , 1, 0, "debugger support") BENIGN_LANGOPT(DebuggerCastResultToId, 1, 0, "for 'po' in the debugger, cast the result to id if it is of unknown type") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2730,6 +2730,10 @@ def fvisibility_global_new_delete_hidden : Flag<["-"], "fvisibility-global-new-delete-hidden">, Group, HelpText<"Give global C++ operator new and delete declarations hidden visibility">, Flags<[CC1Option]>, MarshallingInfoFlag>; +def fnew_infallible : Flag<["-"], "fnew-infallible">, Group, + HelpText<"Treats throwing global C++ operator new as always returning valid memory " + "(annotates with __attribute__((returns_nonnull)) and throw()). This is detectable in source.">, + Flags<[CC1Option]>, MarshallingInfoFlag>; defm whole_program_vtables : BoolFOption<"whole-program-vtables", CodeGenOpts<"WholeProgramVTables">, DefaultFalse, PosFlag, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5711,7 +5711,7 @@ Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden_static_local_var, options::OPT_fno_visibility_inlines_hidden_static_local_var); Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden); - + Args.AddLastArg(CmdArgs, options::OPT_fnew_infallible); Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); if (Args.hasFlag(options::OPT_fno_operator_names, diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -3049,6 +3049,9 @@ EPI.ExceptionSpec.Type = EST_Dynamic; EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType); } + if (getLangOpts().NewInfallible) { + EPI.ExceptionSpec.Type = EST_DynamicNone; + } } else { EPI.ExceptionSpec = getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone; @@ -3064,6 +3067,10 @@ // Global allocation functions should always be visible. Alloc->setVisibleDespiteOwningModule(); + if (HasBadAllocExceptionSpec && getLangOpts().NewInfallible) + Alloc->addAttr( + ReturnsNonNullAttr::CreateImplicit(Context, Alloc->getLocation())); + Alloc->addAttr(VisibilityAttr::CreateImplicit( Context, LangOpts.GlobalAllocationFunctionVisibilityHidden ? VisibilityAttr::Hidden diff --git a/clang/test/CodeGenCXX/new-infallible.cpp b/clang/test/CodeGenCXX/new-infallible.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/new-infallible.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu -fnew-infallible -o - %s | FileCheck %s + +// CHECK: call noalias nonnull i8* @_Znwm(i64 4) + +// CHECK: ; Function Attrs: nobuiltin nounwind allocsize(0) +// CHECK-NEXT: declare nonnull i8* @_Znwm(i64) +int *new_infallible = new int;