-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Fix out of line Concept-comparisons of NestedNameSpecifiers #65993
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
As reported in GH65810, we don't properly collect ALL of the template parameters in a nested name specifier, and were only doing the 'inner level'. This patch makes sure we collect from all levels. Fixes: llvm#65810
@llvm/pr-subscribers-clang ChangesAs reported in GH65810, we don't properly collect ALL of the template parameters in a nested name specifier, and were only doing the 'inner level'. This patch makes sure we collect from all levels. Fixes: #65810Full diff: https://github.com/llvm/llvm-project/pull/65993.diff 3 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index cc8b2c3808933cb..872c32f59da96ad 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -218,6 +218,9 @@ Bug Fixes in This Version (`#65156 `_`) - Clang no longer considers the loss of ``__unaligned`` qualifier from objects as an invalid conversion during method function overload resolution. +- Clang now properly handles out of line template specializations when there is + a non-template inner-class between the function and the class template + (`#65810 `_). Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 3b1731edec95237..832837556601663 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -231,14 +231,18 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD, MultiLevelTemplateArgumentList &Result) { if (!isa(FTD->getDeclContext())) { NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier(); - const Type *Ty; - const TemplateSpecializationType *TSTy; - if (NNS && (Ty = NNS->getAsType()) && - (TSTy = Ty->getAs())) - Result.addOuterTemplateArguments(const_cast(FTD), - TSTy->template_arguments(), - /*Final=*/false); + + while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) { + + if (const auto *TSTy = Ty->getAs()) + Result.addOuterTemplateArguments( + const_cast(FTD), TSTy->template_arguments(), + /*Final=*/false); + + NNS = NNS->getPrefix(); + } } + return Response::ChangeDecl(FTD->getLexicalDeclContext()); } diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp index 4688c28b489307f..f067c02ca48f584 100644 --- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp +++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp @@ -418,3 +418,51 @@ template concept A = true; template struct X { A auto f(); }; template A auto X::f() {} } + +namespace GH65810 { +template +concept TrivialConcept = +requires(Param param) { + (void)param; +}; + +template +struct Base { + class InnerClass; +}; + +template +class Base::InnerClass { + template + requires TrivialConcept + int func(Param param) const; +}; + +template +template +requires TrivialConcept +int Base::InnerClass::func(Param param) const { + return 0; +} + +template +struct Outermost { + struct Middle { + template + struct Innermost { + template + requires TrivialConcept + int func(Param param) const; + }; + }; +}; + +template +template +template +requires TrivialConcept +int Outermost::Middle::Innermost::func(Param param) const { + return 0; +} + +} // namespace GH65810 |
TSTy->template_arguments(), | ||
/*Final=*/false); | ||
|
||
while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This make sense, I was just looking at the AST: https://godbolt.org/z/P3brjcsMG
and I see that InnerClass
has:
| |-NestedNameSpecifier TypeSpec 'Base<T>'
and I wondering what the prefix is there? Maybe the AST is not telling the whole story?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that one you're seeing there is for the InnerClass
on line 13, the NestedNameSpecifier
is for 'everything else' outside of that declaration. So in THAT case, the Prefix of that one is nothing, since the Base<T>
is the entirety of the thing.
However, that AST doesn't show the NNS
of func
on line 22, for some reason we're not dumping that. In THAT case, the NNS
is Base<T>::InnerClass
. At that point, the InnerClass
doesn't have template arguments (since it isn't a template!), but its Prefix
is just the Base<T>
, which has them (which is why/how this loop works).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not look like there is a simple way of getting like w/ CXXRecordDecl
so some work would be involved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what you mean? TagDecl
(IIRC?) has a getQualifier()
to get the appropriate NestedNameSpecifier
. I believe our NNS tree is correct the way I've implemented it above, with the exception of the issue I posted about a moment ago.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I just realized I was looking at the code a moment ago FTD->getTemplatedDecl()->getQualifier()
Huh, blarg, build-bot found an issue with my patch, curiously in the same file I was editing! I'll look into it. I at least reproduce it, which is nice... |
So the latest patch doesn't FIX it, it has a problem with:
The problem/special case here is the I don't have a feeling of how to get those, I thought the At the moment, I'm done with this for at least the night, so if someone else wants to take a look, they are encouraged to share their' findings. |
Alright, I think I got it this time, we'll see how the buildbots treat it, but it passes locally for me. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You obviously have a better grasp of that part of the code than I do, but the patch looks sensible to me. Thanks!
Downstream, this is causing a funny build error in c++20 mode:
It doesn't seem to fail on the public libcxx buildbots, so I'm not sure what's different about our setup that triggers this failure. (cc @ilya-biryukov) |
I couldn't reproduce the error with module-enabled builds of libc++ either, but internally we are building the libc++ module from a generated module map file (and different) rather than the one distributed with libc++. It seems that Clang has an actual bug with C++20 modules exposing the same problem: #66255. It seems that it's been there for a long time. I believe the patch somehow exposes it. @erichkeane maybe this looks familiar? |
This doesn't, I was really hoping it did for you :) This is a really strange one, it almost seems like it doesnt' realize it is IN the header or something? |
As reported in GH65810, we don't properly collect ALL of the template parameters in a nested name specifier, and were only doing the 'inner level'. This patch makes sure we collect from all levels. Fixes: llvm#65810
As reported in GH65810, we don't properly collect ALL of the template parameters in a nested name specifier, and were only doing the 'inner level'.
This patch makes sure we collect from all levels.
Fixes: #65810