<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Apr 30, 2021, at 7:14 AM, Nathan Sidwell via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">hi, I've been working on p1099 (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1099r5.html" class="">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1099r5.html</a>)-- c++20's using-enum feature. Among other things it allows you to being the enumerators of a scoped enumeration into the local scope 'using enum maybe-qualified-tag-name ;' Brings the members of that enum in, as if by individual using declarations. I posted an initial patch seeking advice on a couple of issues as <a href="https://reviews.llvm.org/D101370" class="">https://reviews.llvm.org/D101370</a><br class=""><br class="">I chose to extend EnumDecl, rather than a new decl as we still need the shadow decl chain. The enum is parsed with ParseEnumSpecifier.<br class=""><br class="">Q1) I need to add the EnumDecl to the UsingDecl, and don't need the QualifiedLoc or DNLoc fields. Should I use a local union to overlay those pieces of data, or just live with the size expansion?<br class=""><br class=""></div></div></blockquote><div><br class=""></div><div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">My preference would be to have a separate UsingEnumDecl, and use the opportunity to factor out a common base to handle the shadow stuff, in a manner that would also provide a clearer interface for novice users. (`shadows()` etc. is a bit to abstruse for someone who just wants to quickly get the thing or things being "used.") </div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">IIUC a UsingDecl presently only ever has more than one shadow when it refers to an overloaded function. (And now, when it represents a using-enum-declaration with multiple enumerators).</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">So, a structure like this might be clearer:</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""> </div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">```</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class="">/// A base of both UsingDecl and UsingEnumDecl</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class="">class ShadowIntroducingDecl : public NamedDecl {</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> // All the shadow stuff from UsingDecl, e.g.:</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> llvm::PointerIntPair<UsingShadowDecl *, 1, bool> FirstUsingShadow;</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class="">public:</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> shadow_range shadows() const;</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> unsigned shadow_size() const;</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> //...</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class="">};</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class="">class UsingDecl : public ShadowIntroducingDecl, public Mergeable<UsingDecl> {</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> // ...</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> // DNLoc, QualifierLoc, anything else specific to UsingDecls.</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class="">public:</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> // --- Non-essential methods provided for clarity --- //</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> bool TargetIsFunction() const { </div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> return isa<FunctionDecl>(FirstUsingShadow.getPointer()->getTargetDecl());</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> }</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> NamedDecl *getTargetAsSingleDecl() { </div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> assert(!TargetIsFunction() && "use getTargetOverloads() instead"); </div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> assert(shadow_size() == 1);</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> return FirstUsingShadow.getPointer()->getTargetDecl(); </div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> }</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; min-height: 13px;" class=""> /// Same as shadow_iterator, but dereferences directly to the target FunctionDecls</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> struct function_overload_iterator : shadow_iterator {</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> FunctionDecl *operator*() const { return cast<FunctionDecl>(shadow_iterator::operator*()->getTargetDecl()); }</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> FunctionDecl *operator->() const //""</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> //...</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> };</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> using function_overload_range = llvm::iterator_range<function_overload_iterator>;</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> function_overload_range getTargetOverloads() const { </div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> assert(TargetIsFunction()); </div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> return static_cast<function_overload_range>(shadows()); //or whatever</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> }</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> unsigned getNumOverloads() const {</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> assert(TargetIsFunction());</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> return shadow_size();</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> }</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class="">};</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class="">class UsingEnumDecl : public ShadowIntroducingDecl, public Mergeable<UsingEnumDecl> {</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> //...</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class="">public:</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> EnumDecl *getNominatedEnum() const { </div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> return cast<EnumDecl>(FirstShadowDecl.getPointer()->getTargetDecl()->getDeclContext()); </div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> }</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> auto getTargetEnumerators() const { </div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> return getNominatedEnum()->decls();</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class=""> }</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo;" class="">};</div><div style="margin: 0px; font-stretch: normal; line-height: normal; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">```</div></div><br class=""><blockquote type="cite" class=""><div class=""><div class="">Q2) When the scoped enum is a template member, the members are instantiated when one looks inside the enum -- not when the enum decl is instantiated. That's done with RequireCompleteDeclContext, which is designed for when the parser is looking, and therefore takes a ScopeRef. This is a new situation where we don't have a ScopeRef, we have an EnumDecl, which we desire to complete. Is it best to break RequireCompleteDeclContext apart in some way so there's a new entry point for the new use?<br class=""><br class=""></div></div></blockquote><div><br class=""></div><div>To me it seems reasonable to separate out a `RequireCompleteEnumDecl(EnumDecl *D, CXXScopeSpec *SS = nullptr)` function that handles just the enum-specific stuff in there.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="">thanks,<br class=""><br class="">nathan<br class=""><br class="">-- <br class="">Nathan Sidwell<br class=""><br class=""></div></div></blockquote><br class=""></div><div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">One last thing while we’re on the general topic of UsingDecl, just in case you or anyone else wants to take this opportunity to clean it up more generally. There is presently no `UsingType` to provide the type sugar that a particular type was introduce via a UsingDecl. E.g.</div><div style="margin: 0px; font-stretch: normal; line-height: normal; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">```</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">struct A {</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""> struct Inner {};</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">};</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">struct B : A {</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""> using A::Inner;</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""> Inner i;</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">};</div><div style="margin: 0px; font-stretch: normal; line-height: normal; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">The type dump of `B::i` is</div><div style="margin: 0px; font-stretch: normal; line-height: normal; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><font face="Menlo" class="">RecordType 0x7fe32c80c2c0 'struct A::Inner'</font></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><font face="Menlo" class="">`-CXXRecord 0x7fe32c80c210 'Inner'</font></div><div style="margin: 0px; font-stretch: normal; line-height: normal; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">when I think it really should be something like</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><font face="Menlo" class="">UsingType *********** 'struct A::Inner' sugar</font></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><font face="Menlo" class="">`-RecordType 0x7fe32c80c2c0 'struct A::Inner'</font></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><font face="Menlo" class=""> `-CXXRecord 0x7fe32c80c210 'Inner'</font></div><div style="margin: 0px; font-stretch: normal; line-height: normal; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">I think this is may be the only case in the AST for which full source information about a type is not provided via sugar. And, a quick test suggests the UsingShadowDecl info is available during Lookup (i.e. we know if a particular lookup result is a UsingShadowDecl), so a UsingType would be straightforward to add.</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><br class=""></div></div><br class=""></body></html>