diff options
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 8 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 68 | ||||
-rw-r--r-- | test/CodeGenCXX/visibility.cpp | 32 |
3 files changed, 84 insertions, 24 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index dc50d614bf..d2b1d3990c 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -314,6 +314,10 @@ public: return (TemplateSpecializationKind)(Template.getInt() + 1); } + bool isExplicitSpecialization() const { + return getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + } + /// \brief Set the template specialization kind. void setTemplateSpecializationKind(TemplateSpecializationKind TSK) { assert(TSK != TSK_Undeclared && @@ -1398,6 +1402,10 @@ public: return static_cast<TemplateSpecializationKind>(SpecializationKind); } + bool isExplicitSpecialization() const { + return getSpecializationKind() == TSK_ExplicitSpecialization; + } + void setSpecializationKind(TemplateSpecializationKind TSK) { SpecializationKind = TSK; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 7ca936abc9..9b507cfc5e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -197,6 +197,16 @@ getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), F); } +static bool shouldConsiderTemplateLV(const FunctionDecl *fn, + const FunctionTemplateSpecializationInfo *spec) { + return !(spec->isExplicitSpecialization() && + fn->hasAttr<VisibilityAttr>()); +} + +static bool shouldConsiderTemplateLV(const ClassTemplateSpecializationDecl *d) { + return !(d->isExplicitSpecialization() && d->hasAttr<VisibilityAttr>()); +} + static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && "Not a name having namespace scope"); @@ -397,12 +407,16 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { Function->getType()->getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); - if (FunctionTemplateSpecializationInfo *SpecInfo + // Consider LV from the template and the template arguments unless + // this is an explicit specialization with a visibility attribute. + if (FunctionTemplateSpecializationInfo *specInfo = Function->getTemplateSpecializationInfo()) { - LV.merge(getLVForDecl(SpecInfo->getTemplate(), - F.onlyTemplateVisibility())); - const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments; - LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); + if (shouldConsiderTemplateLV(Function, specInfo)) { + LV.merge(getLVForDecl(specInfo->getTemplate(), + F.onlyTemplateVisibility())); + const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments; + LV.merge(getLVForTemplateArgumentList(templateArgs, F)); + } } // - a named class (Clause 9), or an unnamed class defined in a @@ -418,15 +432,17 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { // If this is a class template specialization, consider the // linkage of the template and template arguments. - if (const ClassTemplateSpecializationDecl *Spec + if (const ClassTemplateSpecializationDecl *spec = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) { - // From the template. - LV.merge(getLVForDecl(Spec->getSpecializedTemplate(), - F.onlyTemplateVisibility())); - - // The arguments at which the template was instantiated. - const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); + if (shouldConsiderTemplateLV(spec)) { + // From the template. + LV.merge(getLVForDecl(spec->getSpecializedTemplate(), + F.onlyTemplateVisibility())); + + // The arguments at which the template was instantiated. + const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs(); + LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); + } } // Consider -fvisibility unless the type has C linkage. @@ -527,14 +543,16 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { // If this is a method template specialization, use the linkage for // the template parameters and arguments. - if (FunctionTemplateSpecializationInfo *Spec + if (FunctionTemplateSpecializationInfo *spec = MD->getTemplateSpecializationInfo()) { - LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments, F)); - if (F.ConsiderTemplateParameterTypes) - LV.merge(getLVForTemplateParameterList( - Spec->getTemplate()->getTemplateParameters())); + if (shouldConsiderTemplateLV(MD, spec)) { + LV.merge(getLVForTemplateArgumentList(*spec->TemplateArguments, F)); + if (F.ConsiderTemplateParameterTypes) + LV.merge(getLVForTemplateParameterList( + spec->getTemplate()->getTemplateParameters())); + } - TSK = Spec->getTemplateSpecializationKind(); + TSK = spec->getTemplateSpecializationKind(); } else if (MemberSpecializationInfo *MSI = MD->getMemberSpecializationInfo()) { TSK = MSI->getTemplateSpecializationKind(); @@ -561,14 +579,16 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { // *do* apply -fvisibility to method declarations. } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { - if (const ClassTemplateSpecializationDecl *Spec + if (const ClassTemplateSpecializationDecl *spec = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { - // Merge template argument/parameter information for member - // class template specializations. - LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs(), F)); + if (shouldConsiderTemplateLV(spec)) { + // Merge template argument/parameter information for member + // class template specializations. + LV.merge(getLVForTemplateArgumentList(spec->getTemplateArgs(), F)); if (F.ConsiderTemplateParameterTypes) LV.merge(getLVForTemplateParameterList( - Spec->getSpecializedTemplate()->getTemplateParameters())); + spec->getSpecializedTemplate()->getTemplateParameters())); + } } // Static data members. diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp index 7644e47ff7..fdccd46045 100644 --- a/test/CodeGenCXX/visibility.cpp +++ b/test/CodeGenCXX/visibility.cpp @@ -422,3 +422,35 @@ namespace test21 { // CHECK: define weak_odr void @_ZN6test211AILNS_2EnE0EE3fooEv( template void A<en>::foo(); } + +// rdar://problem/9616154 +// Visibility on explicit specializations should take precedence. +namespace test22 { + class A1 {}; + class A2 {}; + + template <class T> struct B {}; + template <> struct DEFAULT B<A1> { + static void foo(); + static void bar() {} + }; + template <> struct B<A2> { + static void foo(); + static void bar() {} + }; + + void test() { + B<A1>::foo(); + B<A1>::bar(); + B<A2>::foo(); + B<A2>::bar(); + } + // CHECK: declare void @_ZN6test221BINS_2A1EE3fooEv() + // CHECK: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv() + // CHECK: declare void @_ZN6test221BINS_2A2EE3fooEv() + // CHECK: define linkonce_odr void @_ZN6test221BINS_2A2EE3barEv() + // CHECK-HIDDEN: declare void @_ZN6test221BINS_2A1EE3fooEv() + // CHECK-HIDDEN: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv() + // CHECK-HIDDEN: declare void @_ZN6test221BINS_2A2EE3fooEv() + // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test221BINS_2A2EE3barEv() +} |