diff options
author | Larisse Voufo <lvoufo@google.com> | 2014-07-02 23:08:34 +0000 |
---|---|---|
committer | Larisse Voufo <lvoufo@google.com> | 2014-07-02 23:08:34 +0000 |
commit | 5899e19defe57fe5bd504bc20d254ba1a423b9a7 (patch) | |
tree | 0b82a794eadf3de81eea3085e02b64bfc28a112b /clang/lib/AST/Decl.cpp | |
parent | c67aa5403ca4b7a82bb671de7c6a86db2ff4140d (diff) | |
download | bcm5719-llvm-5899e19defe57fe5bd504bc20d254ba1a423b9a7.tar.gz bcm5719-llvm-5899e19defe57fe5bd504bc20d254ba1a423b9a7.zip |
Fix linkage bug that miscompiled variable templates instantiated from similarly named local types. In essence, this bug ensures that the x<Foo> specialization in function foo() defined as follows differs between two distinct translation units.
static int &foo() {
struct Foo { };
return x<Foo>;
}
llvm-svn: 212233
Diffstat (limited to 'clang/lib/AST/Decl.cpp')
-rw-r--r-- | clang/lib/AST/Decl.cpp | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index fdf94a8ad5e..7448de2ffbc 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -471,6 +471,58 @@ static void mergeTemplateLV(LinkageInfo &LV, LV.mergeExternalVisibility(argsLV); } +/// Should we consider visibility associated with the template +/// arguments and parameters of the given variable template +/// specialization? As usual, follow class template specialization +/// logic up to initialization. +static bool shouldConsiderTemplateVisibility( + const VarTemplateSpecializationDecl *spec, + LVComputationKind computation) { + // Include visibility from the template parameters and arguments + // only if this is not an explicit instantiation or specialization + // with direct explicit visibility (and note that implicit + // instantiations won't have a direct attribute). + if (!spec->isExplicitInstantiationOrSpecialization()) + return true; + + // An explicit variable specialization is an independent, top-level + // declaration. As such, if it has an explicit visibility attribute, + // that must directly express the user's intent, and we should honor + // it. + if (spec->isExplicitSpecialization() && + hasExplicitVisibilityAlready(computation)) + return false; + + return !hasDirectVisibilityAttribute(spec, computation); +} + +/// Merge in template-related linkage and visibility for the given +/// variable template specialization. As usual, follow class template +/// specialization logic up to initialization. +static void mergeTemplateLV(LinkageInfo &LV, + const VarTemplateSpecializationDecl *spec, + LVComputationKind computation) { + bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation); + + // Merge information from the template parameters, but ignore + // visibility if we're only considering template arguments. + + VarTemplateDecl *temp = spec->getSpecializedTemplate(); + LinkageInfo tempLV = + getLVForTemplateParameterList(temp->getTemplateParameters(), computation); + LV.mergeMaybeWithVisibility(tempLV, + considerVisibility && !hasExplicitVisibilityAlready(computation)); + + // Merge information from the template arguments. We ignore + // template-argument visibility if we've got an explicit + // instantiation with a visibility attribute. + const TemplateArgumentList &templateArgs = spec->getTemplateArgs(); + LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation); + if (considerVisibility) + LV.mergeVisibility(argsLV); + LV.mergeExternalVisibility(argsLV); +} + static bool useInlineVisibilityHidden(const NamedDecl *D) { // FIXME: we should warn if -fvisibility-inlines-hidden is used with c. const LangOptions &Opts = D->getASTContext().getLangOpts(); @@ -662,6 +714,14 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // C99 6.2.2p4 and propagating the visibility attribute, so we don't have // to do it here. + // As per function and class template specializations (below), + // consider LV for the template and template arguments. We're at file + // scope, so we do not need to worry about nested specializations. + if (const VarTemplateSpecializationDecl *spec + = dyn_cast<VarTemplateSpecializationDecl>(Var)) { + mergeTemplateLV(LV, spec, computation); + } + // - a function, unless it has internal linkage; or } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { // In theory, we can modify the function's LV by the LV of its @@ -869,6 +929,10 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, // Static data members. } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (const VarTemplateSpecializationDecl *spec + = dyn_cast<VarTemplateSpecializationDecl>(VD)) + mergeTemplateLV(LV, spec, computation); + // Modify the variable's linkage by its type, but ignore the // type's visibility unless it's a definition. LinkageInfo typeLV = getLVForType(*VD->getType(), computation); |