From: Rafael Espindola Date: Tue, 15 May 2012 14:09:55 +0000 (+0000) Subject: Fix our handling of visibility in explicit template instantiations. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=31c195ac0f3869e742d42f9d02b6cd33442fb630;p=clang Fix our handling of visibility in explicit template instantiations. * Don't copy the visibility attribute during instantiations. We have to be able to distinguish struct HIDDEN foo {}; template DEFAULT void bar() {} template DEFAULT void bar(); from struct HIDDEN foo {}; template DEFAULT void bar() {} template void bar(); * If an instantiation has an attribute, it takes precedence over an attribute in the template. * With instantiation attributes handled with the above logic, we can now select the minimum visibility when looking at template arguments. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156821 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 0b3b3cb33f..7d05b72a74 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -93,6 +93,9 @@ class Attr { list Namespaces = []; // 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. @@ -660,6 +663,7 @@ def VecTypeHint : Attr { } def Visibility : InheritableAttr { + let Clone = 0; let Spellings = ["visibility"]; let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 15fa790203..21405d223d 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -158,14 +158,12 @@ getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), OnlyTemplate); } -static bool shouldConsiderTemplateLV(const FunctionDecl *fn, - const FunctionTemplateSpecializationInfo *spec) { - return !(spec->isExplicitSpecialization() && - fn->hasAttr()); +static bool shouldConsiderTemplateLV(const FunctionDecl *fn) { + return !fn->hasAttr(); } static bool shouldConsiderTemplateLV(const ClassTemplateSpecializationDecl *d) { - return !(d->isExplicitSpecialization() && d->hasAttr()); + return !d->hasAttr(); } static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, @@ -376,7 +374,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // this is an explicit specialization with a visibility attribute. if (FunctionTemplateSpecializationInfo *specInfo = Function->getTemplateSpecializationInfo()) { - if (shouldConsiderTemplateLV(Function, specInfo)) { + if (shouldConsiderTemplateLV(Function)) { LV.merge(getLVForDecl(specInfo->getTemplate(), true)); const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments; @@ -407,8 +405,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // The arguments at which the template was instantiated. const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs(); - LV.merge(getLVForTemplateArgumentList(TemplateArgs, - OnlyTemplate)); + LV.mergeWithMin(getLVForTemplateArgumentList(TemplateArgs, + OnlyTemplate)); } } @@ -527,7 +525,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) { // the template parameters and arguments. if (FunctionTemplateSpecializationInfo *spec = MD->getTemplateSpecializationInfo()) { - if (shouldConsiderTemplateLV(MD, spec)) { + if (shouldConsiderTemplateLV(MD)) { LV.mergeWithMin(getLVForTemplateArgumentList(*spec->TemplateArguments, OnlyTemplate)); if (!OnlyTemplate) diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 51dffac59c..0182b3dcc4 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -102,7 +102,8 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, } else { Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context, *this, TemplateArgs); - New->addAttr(NewAttr); + if (NewAttr) + New->addAttr(NewAttr); } } } diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp index 2aa067886a..9de9265db2 100644 --- a/test/CodeGenCXX/visibility.cpp +++ b/test/CodeGenCXX/visibility.cpp @@ -712,3 +712,55 @@ namespace test36 { // CHECK: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test363fooINS_2S1ENS_2S2EE3barEv } + +namespace test37 { + struct HIDDEN foo { + }; + template + DEFAULT void bar() {} + template DEFAULT void bar(); + // CHECK: define weak_odr void @_ZN6test373barINS_3fooEEEvv + // CHECK-HIDDEN: define weak_odr void @_ZN6test373barINS_3fooEEEvv +} + +namespace test38 { + template + class DEFAULT foo { + void bar() {} + }; + struct HIDDEN zed { + }; + template class foo; + // CHECK: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv + // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test383fooINS_3zedEE3barEv +} + +namespace test39 { + class DEFAULT default_t; + class HIDDEN hidden_t; + template class A { + template class B { + HIDDEN void hidden() {} + void noattr() {} + template void temp() {} + }; + }; + template class DEFAULT A; + template class DEFAULT A::B; + template void A::B::temp(); + template void A::B::temp(); + + // CHECK: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv + // CHECK: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv + // CHECK: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv + + // GCC produces a default for this one. Why? + // CHECK: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv + + // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E6hiddenEv + // CHECK-HIDDEN: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E6noattrEv + // CHECK-HIDDEN: define weak_odr void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempINS_9default_tEEEvv + + // GCC produces a default for this one. Why? + // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test391AINS_8hidden_tEE1BIS1_E4tempIS1_EEvv +} diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 772fc2f526..8a8987720e 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -1004,6 +1004,14 @@ void ClangAttrTemplateInstantiateEmitter::run(raw_ostream &OS) { continue; OS << " case attr::" << R.getName() << ": {\n"; + bool ShouldClone = R.getValueAsBit("Clone"); + + if (!ShouldClone) { + OS << " return NULL;\n"; + OS << " }\n"; + continue; + } + OS << " const " << R.getName() << "Attr *A = cast<" << R.getName() << "Attr>(At);\n"; bool TDependent = R.getValueAsBit("TemplateDependent");