[clang] [Sema] Provide `-fvisibility-global-new-delete=` option (PR #75364)

via cfe-commits cfe-commits at lists.llvm.org
Sun Jan 21 09:18:15 PST 2024


https://github.com/bd1976bris updated https://github.com/llvm/llvm-project/pull/75364

>From dc60cb247ababb304a9602043e23259303761878 Mon Sep 17 00:00:00 2001
From: Ben Dunbobbin <Ben.Dunbobbin at sony.com>
Date: Sun, 21 Jan 2024 16:46:07 +0000
Subject: [PATCH] [Sema] Add `-fvisibility-global-new-delete=` option

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 8bb26fcae18d6b..d6efc63a5dfe17 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -310,7 +310,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
@@ -321,6 +321,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=<value>`` 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
 -------------------------
@@ -337,6 +347,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 f181da9aea6f97..c0ab6b97dd8dbe 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 976a00d1a6fa51..79947431e4e2cc 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<char> &Path) const;
 
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index f1687d823f6e0a..63ea7f9c51b9ec 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<f_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<f_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<KeyPathAndMacro kpm, code default>
+  : MarshallingInfoEnum<kpm, default>,
+    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<f_Group>,
   Visibility<[ClangOption, CC1Option]>,
-  MarshallingInfoFlag<LangOpts<"GlobalAllocationFunctionVisibilityHidden">>;
+  HelpText<"The visibility for global C++ operator new and delete declarations. If 'source' is specified the visibility is not adjusted">,
+  MarshallingInfoVisibilityGlobalNewDelete<LangOpts<"GlobalAllocationFunctionVisibility">, "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 fead2e884030e2..f80f8e44de1c43 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 287d2e98931dac..8ba8b80cfec78e 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 8b6a80b45b27b1..2a043b22de6657 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3226,10 +3226,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<ParmVarDecl *, 3> 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 00000000000000..4e9445c9a55cc1
--- /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 00000000000000..3e7f3c8cd1acbf
--- /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}



More information about the cfe-commits mailing list