When we were looking at a template instantiation, that itself was a template instantiation
(say a templated member of a templated class), we weren't looking back far enough along
the chain of instantiations to find a VisibilityAttr (which we don't copy when instantiating
templates). This patch attempts to address that as well as adding a few test cases for these
situations.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
lib/AST/Decl.cpp | ||
---|---|---|
1098–1099 | typo "of a some" | |
lib/AST/DeclCXX.cpp | ||
1348–1354 | This loop structure is not very clear. How about: while (!CTD->isMemberSpecialization()) { auto *NewCTD = CTD->getInstantiatedFromMemberTemplate(); if (!NewCTD) break; CTD = NewCTD; } ... or while (auto *FromCTD = CTD->isMemberSpecialization() ? nullptr : CTD->getInstantiatedFromMemberTemplate()) CTD = FromCTD; |
Address review comment re loop structure. Reword comment that had a typo to both fix the typo and make the intent of the code more clear.
Hmm, the rebased version of this introduces new errors in test/Modules/cxx-templates.cpp. That test didn't exist when I wrote this code and I'm not familiar with templates. @rsmith could you take a look, error is:
error: 'error' diagnostics seen but not expected: File /data/keno/llvm/tools/clang/test/Modules/cxx-templates.cpp Line 202: definition of 'nested_cls_t' must be imported from module 'cxx_templates_common.unimported' before it is required File /data/keno/llvm/tools/clang/test/Modules/cxx-templates.cpp Line 202: definition of 'nested_cls_t' must be imported from module 'cxx_templates_common.unimported' before it is required
I just noticed that this patch fixes a template crash that I have a patch for at https://reviews.llvm.org/D25942. I will abandon my patch since this patch fixes the other issue. Would you mind adding the test case from my patch to this patch? It's available at https://reviews.llvm.org/differential/changeset/?ref=558279&whitespace=ignore-most .
FWIW, I also found this issue while working on my patch and decided to add expected-error 1+{{definition of}} verified check to that line ( https://reviews.llvm.org/differential/changeset/?ref=558280&whitespace=ignore-most). It seems that the preceding lines have this check as well, so I assumed that this diagnostic was expected and my patch fixed a bug that prevented this diagnostic from showing up.
Please factor out the fix for getTemplateInstantiationPattern and commit it separately. D25942 has a testcase for that portion of this change.
lib/AST/Decl.cpp | ||
---|---|---|
1057–1058 | This doesn't seem to match GCC; GCC seems to do this for all kinds of member specialization, not just for member class specialization: template<typename T> struct A { template<typename U> struct __attribute__((visibility("hidden"))) B; }; template<> template<typename U> struct A<int>::B { virtual void f() {} }; void g() { A<int>::B<int>().f(); } Here, A<int>::B<int> gets hidden visibility, even though it was instantiated from the member template specialization A<int>::B which had no visibility attribute. I don't know what the underlying logic is here -- does GCC look at the visibility on the enclosing class when computing visibility for a member class? -- but I don't think this one special case covers it. | |
1096–1097 | Likewise. | |
lib/AST/DeclCXX.cpp | ||
1349–1354 | The same bug exists in VarDecl::getTemplateInstantiationPattern; can you fix it there too? |
lib/AST/DeclCXX.cpp | ||
---|---|---|
1349–1354 | Do you have a test case that shows a problem with the current definition of that function? Would like to include it if possible. I tried cooking one up, but wasn't particularly successful. |
lib/AST/DeclCXX.cpp | ||
---|---|---|
1349–1354 | Since this is only currently used by the modules visibility code, you'd presumably need something like this: // submodule a.x template<typename T> struct A { template<typename U> static const int n; }; // submodule a.y import a.x template<typename T> template<typename U> const int A<T>::n = 1; // submodule a.z import a.x template<> template<typename U> const int A<int>::n = 2; // test import a.z // I expect this to fail because we would incorrectly check to see whether the definition from a.y is visible, because we never check whether the definition from a.z is a member specialization. static_assert(A<int>::n<int> == 2); |
I'm really out of my depth in this code, but it looks like that test case is triggering the one code path in that function that is actually correct. Could you adjust it to trigger the code path behind the first if statement?
This doesn't seem to match GCC; GCC seems to do this for all kinds of member specialization, not just for member class specialization:
Here, A<int>::B<int> gets hidden visibility, even though it was instantiated from the member template specialization A<int>::B which had no visibility attribute.
I don't know what the underlying logic is here -- does GCC look at the visibility on the enclosing class when computing visibility for a member class? -- but I don't think this one special case covers it.