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. @@ -2993,7 +2990,6 @@ } def Visibility : InheritableAttr { - let Clone = 0; let Spellings = [GCC<"visibility">]; let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], @@ -3003,7 +2999,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 @@ -2870,9 +2870,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 @@ -951,10 +951,6 @@ } 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 x, y; @@ -962,8 +958,9 @@ void DEFAULT zed() { } template void zed<&x>(); - // CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv - // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv + /// GCC emits hidden zed<&x> with -fvisibility=hidden. + // CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_1xEEEEEvv template void HIDDEN zed<&y>(); // CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_1yEEEEEvv( @@ -1349,15 +1346,15 @@ template template U foo::bar() { return {}; } + /// foo::{zed,bar} instantiate the HIDDEN attributes. extern template struct DEFAULT foo; int use() { foo o; return o.zed() + o.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-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( } 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 @@ -3627,8 +3627,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) {