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<class T>
 DEFAULT void bar() {}
 template DEFAULT void bar<foo>();

from

 struct HIDDEN foo {};
 template<class T>
 DEFAULT void bar() {}
 template void bar<foo>();

* 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.

llvm-svn: 156821
This commit is contained in:
Rafael Espindola 2012-05-15 14:09:55 +00:00
parent ab5edc3e89
commit 7f90b7d4c2
5 changed files with 73 additions and 10 deletions

View File

@ -93,6 +93,9 @@ class Attr {
list<string> 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"],

View File

@ -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<VisibilityAttr>());
static bool shouldConsiderTemplateLV(const FunctionDecl *fn) {
return !fn->hasAttr<VisibilityAttr>();
}
static bool shouldConsiderTemplateLV(const ClassTemplateSpecializationDecl *d) {
return !(d->isExplicitSpecialization() && d->hasAttr<VisibilityAttr>());
return !d->hasAttr<VisibilityAttr>();
}
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)

View File

@ -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);
}
}
}

View File

@ -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<class T>
DEFAULT void bar() {}
template DEFAULT void bar<foo>();
// CHECK: define weak_odr void @_ZN6test373barINS_3fooEEEvv
// CHECK-HIDDEN: define weak_odr void @_ZN6test373barINS_3fooEEEvv
}
namespace test38 {
template<typename T>
class DEFAULT foo {
void bar() {}
};
struct HIDDEN zed {
};
template class foo<zed>;
// 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 T> class A {
template <class U> class B {
HIDDEN void hidden() {}
void noattr() {}
template <class V> void temp() {}
};
};
template class DEFAULT A<hidden_t>;
template class DEFAULT A<hidden_t>::B<hidden_t>;
template void A<hidden_t>::B<hidden_t>::temp<default_t>();
template void A<hidden_t>::B<hidden_t>::temp<hidden_t>();
// 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
}

View File

@ -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");