Skip to content

Commit

Permalink
[Sema] Add -fvisibility-global-new-delete= option (#75364)
Browse files Browse the repository at this point in the history
[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`.
  • Loading branch information
bd1976bris committed Jan 22, 2024
1 parent df4ba00 commit 27ce26b
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 9 deletions.
15 changes: 14 additions & 1 deletion clang/docs/ReleaseNotes.rst
Expand Up @@ -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
Expand All @@ -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=<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
-------------------------
Expand All @@ -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
-------------------------
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/LangOptions.def
Expand Up @@ -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")
Expand Down
31 changes: 31 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Expand Up @@ -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,
Expand Down Expand Up @@ -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;

Expand Down
11 changes: 9 additions & 2 deletions clang/include/clang/Driver/Options.td
Expand Up @@ -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">,
Expand Down
23 changes: 22 additions & 1 deletion clang/lib/Driver/ToolChains/Clang.cpp
Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Driver/ToolChains/PS4CPU.cpp
Expand Up @@ -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);
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/Sema/SemaExprCXX.cpp
Expand Up @@ -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<ParmVarDecl *, 3> ParamDecls;
for (QualType T : Params) {
Expand Down
14 changes: 14 additions & 0 deletions 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
52 changes: 52 additions & 0 deletions 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}

0 comments on commit 27ce26b

Please sign in to comment.