[clang] Ignore template parameter visibility (PR #72092)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 13 01:04:55 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Fangrui Song (MaskRay)
<details>
<summary>Changes</summary>
When computing the visibility of a template
specialization/instantiation, GCC considers template arguments and
ignores type template parameters.
We currently consider non-type template parameters, which adds a lot of
complexity and is also unnecessary for the majority of cases.
Non-type template arguments that affect the visibility are mostly
`TemplateArgument::Declaration`. If a non-type template argument
involves a `NamedDecl` without a `VisibilityAttr `, the `case
TemplateArgument::Declaration` code in `getLVForTemplateArgumentList`
handles the desired cases.
```
struct HIDDEN foo {};
DEFAULT foo da; // has a VisibilityAttr and is used in a non-type template argument (uncommon)
foo za; // the majority of cases, no VisibilityAttr
template void zed<&da>(); // w/o the patch: hidden, w/ the patch: default
template void zed<&za>(); // no behavior change
```
For the updated tests, they all behave the same as GCC.
---
Full diff: https://github.com/llvm/llvm-project/pull/72092.diff
3 Files Affected:
- (modified) clang/lib/AST/Decl.cpp (+9-99)
- (modified) clang/lib/AST/Linkage.h (-3)
- (modified) clang/test/CodeGenCXX/visibility.cpp (+19-35)
``````````diff
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index c5c2edf1bfe3aba..8a84dad4e4452ed 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -244,62 +244,6 @@ LinkageInfo LinkageComputer::getLVForType(const Type &T,
return getTypeLinkageAndVisibility(&T);
}
-/// Get the most restrictive linkage for the types in the given
-/// template parameter list. For visibility purposes, template
-/// parameters are part of the signature of a template.
-LinkageInfo LinkageComputer::getLVForTemplateParameterList(
- const TemplateParameterList *Params, LVComputationKind computation) {
- LinkageInfo LV;
- for (const NamedDecl *P : *Params) {
- // Template type parameters are the most common and never
- // contribute to visibility, pack or not.
- if (isa<TemplateTypeParmDecl>(P))
- continue;
-
- // Non-type template parameters can be restricted by the value type, e.g.
- // template <enum X> class A { ... };
- // We have to be careful here, though, because we can be dealing with
- // dependent types.
- if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
- // Handle the non-pack case first.
- if (!NTTP->isExpandedParameterPack()) {
- if (!NTTP->getType()->isDependentType()) {
- LV.merge(getLVForType(*NTTP->getType(), computation));
- }
- continue;
- }
-
- // Look at all the types in an expanded pack.
- for (unsigned i = 0, n = NTTP->getNumExpansionTypes(); i != n; ++i) {
- QualType type = NTTP->getExpansionType(i);
- if (!type->isDependentType())
- LV.merge(getTypeLinkageAndVisibility(type));
- }
- continue;
- }
-
- // Template template parameters can be restricted by their
- // template parameters, recursively.
- const auto *TTP = cast<TemplateTemplateParmDecl>(P);
-
- // Handle the non-pack case first.
- if (!TTP->isExpandedParameterPack()) {
- LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters(),
- computation));
- continue;
- }
-
- // Look at all expansions in an expanded pack.
- for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters();
- i != n; ++i) {
- LV.merge(getLVForTemplateParameterList(
- TTP->getExpansionTemplateParameters(i), computation));
- }
- }
-
- return LV;
-}
-
static const Decl *getOutermostFuncOrBlockContext(const Decl *D) {
const Decl *Ret = nullptr;
const DeclContext *DC = D->getDeclContext();
@@ -368,10 +312,9 @@ LinkageComputer::getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
const FunctionTemplateSpecializationInfo *specInfo) {
- // Include visibility from the template parameters and arguments
- // only if this is not an explicit instantiation or specialization
- // with direct explicit visibility. (Implicit instantiations won't
- // have a direct attribute.)
+ // Include visibility from the template arguments only if this is not an
+ // explicit instantiation or specialization with direct explicit visibility.
+ // (Implicit instantiations won't have a direct attribute.)
if (!specInfo->isExplicitInstantiationOrSpecialization())
return true;
@@ -399,11 +342,6 @@ void LinkageComputer::mergeTemplateLV(
// template declaration.
LV.setLinkage(tempLV.getLinkage());
- // Merge information from the template parameters.
- LinkageInfo paramsLV =
- getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
- LV.mergeMaybeWithVisibility(paramsLV, considerVisibility);
-
// Merge information from the template arguments.
const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation);
@@ -426,14 +364,13 @@ static bool hasDirectVisibilityAttribute(const NamedDecl *D,
static bool shouldConsiderTemplateVisibility(
const ClassTemplateSpecializationDecl *spec,
LVComputationKind computation) {
- // Include visibility from the template parameters and arguments
- // only if this is not an explicit instantiation or specialization
- // with direct explicit visibility (and note that implicit
- // instantiations won't have a direct attribute).
+ // Include visibility from the template arguments only if this is not an
+ // explicit instantiation or specialization with direct explicit visibility
+ // (and note that implicit instantiations won't have a direct attribute).
//
- // Furthermore, we want to ignore template parameters and arguments
- // for an explicit specialization when computing the visibility of a
- // member thereof with explicit visibility.
+ // Furthermore, we want to ignore template arguments for an explicit
+ // specialization when computing the visibility of a member thereof with
+ // explicit visibility.
//
// This is a bit complex; let's unpack it.
//
@@ -464,8 +401,6 @@ void LinkageComputer::mergeTemplateLV(
LVComputationKind computation) {
bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation);
- // Merge information from the template parameters, but ignore
- // visibility if we're only considering template arguments.
ClassTemplateDecl *temp = spec->getSpecializedTemplate();
// Merge information from the template declaration.
LinkageInfo tempLV = getLVForDecl(temp, computation);
@@ -473,11 +408,6 @@ void LinkageComputer::mergeTemplateLV(
// template declaration.
LV.setLinkage(tempLV.getLinkage());
- LinkageInfo paramsLV =
- getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
- LV.mergeMaybeWithVisibility(paramsLV,
- considerVisibility && !hasExplicitVisibilityAlready(computation));
-
// Merge information from the template arguments. We ignore
// template-argument visibility if we've got an explicit
// instantiation with a visibility attribute.
@@ -521,14 +451,6 @@ void LinkageComputer::mergeTemplateLV(LinkageInfo &LV,
LVComputationKind computation) {
bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation);
- // Merge information from the template parameters, but ignore
- // visibility if we're only considering template arguments.
- VarTemplateDecl *temp = spec->getSpecializedTemplate();
- LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
- LV.mergeMaybeWithVisibility(tempLV,
- considerVisibility && !hasExplicitVisibilityAlready(computation));
-
// Merge information from the template arguments. We ignore
// template-argument visibility if we've got an explicit
// instantiation with a visibility attribute.
@@ -858,10 +780,6 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
// - a template
} else if (const auto *temp = dyn_cast<TemplateDecl>(D)) {
- bool considerVisibility = !hasExplicitVisibilityAlready(computation);
- LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
- LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
// An unnamed namespace or a namespace declared directly or indirectly
// within an unnamed namespace has internal linkage. All other namespaces
@@ -1029,14 +947,6 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D,
// Template members.
} else if (const auto *temp = dyn_cast<TemplateDecl>(D)) {
- bool considerVisibility =
- (!LV.isVisibilityExplicit() &&
- !classLV.isVisibilityExplicit() &&
- !hasExplicitVisibilityAlready(computation));
- LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
- LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
-
if (const auto *redeclTemp = dyn_cast<RedeclarableTemplateDecl>(temp)) {
if (isExplicitMemberSpecialization(redeclTemp)) {
explicitSpecSuppressor = temp->getTemplatedDecl();
diff --git a/clang/lib/AST/Linkage.h b/clang/lib/AST/Linkage.h
index 31f384eb75d0b2e..0907bad8e656dbf 100644
--- a/clang/lib/AST/Linkage.h
+++ b/clang/lib/AST/Linkage.h
@@ -137,9 +137,6 @@ class LinkageComputer {
LinkageInfo getLVForType(const Type &T, LVComputationKind computation);
- LinkageInfo getLVForTemplateParameterList(const TemplateParameterList *Params,
- LVComputationKind computation);
-
LinkageInfo getLVForValue(const APValue &V, LVComputationKind computation);
public:
diff --git a/clang/test/CodeGenCXX/visibility.cpp b/clang/test/CodeGenCXX/visibility.cpp
index b017bc8b52d5a5d..30f9a6005b04078 100644
--- a/clang/test/CodeGenCXX/visibility.cpp
+++ b/clang/test/CodeGenCXX/visibility.cpp
@@ -83,9 +83,6 @@ namespace test41 {
}
namespace test48 {
- // Test that we use the visibility of struct foo when instantiating the
- // template. Note that is a case where we disagree with gcc, it produces
- // a default symbol.
struct HIDDEN foo {
};
DEFAULT foo x;
@@ -97,7 +94,7 @@ namespace test48 {
};
bar::zed<&x> y;
- // CHECK: _ZN6test481yE = hidden global
+ // CHECK: _ZN6test481yE = global
// CHECK-HIDDEN: _ZN6test481yE = hidden global
}
@@ -137,22 +134,22 @@ namespace test73 {
template int HIDDEN var<&hc>;
int use() { return var<&dd> + var<&hd>; }
- // CHECK: @_ZN6test733varIXadL_ZNS_2daEEEEE = weak_odr hidden global i32 0
+ // CHECK: @_ZN6test733varIXadL_ZNS_2daEEEEE = weak_odr global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2dbEEEEE = weak_odr global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2dcEEEEE = weak_odr hidden global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2haEEEEE = weak_odr hidden global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2hbEEEEE = weak_odr global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2hcEEEEE = weak_odr hidden global i32 0
- // CHECK: @_ZN6test733varIXadL_ZNS_2ddEEEEE = linkonce_odr hidden global i32 0
+ // CHECK: @_ZN6test733varIXadL_ZNS_2ddEEEEE = linkonce_odr global i32 0
// CHECK-NEXT: @_ZN6test733varIXadL_ZNS_2hdEEEEE = linkonce_odr hidden global i32 0
- // CHECK-HIDDEN: @_ZN6test733varIXadL_ZNS_2daEEEEE = weak_odr hidden global i32 0
+ // CHECK-HIDDEN: @_ZN6test733varIXadL_ZNS_2daEEEEE = weak_odr global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2dbEEEEE = weak_odr global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2dcEEEEE = weak_odr hidden global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2haEEEEE = weak_odr hidden global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2hbEEEEE = weak_odr global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2hcEEEEE = weak_odr hidden global i32 0
- // CHECK-HIDDEN: @_ZN6test733varIXadL_ZNS_2ddEEEEE = linkonce_odr hidden global i32 0
+ // CHECK-HIDDEN: @_ZN6test733varIXadL_ZNS_2ddEEEEE = linkonce_odr global i32 0
// CHECK-HIDDEN-NEXT: @_ZN6test733varIXadL_ZNS_2hdEEEEE = linkonce_odr hidden global i32 0
}
@@ -963,10 +960,9 @@ namespace test47 {
}
namespace test49 {
- // Test that we use the visibility of struct foo when instantiating the
- // template. Note that is a case where we disagree with gcc, it produces
- // a default symbol.
-
+ // When instantiating the template, we constraint the visibility with the
+ // non-type template argument &x. The type of &x does not constraint the
+ // visibility.
struct HIDDEN foo {
};
@@ -979,15 +975,11 @@ namespace test49 {
};
template void bar::zed<&x>();
- // CHECK-LABEL: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv
+ // CHECK-LABEL: define weak_odr void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test493bar3zedIXadL_ZNS_1xEEEEEvv
}
namespace test50 {
- // Test that we use the visibility of struct foo when instantiating the
- // template. Note that is a case where we disagree with gcc, it produces
- // a default symbol.
-
struct HIDDEN foo {
};
DEFAULT foo x;
@@ -997,15 +989,11 @@ namespace test50 {
}
};
template void bar<&x>::zed();
- // CHECK-LABEL: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv
- // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv
+ // CHECK-LABEL: define weak_odr void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test503barIXadL_ZNS_1xEEEE3zedEv
}
namespace test51 {
- // Test that we use the visibility of struct foo when instantiating the
- // template. Note that is a case where we disagree with gcc, it produces
- // a default symbol.
-
struct HIDDEN foo {};
DEFAULT foo da, db, dc, dd, de, df;
HIDDEN foo ha, hb, hc, hd, he, hf;
@@ -1013,8 +1001,8 @@ namespace test51 {
void DEFAULT zed() {
}
template void zed<&da>();
- // CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2daEEEEEvv(
- // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2daEEEEEvv(
+ // CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2daEEEEEvv(
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2daEEEEEvv(
template void DEFAULT zed<&db>();
// CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2dbEEEEEvv(
@@ -1041,10 +1029,10 @@ namespace test51 {
template void zed<&hd>();
template void DEFAULT zed<&he>();
#pragma GCC visibility pop
- // CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2ddEEEEEvv(
+ // CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2ddEEEEEvv(
// CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2hdEEEEEvv(
// CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2heEEEEEvv(
- // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2ddEEEEEvv(
+ // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2ddEEEEEvv(
// CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2hdEEEEEvv(
// CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2heEEEEEvv(
@@ -1052,17 +1040,13 @@ namespace test51 {
zed<&df>();
zed<&hf>();
}
- // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test513zedIXadL_ZNS_2dfEEEEEvv(
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test513zedIXadL_ZNS_2dfEEEEEvv(
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test513zedIXadL_ZNS_2hfEEEEEvv(
- // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test513zedIXadL_ZNS_2dfEEEEEvv(
+ // CHECK-HIDDEN-LABEL: define linkonce_odr void @_ZN6test513zedIXadL_ZNS_2dfEEEEEvv(
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test513zedIXadL_ZNS_2hfEEEEEvv(
}
namespace test52 {
- // Test that we use the linkage of struct foo when instantiating the
- // template. Note that is a case where we disagree with gcc, it produces
- // an external symbol.
-
namespace {
struct foo {
};
@@ -1273,8 +1257,8 @@ namespace test63 {
A::foo<E0>();
A::B<E0>::foo();
}
- // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test631A3fooILNS_1EE0EEEvv()
- // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test631A1BILNS_1EE0EE3fooEv()
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test631A3fooILNS_1EE0EEEvv()
+ // CHECK-LABEL: define linkonce_odr void @_ZN6test631A1BILNS_1EE0EE3fooEv()
}
// Don't ignore the visibility of template arguments just because we
``````````
</details>
https://github.com/llvm/llvm-project/pull/72092
More information about the cfe-commits
mailing list