From 27ce26b06655cfece3d54b30e442ef93d3e78ac7 Mon Sep 17 00:00:00 2001 From: bd1976bris Date: Mon, 22 Jan 2024 12:37:11 +0000 Subject: [PATCH] [Sema] Add `-fvisibility-global-new-delete=` option (#75364) [Sema] Add `-fvisibility-global-new-delete=` option (#75364) By default the implicitly declared replaceable global new and delete operators are given a default visibility attribute. Previous work, see: https://reviews.llvm.org/D53787, added `-fvisibility-global-new-delete-hidden` to change this to a hidden visibility attribute. This change adds `-fvisibility-global-new-delete=` which controls whether (or not) to add an implicit visibility attribute to the implicit declarations for these functions, and what visibility that attribute will specify. The option takes 4 values: `force-hidden`, `force-protected`, `force-default` and `source`. Option values `force-hidden`, `force-protected` and `force-default` assign hidden, protected, and default visibilities respectively; the use of the term force in the value names is designed to imply to a user that the semantics of this option differ significantly from `-fvisibility=`. An option value of `source` implies that no implicit attribute is added; without the attribute the replaceable global new and delete operators behave normally (like other functions) with respect to visibility attributes, pragmas and options. The motivation for the `source` value is to facilitate users who intend to replace these functions either for a single linkage unit or a limited set of linkage units. `-fvisibility-global-new-delete=source` can be applied globally to the compilations in a build where the existing `-fvisibility-global-new-delete-hidden` cannot, as it conflicts with a common pattern where these functions are dynamically imported. The existing `-fvisibility-global-new-delete-hidden` is now a deprecated spelling of `-fvisibility-global-new-delete=force-hidden` A release note has been added for these changes. `-fvisibility-global-new-delete=source` will be set by default for PS5. PS5 users that want the normal toolchain behaviour will be able to supply `-fvisibility-global-new-delete=force-default`. --- clang/docs/ReleaseNotes.rst | 15 +++++- clang/include/clang/Basic/LangOptions.def | 3 +- clang/include/clang/Basic/LangOptions.h | 31 +++++++++++ clang/include/clang/Driver/Options.td | 11 +++- clang/lib/Driver/ToolChains/Clang.cpp | 23 +++++++- clang/lib/Driver/ToolChains/PS4CPU.cpp | 6 +++ clang/lib/Sema/SemaExprCXX.cpp | 11 ++-- .../visibility-global-new-delete.cpp | 14 +++++ .../Driver/visibility-global-new-delete.cl | 52 +++++++++++++++++++ 9 files changed, 157 insertions(+), 9 deletions(-) create mode 100644 clang/test/CodeGenCXX/visibility-global-new-delete.cpp create mode 100644 clang/test/Driver/visibility-global-new-delete.cl diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 45fc8bbbb6862..5846503af3acd 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -320,7 +320,7 @@ New Compiler Flags handlers will be smaller. A throw expression of a type with a potentially-throwing destructor will lead to an error. -* ``-fopenacc`` was added as a part of the effort to support OpenACC in clang. +* ``-fopenacc`` was added as a part of the effort to support OpenACC in Clang. * ``-fcx-limited-range`` enables the naive mathematical formulas for complex division and multiplication with no NaN checking of results. The default is @@ -331,6 +331,16 @@ New Compiler Flags division. See SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8 (1962). The default is ``-fno-cx-fortran-rules``. +* ``-fvisibility-global-new-delete=`` gives more freedom to users to + control how and if Clang forces a visibility for the replaceable new and + delete declarations. The option takes 4 values: ``force-hidden``, + ``force-protected``, ``force-default`` and ``source``; ``force-default`` is + the default. Option values with prefix ``force-`` assign such declarations + an implicit visibility attribute with the corresponding visibility. An option + value of ``source`` implies that no implicit attribute is added. Without the + attribute the replaceable global new and delete operators behave normally + (like other functions) with respect to visibility attributes, pragmas and + options (e.g ``--fvisibility=``). Deprecated Compiler Flags ------------------------- @@ -347,6 +357,9 @@ Modified Compiler Flags ``rtdcall``. This new default CC only works for M68k and will use the new ``m68k_rtdcc`` CC on every functions that are not variadic. The ``-mrtd`` driver/frontend flag has the same effect when targeting M68k. +* ``-fvisibility-global-new-delete-hidden`` is now a deprecated spelling of + ``-fvisibility-global-new-delete=force-hidden`` (``-fvisibility-global-new-delete=`` + is new in this release). Removed Compiler Flags ------------------------- diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index f181da9aea6f9..c0ab6b97dd8db 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -308,7 +308,8 @@ BENIGN_LANGOPT(IgnoreXCOFFVisibility, 1, 0, "All the visibility attributes that BENIGN_LANGOPT(VisibilityInlinesHiddenStaticLocalVar, 1, 0, "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") +ENUM_LANGOPT(GlobalAllocationFunctionVisibility, VisibilityForcedKinds, 3, VisibilityForcedKinds::ForceDefault, + "How to apply visibility to global operator new and delete declarations") 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") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 976a00d1a6fa5..79947431e4e2c 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -381,6 +381,17 @@ class LangOptions : public LangOptionsBase { All, }; + enum class VisibilityForcedKinds { + /// Force hidden visibility + ForceHidden, + /// Force protected visibility + ForceProtected, + /// Force default visibility + ForceDefault, + /// Don't alter the visibility + Source, + }; + enum class VisibilityFromDLLStorageClassKinds { /// Keep the IR-gen assigned visibility. Keep, @@ -673,6 +684,26 @@ class LangOptions : public LangOptionsBase { DefaultVisiblityExportMapping::All; } + bool hasGlobalAllocationFunctionVisibility() const { + return getGlobalAllocationFunctionVisibility() != + VisibilityForcedKinds::Source; + } + + bool hasDefaultGlobalAllocationFunctionVisibility() const { + return getGlobalAllocationFunctionVisibility() == + VisibilityForcedKinds::ForceDefault; + } + + bool hasProtectedGlobalAllocationFunctionVisibility() const { + return getGlobalAllocationFunctionVisibility() == + VisibilityForcedKinds::ForceProtected; + } + + bool hasHiddenGlobalAllocationFunctionVisibility() const { + return getGlobalAllocationFunctionVisibility() == + VisibilityForcedKinds::ForceHidden; + } + /// Remap path prefix according to -fmacro-prefix-path option. void remapPathPrefix(SmallVectorImpl &Path) const; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 199537404d0c6..95579d30cd293 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3910,9 +3910,16 @@ def fvisibility_ms_compat : Flag<["-"], "fvisibility-ms-compat">, Group HelpText<"Give global types 'default' visibility and global functions and " "variables 'hidden' visibility by default">; def fvisibility_global_new_delete_hidden : Flag<["-"], "fvisibility-global-new-delete-hidden">, Group, - HelpText<"Give global C++ operator new and delete declarations hidden visibility">, + HelpText<"Give global C++ operator new and delete declarations hidden visibility">; +class MarshallingInfoVisibilityGlobalNewDelete + : MarshallingInfoEnum, + Values<"force-default,force-protected,force-hidden,source">, + NormalizedValuesScope<"LangOptions::VisibilityForcedKinds">, + NormalizedValues<["ForceDefault", "ForceProtected", "ForceHidden", "Source"]> {} +def fvisibility_global_new_delete_EQ : Joined<["-"], "fvisibility-global-new-delete=">, Group, Visibility<[ClangOption, CC1Option]>, - MarshallingInfoFlag>; + HelpText<"The visibility for global C++ operator new and delete declarations. If 'source' is specified the visibility is not adjusted">, + MarshallingInfoVisibilityGlobalNewDelete, "ForceDefault">; def mdefault_visibility_export_mapping_EQ : Joined<["-"], "mdefault-visibility-export-mapping=">, Values<"none,explicit,all">, NormalizedValuesScope<"LangOptions::DefaultVisiblityExportMapping">, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index fead2e884030e..f80f8e44de1c4 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6325,7 +6325,28 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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); + + // -fvisibility-global-new-delete-hidden is a deprecated spelling of + // -fvisibility-global-new-delete=force-hidden. + if (const Arg *A = + Args.getLastArg(options::OPT_fvisibility_global_new_delete_hidden)) { + D.Diag(diag::warn_drv_deprecated_arg) + << A->getAsString(Args) + << "-fvisibility-global-new-delete=force-hidden"; + } + + if (const Arg *A = + Args.getLastArg(options::OPT_fvisibility_global_new_delete_EQ, + options::OPT_fvisibility_global_new_delete_hidden)) { + if (A->getOption().matches(options::OPT_fvisibility_global_new_delete_EQ)) { + A->render(Args, CmdArgs); + } else { + assert(A->getOption().matches( + options::OPT_fvisibility_global_new_delete_hidden)); + CmdArgs.push_back("-fvisibility-global-new-delete=force-hidden"); + } + } + Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); if (Args.hasFlag(options::OPT_fnew_infallible, diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp index 287d2e98931da..8ba8b80cfec78 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -359,6 +359,12 @@ void toolchains::PS4PS5Base::addClangTargetOptions( CC1Args.push_back("-fno-use-init-array"); + // Default to -fvisibility-global-new-delete=source for PS5. + if (getTriple().isPS5() && + !DriverArgs.hasArg(options::OPT_fvisibility_global_new_delete_EQ, + options::OPT_fvisibility_global_new_delete_hidden)) + CC1Args.push_back("-fvisibility-global-new-delete=source"); + const Arg *A = DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass, options::OPT_fno_visibility_from_dllstorageclass); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 482afb5a677ec..953bfe484a528 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -3216,10 +3216,13 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, Alloc->setLocalOwningModule(TheGlobalModuleFragment); } - Alloc->addAttr(VisibilityAttr::CreateImplicit( - Context, LangOpts.GlobalAllocationFunctionVisibilityHidden - ? VisibilityAttr::Hidden - : VisibilityAttr::Default)); + if (LangOpts.hasGlobalAllocationFunctionVisibility()) + Alloc->addAttr(VisibilityAttr::CreateImplicit( + Context, LangOpts.hasHiddenGlobalAllocationFunctionVisibility() + ? VisibilityAttr::Hidden + : LangOpts.hasProtectedGlobalAllocationFunctionVisibility() + ? VisibilityAttr::Protected + : VisibilityAttr::Default)); llvm::SmallVector ParamDecls; for (QualType T : Params) { diff --git a/clang/test/CodeGenCXX/visibility-global-new-delete.cpp b/clang/test/CodeGenCXX/visibility-global-new-delete.cpp new file mode 100644 index 0000000000000..4e9445c9a55cc --- /dev/null +++ b/clang/test/CodeGenCXX/visibility-global-new-delete.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 %s -std=c++11 -triple x86_64-unknown-unknown -fvisibility=hidden -emit-llvm -o - | FileCheck %s -DLINKAGE=dso_local +// RUN: %clang_cc1 %s -std=c++11 -triple x86_64-unknown-unknown -fvisibility=default -fvisibility-global-new-delete=force-hidden -emit-llvm -o - | FileCheck %s -DLINKAGE=hidden +// RUN: %clang_cc1 %s -std=c++11 -triple x86_64-unknown-unknown -fvisibility=hidden -fvisibility-global-new-delete=force-protected -emit-llvm -o - | FileCheck %s -DLINKAGE=protected +// RUN: %clang_cc1 %s -std=c++11 -triple x86_64-unknown-unknown -fvisibility=hidden -fvisibility-global-new-delete=force-default -emit-llvm -o - | FileCheck %s -DLINKAGE=dso_local +// RUN: %clang_cc1 %s -std=c++11 -triple x86_64-unknown-unknown -fvisibility=hidden -fvisibility-global-new-delete=source -emit-llvm -o - | FileCheck %s -DLINKAGE=hidden + +namespace std { + typedef __typeof__(sizeof(0)) size_t; + struct nothrow_t {}; +} + +// Definition which inherits visibility from the implicit compiler generated declaration. +void operator delete(void*) throw() {} +// CHECK: define [[LINKAGE]] void @_ZdlPv diff --git a/clang/test/Driver/visibility-global-new-delete.cl b/clang/test/Driver/visibility-global-new-delete.cl new file mode 100644 index 0000000000000..3e7f3c8cd1acb --- /dev/null +++ b/clang/test/Driver/visibility-global-new-delete.cl @@ -0,0 +1,52 @@ +/// Check driver handling for "-fvisibility-global-new-delete-hidden" and "-fvisibility-global-new-delete=". + +/// These options are not added by default. +// RUN: %clang -### --target=x86_64-unknown-unknown -c -emit-llvm %s 2>&1 | \ +// RUN: FileCheck -check-prefix=DEFAULTS %s +// DEFAULTS-NOT: "-fvisibility-global-new-delete=" +// DEFAULTS-NOT: "-fvisibility-global-new-delete-hidden" + +// DEFINE: %{implicit-check-nots} = --implicit-check-not=-fvisibility-global-new-delete= --implicit-check-not=-fvisibility-global-new-delete-hidden + +/// "-fvisibility-global-new-delete=source" added by default for PS5. +// RUN: %clang -### --target=x86_64-sie-ps5 -c -emit-llvm %s 2>&1 | \ +// RUN: FileCheck -check-prefix=PS5 %s +// PS5: "-fvisibility-global-new-delete=source" + +/// -fvisibility-global-new-delete-hidden added explicitly. +// RUN: %clang -### --target=x86_64-unknown-unknown -c -emit-llvm \ +// RUN: -fvisibility-global-new-delete-hidden %s 2>&1 | FileCheck -check-prefixes=VGNDH,DEPRECATED %s %{implicit-check-nots} +// RUN: %clang -### --target=x86_64-sie-ps5 -c -emit-llvm \ +// RUN: -fvisibility-global-new-delete-hidden %s 2>&1 | FileCheck -check-prefixes=VGNDH,DEPRECATED %s %{implicit-check-nots} +// DEPRECATED-DAG: clang: warning: argument '-fvisibility-global-new-delete-hidden' is deprecated, use '-fvisibility-global-new-delete=force-hidden' instead [-Wdeprecated] +// VGNDH-DAG: "-fvisibility-global-new-delete=force-hidden" + +/// -fvisibility-global-new-delete=force-hidden added explicitly. +// RUN: %clang -### --target=x86_64-unknown-unknown -c -emit-llvm \ +// RUN: -fvisibility-global-new-delete=force-hidden %s 2>&1 | FileCheck -check-prefixes=VGNDH %s %{implicit-check-nots} +// RUN: %clang -### --target=x86_64-sie-ps5 -c -emit-llvm \ +// RUN: -fvisibility-global-new-delete=force-hidden %s 2>&1 | FileCheck -check-prefixes=VGNDH %s %{implicit-check-nots} + +/// -fvisibility-global-new-delete=force-protected added explicitly. +// RUN: %clang -### --target=x86_64-unknown-unknown -c -emit-llvm \ +// RUN: -fvisibility-global-new-delete=force-protected %s 2>&1 | FileCheck -check-prefixes=VGNDP %s %{implicit-check-nots} +// RUN: %clang -### --target=x86_64-sie-ps5 -c -emit-llvm \ +// RUN: -fvisibility-global-new-delete=force-protected %s 2>&1 | FileCheck -check-prefixes=VGNDP %s %{implicit-check-nots} +// VGNDP-DAG: "-fvisibility-global-new-delete=force-protected" + +/// -fvisibility-global-new-delete=force-default added explicitly. +// RUN: %clang -### --target=x86_64-unknown-unknown -c -emit-llvm \ +// RUN: -fvisibility-global-new-delete=force-default %s 2>&1 | FileCheck -check-prefixes=VGNDD %s %{implicit-check-nots} +// RUN: %clang -### --target=x86_64-sie-ps5 -c -emit-llvm \ +// RUN: -fvisibility-global-new-delete=force-default %s 2>&1 | FileCheck -check-prefixes=VGNDD %s %{implicit-check-nots} +// VGNDD-DAG: "-fvisibility-global-new-delete=force-default" + +/// last specfied used: -fvisibility-global-new-delete-hidden. +// RUN: %clang -### --target=x86_64-unknown-unknown -c -emit-llvm \ +// RUN: -fvisibility-global-new-delete=force-default -fvisibility-global-new-delete=force-protected -fvisibility-global-new-delete-hidden %s 2>&1 | \ +// RUN: FileCheck -check-prefixes=VGNDH,DEPRECATED %s %{implicit-check-nots} + +/// last specfied used: -fvisibility-global-new-delete=. +// RUN: %clang -### --target=x86_64-unknown-unknown -c -emit-llvm \ +// RUN: -fvisibility-global-new-delete-hidden -fvisibility-global-new-delete=force-default -fvisibility-global-new-delete=force-protected %s 2>&1 | \ +// RUN: FileCheck -check-prefixes=VGNDP,DEPRECATED %s %{implicit-check-nots}