-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[Clang] [C++26] Expansion Statements (Part 1: AST) #169680
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
base: main
Are you sure you want to change the base?
Changes from 2 commits
e5f2dd4
902410b
f812c54
ec6fde3
4415e4d
8a4a548
76330f9
66a2c59
8432c3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl, | |
| static bool classofKind(Kind K) { return K == TemplateParamObject; } | ||
| }; | ||
|
|
||
| /// Represents a C++26 expansion statement declaration. | ||
| /// | ||
| /// This is a bit of a hack, since expansion statements shouldn't really be | ||
| /// 'declarations' per se (they don't declare anything). Nevertheless, we *do* | ||
| /// need them to be declaration *contexts*, because the DeclContext is used to | ||
| /// compute the 'template depth' of entities enclosed therein. In particular, | ||
| /// the 'template depth' is used to find instantiations of parameter variables, | ||
| /// and a lambda enclosed within an expansion statement cannot compute its | ||
| /// template depth without a pointer to the enclosing expansion statement. | ||
| /// | ||
| /// For the remainder of this comment, let 'expanding' an expansion statement | ||
| /// refer to the process of performing template substitution on its body N | ||
| /// times, where N is the expansion size (how this size is determined depends on | ||
| /// the kind of expansion statement); by contrast we may sometimes 'instantiate' | ||
| /// an expansion statement (because it happens to be in a template). This is | ||
| /// just regular template instantiation. | ||
| /// | ||
| /// Apart from a template parameter list that contains a template parameter used | ||
| /// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as | ||
| /// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to | ||
| /// distinct representations of the expansion statement: the former is used | ||
| /// prior to expansion and contains all the parts needed to perform expansion; | ||
| /// the latter holds the expanded/desugared AST nodes that result from the | ||
Sirraide marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// expansion. | ||
| /// | ||
| /// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and left | ||
| /// as-is; this also means that, if an already-expanded expansion statement is | ||
| /// inside a template, and that template is then instantiated, the | ||
| /// 'CXXExpansionStmtPattern' is *not* instantiated; only the | ||
| /// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for | ||
| /// codegen and constant evaluation. | ||
| /// | ||
| /// For example, if the user writes the following expansion statement: | ||
| /// \verbatim | ||
| /// std::tuple<int, int, int> a{1, 2, 3}; | ||
| /// template for (auto x : a) { | ||
| /// // ... | ||
| /// } | ||
| /// \endverbatim | ||
| /// | ||
| /// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is a | ||
| /// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things, | ||
| /// the declaration of the variable 'x' as well as the expansion-initializer | ||
| /// 'a'. | ||
| /// | ||
| /// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, huh.... so it is ALL of the statements wrapped in a compound stmt... I rather wonder if we're better off NOT doing the compound statement and having code-gen just emit these scopes right. Are there any other advantages to the compound statement?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, so that is explained in more detail in the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I should update this comment to indicate that the outer compound statement is ‘not actually there’; I don’t remember why I didn’t explain that here (and perhaps some of the documentation needs to be deduplicated, and this section here should just say ‘see the comment on Alternatively, as you (or Corentin, I don’t remember?) suggested, I can move all of the expansion statement documentation into one big comment here, and then all the other nodes just have a comment that says ‘see
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the idea of having it all in 1 place, but would also like each node to have a quick summary of its participation too. I DO wonder if the 'big' comment has hit the "should be in the internals manual" though.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I’ll see if I can figure out a way to make that work
It is getting rather huge yeah... but at the same time, a large portion of the big comment(s) is just ‘this is how expansion statements work’, so not sure if that belongs in the internals manuall since those parts aren’t really Clang-specific
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, we SHOULD be putting more of that sorta stuff into the internals manual. These comments get lost/stale/tough to figure out WHERE they are when you need them. So I think it makes sense to be there.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I decided not to put everything in one place after all, but I’ve added a paragraph that explains the compount statement situation to both the decl and the instantiation stmt and overall added some more explanatory notes. Hopefully this makes everything a bit clearer. |
||
| /// contains a DecompositionDecl and 3 CompoundStmts, one for each expansion: | ||
| /// | ||
| /// \verbatim | ||
| /// { | ||
| /// auto [__u0, __u1, __u2] = a; | ||
| /// { | ||
| /// auto x = __u0; | ||
| /// // ... | ||
| /// } | ||
| /// { | ||
| /// auto x = __u1; | ||
| /// // ... | ||
| /// } | ||
| /// { | ||
| /// auto x = __u2; | ||
| /// // ... | ||
| /// } | ||
| /// } | ||
| /// \endverbatim | ||
| /// | ||
| /// The outer braces shown above are implicit; we don't actually create another | ||
Sirraide marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// CompoundStmt wrapping everything. | ||
| /// | ||
| /// \see CXXExpansionStmtPattern | ||
| /// \see CXXExpansionStmtInstantiation | ||
| class CXXExpansionStmtDecl : public Decl, public DeclContext { | ||
| CXXExpansionStmtPattern *Expansion = nullptr; | ||
| TemplateParameterList *TParams; | ||
| CXXExpansionStmtInstantiation *Instantiations = nullptr; | ||
|
|
||
| CXXExpansionStmtDecl(DeclContext *DC, SourceLocation Loc, | ||
| TemplateParameterList *TParams); | ||
|
|
||
| public: | ||
| friend class ASTDeclReader; | ||
|
|
||
| static CXXExpansionStmtDecl *Create(ASTContext &C, DeclContext *DC, | ||
| SourceLocation Loc, | ||
| TemplateParameterList *TParams); | ||
| static CXXExpansionStmtDecl *CreateDeserialized(ASTContext &C, | ||
| GlobalDeclID ID); | ||
|
|
||
| CXXExpansionStmtPattern *getExpansionPattern() { return Expansion; } | ||
| const CXXExpansionStmtPattern *getExpansionPattern() const { | ||
| return Expansion; | ||
| } | ||
| void setExpansionPattern(CXXExpansionStmtPattern *S) { Expansion = S; } | ||
|
|
||
| CXXExpansionStmtInstantiation *getInstantiations() { return Instantiations; } | ||
| const CXXExpansionStmtInstantiation *getInstantiations() const { | ||
| return Instantiations; | ||
| } | ||
|
|
||
| void setInstantiations(CXXExpansionStmtInstantiation *S) { | ||
| Instantiations = S; | ||
| } | ||
|
|
||
| NonTypeTemplateParmDecl *getIndexTemplateParm() const { | ||
| return cast<NonTypeTemplateParmDecl>(TParams->getParam(0)); | ||
| } | ||
| TemplateParameterList *getTemplateParameters() const { return TParams; } | ||
|
|
||
| SourceRange getSourceRange() const override LLVM_READONLY; | ||
|
|
||
| static bool classof(const Decl *D) { return classofKind(D->getKind()); } | ||
| static bool classofKind(Kind K) { return K == CXXExpansionStmt; } | ||
| }; | ||
|
|
||
| inline NamedDecl *getAsNamedDecl(TemplateParameter P) { | ||
| if (auto *PD = P.dyn_cast<TemplateTypeParmDecl *>()) | ||
| return PD; | ||
|
|
||
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.
What else does the list contain? And why a list instead of a single template parameter if that is the only thing in the list?
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 only contains one parameter; as to why we’re storing a template parameter list, er, the fork was using one, and I kind of assumed that we needed to have one because it feels a bit weird to have a template parameter just on its own, but if storing just the parameter works, then I’ll do that instead; I’ll take a look at that
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 was able to remove the template parameter list and only store the parameter instead