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

via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 19 01:24:33 PST 2024


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

>From 97efed8c73aed4fdca5510013c844e84953ec256 Mon Sep 17 00:00:00 2001
From: Ben Dunbobbin <Ben.Dunbobbin at sony.com>
Date: Tue, 12 Dec 2023 08:07:17 +0000
Subject: [PATCH 1/4] [Sema] Provide `-fno-/-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: `-fno/-fvisibility-global-new-delete` which controls
whether or not to add a visibility attribute to the implicit
declarations for these functions. Without the attribute the replaceable
global new and delete operators behave normally (like other functions)
with respect to visibility attributes, pragmas and options.

The command line help for these options is rendered as:

  -fvisibility-global-new-delete
                          Add a visibility attribute to the implicit
                          global C++ operator new and delete declarations

  -fno-visibility-global-new-delete
                          Do not add a visibility attribute to the implicit
                          global C++ operator new and delete declarations

The motivation is to allow users to specify
`-fno-visibility-global-new-delete` when they intend to replace these
functions either for a single linkage unit or set of linkage units.

`-fno-visibility-global-new-delete` can be applied globally to the
compilations in a build where `-fvisibility-global-new-delete-hidden`
cannot; as it conflicts with a common pattern where these functions are
dynamically imported.

`-fno-visibility-global-new-delete` makes sense as the default for PS5.
Users that want the normal toolchain behaviour will be able to supply
`-fvisibility-global-new-delete`.
---
 clang/include/clang/Basic/LangOptions.def     |  3 +-
 clang/include/clang/Driver/Options.td         |  6 +++
 clang/lib/Driver/ToolChains/Clang.cpp         | 12 +++++
 clang/lib/Driver/ToolChains/PS4CPU.cpp        |  6 +++
 clang/lib/Sema/SemaExprCXX.cpp                |  9 ++--
 .../visibility-global-new-delete.cpp          | 13 +++++
 .../Driver/visibility-global-new-delete.cl    | 47 +++++++++++++++++++
 7 files changed, 91 insertions(+), 5 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/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index c3d5399905a3fd..1471fc11e11663 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -306,7 +306,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")
+LANGOPT(GlobalAllocationFunctionVisibility, 1, 1, "add a visibility attribute to the implicit global operator new and delete declarations")
+LANGOPT(GlobalAllocationFunctionVisibilityHidden, 1, 0, "hidden visibility for 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/Driver/Options.td b/clang/include/clang/Driver/Options.td
index db2190318c931a..a9f43b18df6fbf 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3863,6 +3863,12 @@ defm visibility_inlines_hidden_static_local_var : BoolFOption<"visibility-inline
 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">;
+defm visibility_global_new_delete : BoolFOption<"visibility-global-new-delete",
+  LangOpts<"GlobalAllocationFunctionVisibility">, DefaultTrue,
+  PosFlag<SetTrue, [], [ClangOption], "Add">,
+  NegFlag<SetFalse, [], [ClangOption], "Do not add">,
+  BothFlags<[], [ClangOption, CC1Option],
+          " a visibility attribute to the implicit global C++ operator new and delete declarations">>;
 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">,
   Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index f02f7c841b91f0..979e2a0e83be37 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6204,7 +6204,19 @@ 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,
+                           options::OPT_fno_visibility_global_new_delete);
   Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden);
+  // Error for incompatible global new and delete directives.
+  const Arg *N = Args.getLastArg(options::OPT_fvisibility_global_new_delete,
+                                 options::OPT_fno_visibility_global_new_delete);
+  if (N &&
+      N->getOption().matches(options::OPT_fno_visibility_global_new_delete)) {
+    if (Arg *H =
+            Args.getLastArg(options::OPT_fvisibility_global_new_delete_hidden))
+      D.Diag(diag::err_drv_incompatible_options)
+          << N->getSpelling() << H->getSpelling();
+  }
   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 5fd82d1da19926..a535d5fb2a7200 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 -fno-visibility-global-new-delete for PS5.
+  if (getTriple().isPS5() &&
+      !DriverArgs.hasArg(options::OPT_fvisibility_global_new_delete,
+                         options::OPT_fno_visibility_global_new_delete,
+                         options::OPT_fvisibility_global_new_delete_hidden))
+    CC1Args.push_back("-fno-visibility-global-new-delete");
   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 081b568762ae22..29480a1e0c0346 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3222,10 +3222,11 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
       Alloc->setLocalOwningModule(TheGlobalModuleFragment);
     }
 
-    Alloc->addAttr(VisibilityAttr::CreateImplicit(
-        Context, LangOpts.GlobalAllocationFunctionVisibilityHidden
-                     ? VisibilityAttr::Hidden
-                     : VisibilityAttr::Default));
+    if (LangOpts.GlobalAllocationFunctionVisibility)
+      Alloc->addAttr(VisibilityAttr::CreateImplicit(
+          Context, LangOpts.GlobalAllocationFunctionVisibilityHidden
+                       ? VisibilityAttr::Hidden
+                       : 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..b29a5f01e9a647
--- /dev/null
+++ b/clang/test/CodeGenCXX/visibility-global-new-delete.cpp
@@ -0,0 +1,13 @@
+// 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=hidden -fvisibility-global-new-delete -emit-llvm -o - | FileCheck %s -DLINKAGE=dso_local
+// RUN: %clang_cc1 %s -std=c++11 -triple x86_64-unknown-unknown -fvisibility=hidden -fno-visibility-global-new-delete -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-hidden -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..08e3a812887452
--- /dev/null
+++ b/clang/test/Driver/visibility-global-new-delete.cl
@@ -0,0 +1,47 @@
+/// 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 -x cl -c -emit-llvm %s 2>&1 | \
+// RUN:   FileCheck -check-prefix=DEFAULTS %s
+// DEFAULTS-NOT: "-fvisibility-global-new-delete"
+// DEFAULTS-NOT: "-fno-visibility-global-new-delete"
+// DEFAULTS-NOT: "-fvisibility-global-new-delete-hidden"
+
+// DEFINE: %{implicit-check-nots} = --implicit-check-not=-fvisibility-global-new-delete --implicit-check-not=-fno-visibility-global-new-delete
+
+/// "-fno-visibility-global-new-delete" added by default for PS5.
+// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm %s 2>&1 | \
+// RUN:   FileCheck -check-prefix=PS5 %s 
+// PS5: "-fno-visibility-global-new-delete"
+
+/// -fvisibility-global-new-delete-hidden added explicitly.
+// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
+// RUN:   -fvisibility-global-new-delete-hidden %s 2>&1 | FileCheck -check-prefixes=HIDDEN %s %{implicit-check-nots}
+// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
+// RUN:   -fvisibility-global-new-delete-hidden %s 2>&1 | FileCheck -check-prefixes=HIDDEN %s %{implicit-check-nots}
+// HIDDEN-DAG: "-fvisibility-global-new-delete-hidden"
+
+/// -fvisibility-global-new-delete added explicitly.
+// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
+// RUN:   -fvisibility-global-new-delete %s 2>&1 | FileCheck -check-prefixes=VGND %s %{implicit-check-nots}
+// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
+// RUN:   -fvisibility-global-new-delete %s 2>&1 | FileCheck -check-prefixes=VGND %s %{implicit-check-nots}
+// VGND-DAG: "-fvisibility-global-new-delete"
+
+/// -fno-visibility-global-new-delete added explicitly.
+// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
+// RUN:   -fno-visibility-global-new-delete %s 2>&1 | FileCheck -check-prefixes=NO_VGND %s %{implicit-check-nots}
+// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
+// RUN:   -fno-visibility-global-new-delete %s 2>&1 | FileCheck -check-prefixes=NO_VGND %s %{implicit-check-nots}
+// NO_VGND-DAG: "-fno-visibility-global-new-delete"
+
+/// No error if both -fvisibility-global-new-delete and -fvisibility-global-new-delete-hidden specified.
+// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \ 
+// RUN:   -fvisibility-global-new-delete-hidden -fvisibility-global-new-delete %s 2>&1 | \
+// RUN:     FileCheck -check-prefixes=VGND,HIDDEN %s %{implicit-check-nots}
+
+/// Error if both -fno-visibility-global-new-delete and -fvisibility-global-new-delete-hidden specified.
+// RUN: not %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \ 
+// RUN:   -fvisibility-global-new-delete-hidden -fvisibility-global-new-delete -fno-visibility-global-new-delete %s 2>&1 | \
+// RUN:     FileCheck -check-prefixes=INCOMPAT %s
+// INCOMPAT: clang: error: the combination of '-fno-visibility-global-new-delete' and '-fvisibility-global-new-delete-hidden' is incompatible

>From b48efc45f9b3306a3f740eb58099c7d436b73e43 Mon Sep 17 00:00:00 2001
From: Ben Dunbobbin <Ben.Dunbobbin at sony.com>
Date: Thu, 14 Dec 2023 08:30:22 +0000
Subject: [PATCH 2/4] appease CI clang-format check. Previously, I had matched
 the coding style of the sourrounding code.

---
 clang/lib/Driver/ToolChains/Clang.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 979e2a0e83be37..ae92cfc2d8ee2b 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6205,7 +6205,7 @@ 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,
-                           options::OPT_fno_visibility_global_new_delete);
+                  options::OPT_fno_visibility_global_new_delete);
   Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden);
   // Error for incompatible global new and delete directives.
   const Arg *N = Args.getLastArg(options::OPT_fvisibility_global_new_delete,

>From dea61c3c74b437784abc1bb6ba2f239c571d1641 Mon Sep 17 00:00:00 2001
From: Ben Dunbobbin <Ben.Dunbobbin at sony.com>
Date: Thu, 21 Dec 2023 16:25:03 +0000
Subject: [PATCH 3/4] Use suggested
 `-f[no-]forced-global-new-delete-visibility` option name

The options are rendered as:

  -fforced-global-new-delete-visibility
    Force the visibility of the implicit global C++ operator new
    and delete declarations

  -fno-forced-global-new-delete-visibility
    Do not force the visibility of the implicit global C++ operator
    new and delete declarations
---
 clang/include/clang/Basic/LangOptions.def     |  2 +-
 clang/include/clang/Driver/Options.td         | 10 ++--
 clang/lib/Driver/ToolChains/Clang.cpp         | 13 ++---
 clang/lib/Driver/ToolChains/PS4CPU.cpp        |  8 ++--
 clang/lib/Sema/SemaExprCXX.cpp                |  2 +-
 .../visibility-global-new-delete.cpp          |  4 +-
 .../forced-global-new-delete-visibility.cl    | 47 +++++++++++++++++++
 .../Driver/visibility-global-new-delete.cl    | 47 -------------------
 8 files changed, 67 insertions(+), 66 deletions(-)
 create mode 100644 clang/test/Driver/forced-global-new-delete-visibility.cl
 delete mode 100644 clang/test/Driver/visibility-global-new-delete.cl

diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 1471fc11e11663..d3cb3838b5b7da 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -306,7 +306,7 @@ 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(GlobalAllocationFunctionVisibility, 1, 1, "add a visibility attribute to the implicit global operator new and delete declarations")
+LANGOPT(GlobalAllocationFunctionVisibilityAttr, 1, 1, "apply a visibility attribute to the implicit global operator new and delete declarations")
 LANGOPT(GlobalAllocationFunctionVisibilityHidden, 1, 0, "hidden visibility for 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")
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index a9f43b18df6fbf..968766c7dc22a9 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3863,12 +3863,12 @@ defm visibility_inlines_hidden_static_local_var : BoolFOption<"visibility-inline
 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">;
-defm visibility_global_new_delete : BoolFOption<"visibility-global-new-delete",
-  LangOpts<"GlobalAllocationFunctionVisibility">, DefaultTrue,
-  PosFlag<SetTrue, [], [ClangOption], "Add">,
-  NegFlag<SetFalse, [], [ClangOption], "Do not add">,
+defm forced_global_new_delete_visibility : BoolFOption<"forced-global-new-delete-visibility",
+  LangOpts<"GlobalAllocationFunctionVisibilityAttr">, DefaultTrue,
+  PosFlag<SetTrue, [], [ClangOption], "Force">,
+  NegFlag<SetFalse, [], [ClangOption], "Do not force">,
   BothFlags<[], [ClangOption, CC1Option],
-          " a visibility attribute to the implicit global C++ operator new and delete declarations">>;
+          " the visibility of the implicit global C++ operator new and delete declarations">>;
 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">,
   Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index ae92cfc2d8ee2b..b0313e57320422 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6204,14 +6204,15 @@ 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,
-                  options::OPT_fno_visibility_global_new_delete);
+  Args.AddLastArg(CmdArgs, options::OPT_fforced_global_new_delete_visibility,
+                  options::OPT_fno_forced_global_new_delete_visibility);
   Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden);
   // Error for incompatible global new and delete directives.
-  const Arg *N = Args.getLastArg(options::OPT_fvisibility_global_new_delete,
-                                 options::OPT_fno_visibility_global_new_delete);
-  if (N &&
-      N->getOption().matches(options::OPT_fno_visibility_global_new_delete)) {
+  const Arg *N =
+      Args.getLastArg(options::OPT_fforced_global_new_delete_visibility,
+                      options::OPT_fno_forced_global_new_delete_visibility);
+  if (N && N->getOption().matches(
+               options::OPT_fno_forced_global_new_delete_visibility)) {
     if (Arg *H =
             Args.getLastArg(options::OPT_fvisibility_global_new_delete_hidden))
       D.Diag(diag::err_drv_incompatible_options)
diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp
index a535d5fb2a7200..053eb7a7d7606d 100644
--- a/clang/lib/Driver/ToolChains/PS4CPU.cpp
+++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp
@@ -359,12 +359,12 @@ void toolchains::PS4PS5Base::addClangTargetOptions(
 
   CC1Args.push_back("-fno-use-init-array");
 
-  // Default to -fno-visibility-global-new-delete for PS5.
+  // Default to -fno-forced-global-new-delete-visibility for PS5.
   if (getTriple().isPS5() &&
-      !DriverArgs.hasArg(options::OPT_fvisibility_global_new_delete,
-                         options::OPT_fno_visibility_global_new_delete,
+      !DriverArgs.hasArg(options::OPT_fforced_global_new_delete_visibility,
+                         options::OPT_fno_forced_global_new_delete_visibility,
                          options::OPT_fvisibility_global_new_delete_hidden))
-    CC1Args.push_back("-fno-visibility-global-new-delete");
+    CC1Args.push_back("-fno-forced-global-new-delete-visibility");
   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 29480a1e0c0346..00311b0dbcadab 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3222,7 +3222,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
       Alloc->setLocalOwningModule(TheGlobalModuleFragment);
     }
 
-    if (LangOpts.GlobalAllocationFunctionVisibility)
+    if (LangOpts.GlobalAllocationFunctionVisibilityAttr)
       Alloc->addAttr(VisibilityAttr::CreateImplicit(
           Context, LangOpts.GlobalAllocationFunctionVisibilityHidden
                        ? VisibilityAttr::Hidden
diff --git a/clang/test/CodeGenCXX/visibility-global-new-delete.cpp b/clang/test/CodeGenCXX/visibility-global-new-delete.cpp
index b29a5f01e9a647..d4765dd5934969 100644
--- a/clang/test/CodeGenCXX/visibility-global-new-delete.cpp
+++ b/clang/test/CodeGenCXX/visibility-global-new-delete.cpp
@@ -1,6 +1,6 @@
 // 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=hidden -fvisibility-global-new-delete -emit-llvm -o - | FileCheck %s -DLINKAGE=dso_local
-// RUN: %clang_cc1 %s -std=c++11 -triple x86_64-unknown-unknown -fvisibility=hidden -fno-visibility-global-new-delete -emit-llvm -o - | FileCheck %s -DLINKAGE=hidden
+// RUN: %clang_cc1 %s -std=c++11 -triple x86_64-unknown-unknown -fvisibility=hidden -fforced-global-new-delete-visibility -emit-llvm -o - | FileCheck %s -DLINKAGE=dso_local
+// RUN: %clang_cc1 %s -std=c++11 -triple x86_64-unknown-unknown -fvisibility=hidden -fno-forced-global-new-delete-visibility -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-hidden -emit-llvm -o - | FileCheck %s -DLINKAGE=hidden
 
 namespace std {
diff --git a/clang/test/Driver/forced-global-new-delete-visibility.cl b/clang/test/Driver/forced-global-new-delete-visibility.cl
new file mode 100644
index 00000000000000..85060952f3ec1f
--- /dev/null
+++ b/clang/test/Driver/forced-global-new-delete-visibility.cl
@@ -0,0 +1,47 @@
+/// Check driver handling for "-fvisibility-global-new-delete-hidden" and "-f[no-]forced-global-new-delete-visibility".
+
+/// These options are not added by default.
+// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm %s 2>&1 | \
+// RUN:   FileCheck -check-prefix=DEFAULTS %s
+// DEFAULTS-NOT: "-fforced-global-new-delete-visibility"
+// DEFAULTS-NOT: "-fno-forced-global-new-delete-visibility"
+// DEFAULTS-NOT: "-fvisibility-global-new-delete-hidden"
+
+// DEFINE: %{implicit-check-nots} = --implicit-check-not=-fforced-global-new-delete-visibility --implicit-check-not=-fno-forced-global-new-delete-visibility --implicit-check-not=-fvisibility-global-new-delete-hidden
+
+/// "-fno-forced-global-new-delete-visibility" added by default for PS5.
+// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm %s 2>&1 | \
+// RUN:   FileCheck -check-prefix=PS5 %s 
+// PS5: "-fno-forced-global-new-delete-visibility"
+
+/// -fvisibility-global-new-delete-hidden added explicitly.
+// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
+// RUN:   -fvisibility-global-new-delete-hidden %s 2>&1 | FileCheck -check-prefixes=HIDDEN %s %{implicit-check-nots}
+// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
+// RUN:   -fvisibility-global-new-delete-hidden %s 2>&1 | FileCheck -check-prefixes=HIDDEN %s %{implicit-check-nots}
+// HIDDEN-DAG: "-fvisibility-global-new-delete-hidden"
+
+/// -fforced-global-new-delete-visibility added explicitly.
+// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
+// RUN:   -fforced-global-new-delete-visibility %s 2>&1 | FileCheck -check-prefixes=FGNDV %s %{implicit-check-nots}
+// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
+// RUN:   -fforced-global-new-delete-visibility %s 2>&1 | FileCheck -check-prefixes=FGNDV %s %{implicit-check-nots}
+// FGNDV-DAG: "-fforced-global-new-delete-visibility"
+
+/// -fno-forced-global-new-delete-visibility added explicitly.
+// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
+// RUN:   -fno-forced-global-new-delete-visibility %s 2>&1 | FileCheck -check-prefixes=NO_FGNDV %s %{implicit-check-nots}
+// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
+// RUN:   -fno-forced-global-new-delete-visibility %s 2>&1 | FileCheck -check-prefixes=NO_FGNDV %s %{implicit-check-nots}
+// NO_FGNDV-DAG: "-fno-forced-global-new-delete-visibility"
+
+/// No error if both -fforced-global-new-delete-visibility and -fvisibility-global-new-delete-hidden specified.
+// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \ 
+// RUN:   -fvisibility-global-new-delete-hidden -fforced-global-new-delete-visibility %s 2>&1 | \
+// RUN:     FileCheck -check-prefixes=FGNDV,HIDDEN %s %{implicit-check-nots}
+
+/// Error if both -fno-forced-global-new-delete-visibility and -fvisibility-global-new-delete-hidden specified.
+// RUN: not %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \ 
+// RUN:   -fvisibility-global-new-delete-hidden -fforced-global-new-delete-visibility -fno-forced-global-new-delete-visibility %s 2>&1 | \
+// RUN:     FileCheck -check-prefixes=INCOMPAT %s
+// INCOMPAT: clang: error: the combination of '-fno-forced-global-new-delete-visibility' and '-fvisibility-global-new-delete-hidden' is incompatible
diff --git a/clang/test/Driver/visibility-global-new-delete.cl b/clang/test/Driver/visibility-global-new-delete.cl
deleted file mode 100644
index 08e3a812887452..00000000000000
--- a/clang/test/Driver/visibility-global-new-delete.cl
+++ /dev/null
@@ -1,47 +0,0 @@
-/// 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 -x cl -c -emit-llvm %s 2>&1 | \
-// RUN:   FileCheck -check-prefix=DEFAULTS %s
-// DEFAULTS-NOT: "-fvisibility-global-new-delete"
-// DEFAULTS-NOT: "-fno-visibility-global-new-delete"
-// DEFAULTS-NOT: "-fvisibility-global-new-delete-hidden"
-
-// DEFINE: %{implicit-check-nots} = --implicit-check-not=-fvisibility-global-new-delete --implicit-check-not=-fno-visibility-global-new-delete
-
-/// "-fno-visibility-global-new-delete" added by default for PS5.
-// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm %s 2>&1 | \
-// RUN:   FileCheck -check-prefix=PS5 %s 
-// PS5: "-fno-visibility-global-new-delete"
-
-/// -fvisibility-global-new-delete-hidden added explicitly.
-// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
-// RUN:   -fvisibility-global-new-delete-hidden %s 2>&1 | FileCheck -check-prefixes=HIDDEN %s %{implicit-check-nots}
-// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
-// RUN:   -fvisibility-global-new-delete-hidden %s 2>&1 | FileCheck -check-prefixes=HIDDEN %s %{implicit-check-nots}
-// HIDDEN-DAG: "-fvisibility-global-new-delete-hidden"
-
-/// -fvisibility-global-new-delete added explicitly.
-// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
-// RUN:   -fvisibility-global-new-delete %s 2>&1 | FileCheck -check-prefixes=VGND %s %{implicit-check-nots}
-// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
-// RUN:   -fvisibility-global-new-delete %s 2>&1 | FileCheck -check-prefixes=VGND %s %{implicit-check-nots}
-// VGND-DAG: "-fvisibility-global-new-delete"
-
-/// -fno-visibility-global-new-delete added explicitly.
-// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
-// RUN:   -fno-visibility-global-new-delete %s 2>&1 | FileCheck -check-prefixes=NO_VGND %s %{implicit-check-nots}
-// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
-// RUN:   -fno-visibility-global-new-delete %s 2>&1 | FileCheck -check-prefixes=NO_VGND %s %{implicit-check-nots}
-// NO_VGND-DAG: "-fno-visibility-global-new-delete"
-
-/// No error if both -fvisibility-global-new-delete and -fvisibility-global-new-delete-hidden specified.
-// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \ 
-// RUN:   -fvisibility-global-new-delete-hidden -fvisibility-global-new-delete %s 2>&1 | \
-// RUN:     FileCheck -check-prefixes=VGND,HIDDEN %s %{implicit-check-nots}
-
-/// Error if both -fno-visibility-global-new-delete and -fvisibility-global-new-delete-hidden specified.
-// RUN: not %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \ 
-// RUN:   -fvisibility-global-new-delete-hidden -fvisibility-global-new-delete -fno-visibility-global-new-delete %s 2>&1 | \
-// RUN:     FileCheck -check-prefixes=INCOMPAT %s
-// INCOMPAT: clang: error: the combination of '-fno-visibility-global-new-delete' and '-fvisibility-global-new-delete-hidden' is incompatible

>From 85efee55f752a4a17f648e5bef91c03f74010959 Mon Sep 17 00:00:00 2001
From: Ben Dunbobbin <Ben.Dunbobbin at sony.com>
Date: Fri, 19 Jan 2024 08:52:12 +0000
Subject: [PATCH 4/4] [Sema] Introduce `-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 assign. 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 visibility respectively. The use of the term
force in the value names is designed to imply to a user that the effects
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 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`

-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=default.
---
 clang/include/clang/Basic/LangOptions.def     |  4 +-
 clang/include/clang/Basic/LangOptions.h       | 31 +++++++++++
 clang/include/clang/Driver/Options.td         | 17 +++---
 clang/lib/Driver/ToolChains/Clang.cpp         | 37 +++++++------
 clang/lib/Driver/ToolChains/PS4CPU.cpp        |  8 +--
 clang/lib/Sema/SemaExprCXX.cpp                |  6 ++-
 .../visibility-global-new-delete.cpp          |  9 ++--
 .../forced-global-new-delete-visibility.cl    | 47 -----------------
 .../Driver/visibility-global-new-delete.cl    | 52 +++++++++++++++++++
 9 files changed, 125 insertions(+), 86 deletions(-)
 delete mode 100644 clang/test/Driver/forced-global-new-delete-visibility.cl
 create mode 100644 clang/test/Driver/visibility-global-new-delete.cl

diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index d3cb3838b5b7da..cd77fa99e648fa 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -306,8 +306,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(GlobalAllocationFunctionVisibilityAttr, 1, 1, "apply a visibility attribute to the implicit global operator new and delete declarations")
-LANGOPT(GlobalAllocationFunctionVisibilityHidden, 1, 0, "hidden visibility for global operator new and delete declarations")
+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 2d167dd2bdf128..71baaa7554c2d8 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -380,6 +380,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 StrictFlexArraysLevelKind {
     /// Any trailing array member is a FAM.
     Default = 0,
@@ -659,6 +670,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 968766c7dc22a9..315aa974b88e9f 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3863,16 +3863,17 @@ defm visibility_inlines_hidden_static_local_var : BoolFOption<"visibility-inline
 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">;
-defm forced_global_new_delete_visibility : BoolFOption<"forced-global-new-delete-visibility",
-  LangOpts<"GlobalAllocationFunctionVisibilityAttr">, DefaultTrue,
-  PosFlag<SetTrue, [], [ClangOption], "Force">,
-  NegFlag<SetFalse, [], [ClangOption], "Do not force">,
-  BothFlags<[], [ClangOption, CC1Option],
-          " the visibility of the implicit global C++ operator new and delete declarations">>;
 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 definitions. 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 b0313e57320422..c1f277cfe1cc62 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6198,26 +6198,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     }
   }
 
-  if (Args.hasFlag(options::OPT_fvisibility_inlines_hidden,
-                    options::OPT_fno_visibility_inlines_hidden, false))
-    CmdArgs.push_back("-fvisibility-inlines-hidden");
-
-  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_fforced_global_new_delete_visibility,
-                  options::OPT_fno_forced_global_new_delete_visibility);
-  Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden);
-  // Error for incompatible global new and delete directives.
-  const Arg *N =
-      Args.getLastArg(options::OPT_fforced_global_new_delete_visibility,
-                      options::OPT_fno_forced_global_new_delete_visibility);
-  if (N && N->getOption().matches(
-               options::OPT_fno_forced_global_new_delete_visibility)) {
-    if (Arg *H =
-            Args.getLastArg(options::OPT_fvisibility_global_new_delete_hidden))
-      D.Diag(diag::err_drv_incompatible_options)
-          << N->getSpelling() << H->getSpelling();
+  // -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 053eb7a7d7606d..baba44251ce55a 100644
--- a/clang/lib/Driver/ToolChains/PS4CPU.cpp
+++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp
@@ -359,12 +359,12 @@ void toolchains::PS4PS5Base::addClangTargetOptions(
 
   CC1Args.push_back("-fno-use-init-array");
 
-  // Default to -fno-forced-global-new-delete-visibility for PS5.
+  // Default to -fglobal-new-delete-visibility=source for PS5.
   if (getTriple().isPS5() &&
-      !DriverArgs.hasArg(options::OPT_fforced_global_new_delete_visibility,
-                         options::OPT_fno_forced_global_new_delete_visibility,
+      !DriverArgs.hasArg(options::OPT_fvisibility_global_new_delete_EQ,
                          options::OPT_fvisibility_global_new_delete_hidden))
-    CC1Args.push_back("-fno-forced-global-new-delete-visibility");
+    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 00311b0dbcadab..f3e9ad1b0f4b6b 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -3222,10 +3222,12 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
       Alloc->setLocalOwningModule(TheGlobalModuleFragment);
     }
 
-    if (LangOpts.GlobalAllocationFunctionVisibilityAttr)
+    if (LangOpts.hasGlobalAllocationFunctionVisibility())
       Alloc->addAttr(VisibilityAttr::CreateImplicit(
-          Context, LangOpts.GlobalAllocationFunctionVisibilityHidden
+          Context, LangOpts.hasHiddenGlobalAllocationFunctionVisibility()
                        ? VisibilityAttr::Hidden
+                   : LangOpts.hasProtectedGlobalAllocationFunctionVisibility()
+                       ? VisibilityAttr::Protected
                        : VisibilityAttr::Default));
 
     llvm::SmallVector<ParmVarDecl *, 3> ParamDecls;
diff --git a/clang/test/CodeGenCXX/visibility-global-new-delete.cpp b/clang/test/CodeGenCXX/visibility-global-new-delete.cpp
index d4765dd5934969..4e9445c9a55cc1 100644
--- a/clang/test/CodeGenCXX/visibility-global-new-delete.cpp
+++ b/clang/test/CodeGenCXX/visibility-global-new-delete.cpp
@@ -1,7 +1,8 @@
 // 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=hidden -fforced-global-new-delete-visibility -emit-llvm -o - | FileCheck %s -DLINKAGE=dso_local
-// RUN: %clang_cc1 %s -std=c++11 -triple x86_64-unknown-unknown -fvisibility=hidden -fno-forced-global-new-delete-visibility -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-hidden -emit-llvm -o - | FileCheck %s -DLINKAGE=hidden
+// 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;
@@ -10,4 +11,4 @@ namespace std {
 
 // Definition which inherits visibility from the implicit compiler generated declaration.
 void operator delete(void*) throw() {}
-// CHECK: define [[LINKAGE]]  void @_ZdlPv
+// CHECK: define [[LINKAGE]] void @_ZdlPv
diff --git a/clang/test/Driver/forced-global-new-delete-visibility.cl b/clang/test/Driver/forced-global-new-delete-visibility.cl
deleted file mode 100644
index 85060952f3ec1f..00000000000000
--- a/clang/test/Driver/forced-global-new-delete-visibility.cl
+++ /dev/null
@@ -1,47 +0,0 @@
-/// Check driver handling for "-fvisibility-global-new-delete-hidden" and "-f[no-]forced-global-new-delete-visibility".
-
-/// These options are not added by default.
-// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm %s 2>&1 | \
-// RUN:   FileCheck -check-prefix=DEFAULTS %s
-// DEFAULTS-NOT: "-fforced-global-new-delete-visibility"
-// DEFAULTS-NOT: "-fno-forced-global-new-delete-visibility"
-// DEFAULTS-NOT: "-fvisibility-global-new-delete-hidden"
-
-// DEFINE: %{implicit-check-nots} = --implicit-check-not=-fforced-global-new-delete-visibility --implicit-check-not=-fno-forced-global-new-delete-visibility --implicit-check-not=-fvisibility-global-new-delete-hidden
-
-/// "-fno-forced-global-new-delete-visibility" added by default for PS5.
-// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm %s 2>&1 | \
-// RUN:   FileCheck -check-prefix=PS5 %s 
-// PS5: "-fno-forced-global-new-delete-visibility"
-
-/// -fvisibility-global-new-delete-hidden added explicitly.
-// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
-// RUN:   -fvisibility-global-new-delete-hidden %s 2>&1 | FileCheck -check-prefixes=HIDDEN %s %{implicit-check-nots}
-// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
-// RUN:   -fvisibility-global-new-delete-hidden %s 2>&1 | FileCheck -check-prefixes=HIDDEN %s %{implicit-check-nots}
-// HIDDEN-DAG: "-fvisibility-global-new-delete-hidden"
-
-/// -fforced-global-new-delete-visibility added explicitly.
-// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
-// RUN:   -fforced-global-new-delete-visibility %s 2>&1 | FileCheck -check-prefixes=FGNDV %s %{implicit-check-nots}
-// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
-// RUN:   -fforced-global-new-delete-visibility %s 2>&1 | FileCheck -check-prefixes=FGNDV %s %{implicit-check-nots}
-// FGNDV-DAG: "-fforced-global-new-delete-visibility"
-
-/// -fno-forced-global-new-delete-visibility added explicitly.
-// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \
-// RUN:   -fno-forced-global-new-delete-visibility %s 2>&1 | FileCheck -check-prefixes=NO_FGNDV %s %{implicit-check-nots}
-// RUN: %clang -### -target x86_64-sie-ps5 -x cl -c -emit-llvm \
-// RUN:   -fno-forced-global-new-delete-visibility %s 2>&1 | FileCheck -check-prefixes=NO_FGNDV %s %{implicit-check-nots}
-// NO_FGNDV-DAG: "-fno-forced-global-new-delete-visibility"
-
-/// No error if both -fforced-global-new-delete-visibility and -fvisibility-global-new-delete-hidden specified.
-// RUN: %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \ 
-// RUN:   -fvisibility-global-new-delete-hidden -fforced-global-new-delete-visibility %s 2>&1 | \
-// RUN:     FileCheck -check-prefixes=FGNDV,HIDDEN %s %{implicit-check-nots}
-
-/// Error if both -fno-forced-global-new-delete-visibility and -fvisibility-global-new-delete-hidden specified.
-// RUN: not %clang -### -target x86_64-unknown-unknown -x cl -c -emit-llvm \ 
-// RUN:   -fvisibility-global-new-delete-hidden -fforced-global-new-delete-visibility -fno-forced-global-new-delete-visibility %s 2>&1 | \
-// RUN:     FileCheck -check-prefixes=INCOMPAT %s
-// INCOMPAT: clang: error: the combination of '-fno-forced-global-new-delete-visibility' and '-fvisibility-global-new-delete-hidden' is incompatible
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..ba2ca8f77c3f43
--- /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 -x cl -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 -x cl -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 -x cl -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 -x cl -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 -x cl -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 -x cl -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 -x cl -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 -x cl -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 -x cl -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 -x cl -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 -x cl -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 -x cl -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