-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[Clang][Sema] Refactor collection of multi-level template argument lists #106585
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
[Clang][Sema] Refactor collection of multi-level template argument lists #106585
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
Awesome, thanks! I will give a review later, but just want to note a different (but much smaller) PR touching the same area: #102922 Just to keep in mind that the idea is to later further simplify |
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.
Thanks for working on the refactor! I did a cursory review, mostly on the getTemplateInstantiationArgs()
part, and the general approach looks plausible.
Re @mizvekov : this patch could supersede my refactoring work not only because of the reuse of the logic of "which next decl context to pick up for innermost arguments" and the reduction of the bool states, but my cwg2369 patch could also rely on it. So I like this patch. (Finally I don't have to rack my brain over the refactoring of it!)
Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) { | ||
if (Innermost) | ||
AddInnermostTemplateArguments(TTPD); |
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... it turns out we don't have to move to the parent semantic declaration of TTPD even if Innermost is present?
Note that we still want to traverse its parents in the previous implementation anyway.
Also, do you plan to fix #102320 in this or the follow-up patches? |
e227b7f
to
09093ca
Compare
clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp
Outdated
Show resolved
Hide resolved
5d5b40c
to
124d6d4
Compare
Ping @mizvekov |
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'll have to take another look at this when I get more time for it, but I'm glad this is getting further attention. I'd refactored this only a year or two ago (preivously it was a single really long function with a loop), so it is disappointing that we're needing to refactor it again already.
Collection of these arguments is unfortunately quite a task and ends up being a bit of trial/error, so hopefully the previous version ends up providing enough tests/etc to help inform this one.
That said, I'd vastly prefer this patch get split up into a few. The straight refactor + new visitor, plus it seems like there are a handful of similar/related refactors that are happening here too.
@@ -52,38 +52,6 @@ using namespace sema; | |||
//===----------------------------------------------------------------------===/ | |||
|
|||
namespace { | |||
namespace TemplateInstArgsHelpers { |
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.
Awe, I thought this was clever/useful :)
@erichkeane I could move the "early setting of |
Ping @erichkeane |
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.
Thanks for the ping, I'd forgotten about this one! I'm happy for the most part, I have 1 question and a couple nits.
SkipBodyInfo *SkipBody = nullptr); | ||
SourceLocation FriendLoc, | ||
ArrayRef<TemplateParameterList *> OuterTemplateParamLists, | ||
bool IsMemberSpecialization, SkipBodyInfo *SkipBody = 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.
I have a preference for using an enum instead of bool params (so that callers do: SpecializationKind::None
, or SpecializationKind::Member
or something like that?). Even if there are two options, it improves readability of callers a ton.
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 still have a preference for something like this, but otherwise
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.
1 comment, otherwise LGTM.
SkipBodyInfo *SkipBody = nullptr); | ||
SourceLocation FriendLoc, | ||
ArrayRef<TemplateParameterList *> OuterTemplateParamLists, | ||
bool IsMemberSpecialization, SkipBodyInfo *SkipBody = 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.
I still have a preference for something like this, but otherwise
…lists of class templates
…l when comparing variable templates
Reduced further to: template<int N>
struct A
{
template<typename T>
static constexpr bool f();
};
template<>
template<typename T>
constexpr bool A<0>::f()
{
return A<1>::f<T>(); // note: undefined function 'f<int>' cannot be used in a constant expression
}
template<>
template<typename T>
constexpr bool A<1>::f()
{
return true;
}
static_assert(A<0>::f<int>()); // error: static assertion expression is not an integral constant expression Also, if the first declaration of |
Another example using class templates: template<int N>
struct A
{
template<typename T>
struct B;
};
template<>
template<typename T>
struct A<0>::B : A<1>::B<T> { };
template<>
template<typename T>
struct A<1>::B
{
static constexpr bool x = true;
};
static_assert(A<0>::B<int>::x); // error: implicit instantiation of undefined template 'A<1>::B<int>' This currently results in a crash on trunk. With this patch applied, we instantiate the undefined class template declared in the definition of These differences in behavior arise from the fact that we bind names to the most recent redeclaration of an entity when creating IMO this behavior is correct per [temp.expl.spec] p7:
However, I would like to know what @erichkeane, @mizvekov, and @zygoloid think. In any case, the QT example can be fixed by reordering the explicit specialization such that each specialization is declared before being referenced. |
I agree I think with your take on temp.expl.spec, we run into this in quite a few places. I'd like to hear from the others, but this is a paragraph I've used in the past to justify a lot of this sort of diagnostics. |
Yep, I agree that the reduction indicates the original code was IFNDR. We need a new reduction with no rename in order to locate this on QT code base and know for sure. |
In @sdkrystian's latest example, does the use of My understanding is that the point of [temp.expl.spec]/7 is that an explicit specialization needs to be declared before the point where we'd otherwise consider implicitly instantiating a specialization from the primary template or a partial specialization, and in this example it seems to me that it is. |
@sdkrystian do you plan to reland this patch in some other form these days? I'm going to restart my cwg 2369 work on top of it. |
@zyn0217 I plan to reapply the patch after addressing the issues discussed above, but I have to get some more pressing work stuff done first :) |
…gument lists (#106585)" (#111173) Reapplies #106585, fixing an issue where non-dependent names of member templates appearing prior to that member template being explicitly specialized for an implicitly instantiated class template specialization would incorrectly use the definition of the explicitly specialized member template.
…plate argument lists (llvm#106585)" (llvm#111173)" This reverts commit 4da8ac3.
…gument lists (#106585, #111173)" (#111852) This patch reapplies #111173, fixing a bug when instantiating dependent expressions that name a member template that is later explicitly specialized for a class specialization that is implicitly instantiated. The bug is addressed by adding the `hasMemberSpecialization` function, which return `true` if _any_ redeclaration is a member specialization. This is then used when determining the instantiation pattern for a specialization of a template, and when collecting template arguments for a specialization of a template.
…plate argument lists (llvm#106585)" (llvm#111173)" (llvm#111766) This reverts commit 4da8ac3.
…gument lists (llvm#106585, llvm#111173)" (llvm#111852) This patch reapplies llvm#111173, fixing a bug when instantiating dependent expressions that name a member template that is later explicitly specialized for a class specialization that is implicitly instantiated. The bug is addressed by adding the `hasMemberSpecialization` function, which return `true` if _any_ redeclaration is a member specialization. This is then used when determining the instantiation pattern for a specialization of a template, and when collecting template arguments for a specialization of a template.
…plate argument lists (llvm#106585, llvm#111173)" (llvm#111852)" This reverts commit 2bb3d3a.
Currently, clang rejects the following explicit specialization of
f
due to the constraints not being equivalent:This happens because, in most cases, we do not set the flag indicating whether a
RedeclarableTemplate
is an explicit specialization of a member of an implicitly instantiated class template specialization until after we compare constraints for equivalence. This patch addresses the issue (and a number of other issues) by:Sema::getTemplateInstantiationArgs
so we collect the right set of template argument in all cases.Many of our declaration matching & constraint evaluation woes can be traced back to bugs in
Sema::getTemplateInstantiationArgs
. This change/refactor should fix a lot of them. It also paves the way for fixing #101330 and #105462 per my suggestion in #102267 (which I have implemented on top of this patch but will merge in a subsequent PR).