diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -569,9 +569,6 @@ list Accessors = []; // Set to true for attributes with arguments which require delayed parsing. bit LateParsed = 0; - // Set to false to prevent an attribute from being propagated from a template - // to the instantiation. - bit Clone = 1; // Set to true for attributes which must be instantiated within templates bit TemplateDependent = 0; // Set to true for attributes that have a corresponding AST node. @@ -3027,7 +3024,6 @@ } def Visibility : InheritableAttr { - let Clone = 0; let Spellings = [GCC<"visibility">]; let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], @@ -3037,7 +3033,6 @@ } def TypeVisibility : InheritableAttr { - let Clone = 0; let Spellings = [Clang<"type_visibility">]; let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2885,9 +2885,11 @@ typename T::VisibilityType existingValue = existingAttr->getVisibility(); if (existingValue == value) return nullptr; - S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility); - S.Diag(CI.getLoc(), diag::note_previous_attribute); D->dropAttr(); + if (!existingAttr->isImplicit()) { + S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility); + S.Diag(CI.getLoc(), diag::note_previous_attribute); + } } return ::new (S.Context) T(S.Context, CI, value); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -815,6 +815,18 @@ continue; } + if (auto *A = dyn_cast(TmplAttr)) { + if (isa(Tmpl) && !New->hasAttr()) { + auto *NewA = A->clone(Context); + NewA->setImplicit(true); + New->addAttr(NewA); + } + continue; + } + + if (auto *A = dyn_cast(TmplAttr)) + continue; + assert(!TmplAttr->isPackExpansion()); if (TmplAttr->isLateParsed() && LateAttrs) { // Late parsed attributes must be instantiated and attached after the diff --git a/clang/test/CodeGenCXX/visibility.cpp b/clang/test/CodeGenCXX/visibility.cpp --- a/clang/test/CodeGenCXX/visibility.cpp +++ b/clang/test/CodeGenCXX/visibility.cpp @@ -1017,8 +1017,8 @@ 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( @@ -1029,8 +1029,8 @@ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2dcEEEEEvv( template void zed<&ha>(); - // CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2haEEEEEvv( - // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2haEEEEEvv( + // CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2haEEEEEvv( + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2haEEEEEvv( template void DEFAULT zed<&hb>(); // CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2hbEEEEEvv( @@ -1429,6 +1429,7 @@ template template U foo::bar() { return {}; } + /// foo::{zed,bar} get the instantiated-from member's HIDDEN, overriding DEFAULT. extern template struct DEFAULT foo; int use() { @@ -1436,13 +1437,12 @@ foo p; return o.zed() + o.bar() + p.zed() + p.bar(); } - /// FIXME: foo::bar is hidden in GCC w/ or w/o -fvisibility=hidden. // CHECK-LABEL: declare hidden noundef i32 @_ZN6test713fooIiE3zedEv( - // CHECK-LABEL: define linkonce_odr noundef i32 @_ZN6test713fooIiE3barIiEET_v( + // CHECK-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIiE3barIiEET_v( // CHECK-LABEL: define linkonce_odr hidden noundef i64 @_ZN6test713fooIlE3zedEv( - // CHECK-LABEL: define linkonce_odr noundef i32 @_ZN6test713fooIlE3barIiEET_v( + // CHECK-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIlE3barIiEET_v( // CHECK-HIDDEN-LABEL: declare hidden noundef i32 @_ZN6test713fooIiE3zedEv( - // CHECK-HIDDEN-LABEL: define linkonce_odr noundef i32 @_ZN6test713fooIiE3barIiEET_v( + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIiE3barIiEET_v( // CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i64 @_ZN6test713fooIlE3zedEv( // CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIlE3barIiEET_v( } diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3667,8 +3667,7 @@ if (!R.getValueAsBit("ASTNode")) continue; OS << " case attr::" << R.getName() << ": {\n"; - bool ShouldClone = R.getValueAsBit("Clone") && - (!AppliesToDecl || + bool ShouldClone = (!AppliesToDecl || R.getValueAsBit("MeaningfulToClassTemplateDefinition")); if (!ShouldClone) {