From b2d0c16e91f39def3646b71e5afebfaea262cca1 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Wed, 5 May 2021 08:55:02 -0700 Subject: [PATCH] [clang] p1099 using enum part 2 This implements the 'using enum maybe-qualified-enum-tag ;' part of 1099. It introduces a new 'UsingEnumDecl', subclassed from 'BaseUsingDecl'. Much of the diff is the boilerplate needed to get the new class set up. There is one case where we accept ill-formed, but I believe this is merely an extended case of an existing bug, so consider it orthogonal. AFAICT in class-scope the c++20 rule is that no 2 using decls can bring in the same target decl ([namespace.udecl]/8). But we already accept: struct A { enum { a }; }; struct B : A { using A::a; }; struct C : B { using A::a; using B::a; }; // same enumerator this patch permits mixtures of 'using enum Bob;' and 'using Bob::member;' in the same way. Differential Revision: https://reviews.llvm.org/D102241 --- clang-tools-extra/clangd/FindTarget.cpp | 3 + clang/include/clang/AST/ASTContext.h | 33 ++- clang/include/clang/AST/DeclCXX.h | 61 +++++- clang/include/clang/AST/JSONNodeDumper.h | 1 + clang/include/clang/AST/RecursiveASTVisitor.h | 2 + clang/include/clang/AST/TextNodeDumper.h | 1 + clang/include/clang/ASTMatchers/ASTMatchers.h | 14 +- clang/include/clang/Basic/DeclNodes.td | 1 + clang/include/clang/Basic/DiagnosticParseKinds.td | 6 + clang/include/clang/Basic/DiagnosticSemaKinds.td | 7 +- clang/include/clang/Index/IndexSymbol.h | 1 + clang/include/clang/Sema/Sema.h | 22 +- clang/include/clang/Sema/Template.h | 2 + clang/include/clang/Serialization/ASTBitCodes.h | 3 + clang/lib/AST/ASTContext.cpp | 15 ++ clang/lib/AST/ASTImporter.cpp | 58 ++++- clang/lib/AST/Decl.cpp | 1 + clang/lib/AST/DeclBase.cpp | 1 + clang/lib/AST/DeclCXX.cpp | 17 ++ clang/lib/AST/DeclPrinter.cpp | 5 + clang/lib/AST/JSONNodeDumper.cpp | 4 + clang/lib/AST/TextNodeDumper.cpp | 5 + clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 1 + clang/lib/ASTMatchers/Dynamic/Registry.cpp | 1 + clang/lib/CodeGen/CGDebugInfo.cpp | 11 + clang/lib/CodeGen/CGDebugInfo.h | 3 + clang/lib/CodeGen/CGDecl.cpp | 4 + clang/lib/CodeGen/CodeGenModule.cpp | 4 + clang/lib/Index/IndexSymbol.cpp | 7 + clang/lib/Parse/ParseDeclCXX.cpp | 45 +++- clang/lib/Sema/SemaCXXScopeSpec.cpp | 15 +- clang/lib/Sema/SemaCodeComplete.cpp | 3 + clang/lib/Sema/SemaDeclCXX.cpp | 141 +++++++++++-- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 114 ++++++---- clang/lib/Serialization/ASTCommon.cpp | 1 + clang/lib/Serialization/ASTReaderDecl.cpp | 15 ++ clang/lib/Serialization/ASTWriterDecl.cpp | 11 + clang/test/AST/ast-dump-using-enum.cpp | 30 +++ clang/test/SemaCXX/cxx20-using-enum.cpp | 233 +++++++++++++++++++++ clang/tools/libclang/CIndex.cpp | 1 + clang/unittests/AST/ASTImporterTest.cpp | 18 +- .../unittests/ASTMatchers/ASTMatchersNodeTest.cpp | 16 ++ 42 files changed, 838 insertions(+), 99 deletions(-) create mode 100644 clang/test/AST/ast-dump-using-enum.cpp create mode 100644 clang/test/SemaCXX/cxx20-using-enum.cpp diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index 9068fff..b68e5c6 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -181,6 +181,9 @@ public: for (const UsingShadowDecl *S : UD->shadows()) add(S->getUnderlyingDecl(), Flags); Flags |= Rel::Alias; // continue with the alias. + } else if (const UsingEnumDecl *UED = dyn_cast(D)) { + add(UED->getEnumDecl(), Flags); + Flags |= Rel::Alias; // continue with the alias. } else if (const auto *NAD = dyn_cast(D)) { add(NAD->getUnderlyingDecl(), Flags | Rel::Underlying); Flags |= Rel::Alias; // continue with the alias diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 22588a6..f103ec6 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -518,6 +518,17 @@ private: /// B to the UnresolvedUsingDecl in B. llvm::DenseMap InstantiatedFromUsingDecl; + /// Like InstantiatedFromUsingDecl, but for using-enum-declarations. Maps + /// from the instantiated using-enum to the templated decl from whence it + /// came. + /// Note that using-enum-declarations cannot be dependent and + /// thus will never be instantiated from an "unresolved" + /// version thereof (as with using-declarations), so each mapping is from + /// a (resolved) UsingEnumDecl to a (resolved) UsingEnumDecl. + llvm::DenseMap + InstantiatedFromUsingEnumDecl; + + /// Simlarly maps instantiated UsingShadowDecls to their origin. llvm::DenseMap InstantiatedFromUsingShadowDecl; @@ -886,30 +897,38 @@ public: MemberSpecializationInfo *getInstantiatedFromStaticDataMember( const VarDecl *Var); - TemplateOrSpecializationInfo - getTemplateOrSpecializationInfo(const VarDecl *Var); - /// Note that the static data member \p Inst is an instantiation of /// the static data member template \p Tmpl of a class template. void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation = SourceLocation()); + TemplateOrSpecializationInfo + getTemplateOrSpecializationInfo(const VarDecl *Var); + void setTemplateOrSpecializationInfo(VarDecl *Inst, TemplateOrSpecializationInfo TSI); - /// If the given using decl \p Inst is an instantiation of a - /// (possibly unresolved) using decl from a template instantiation, - /// return it. + /// If the given using decl \p Inst is an instantiation of + /// another (possibly unresolved) using decl, return it. NamedDecl *getInstantiatedFromUsingDecl(NamedDecl *Inst); /// Remember that the using decl \p Inst is an instantiation /// of the using decl \p Pattern of a class template. void setInstantiatedFromUsingDecl(NamedDecl *Inst, NamedDecl *Pattern); + /// If the given using-enum decl \p Inst is an instantiation of + /// another using-enum decl, return it. + UsingEnumDecl *getInstantiatedFromUsingEnumDecl(UsingEnumDecl *Inst); + + /// Remember that the using enum decl \p Inst is an instantiation + /// of the using enum decl \p Pattern of a class template. + void setInstantiatedFromUsingEnumDecl(UsingEnumDecl *Inst, + UsingEnumDecl *Pattern); + + UsingShadowDecl *getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst); void setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst, UsingShadowDecl *Pattern); - UsingShadowDecl *getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst); FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field); diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index c8095bb..e9f9da6 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -3366,7 +3366,7 @@ public: void removeShadowDecl(UsingShadowDecl *S); static bool classof(const Decl *D) { return classofKind(D->getKind()); } - static bool classofKind(Kind K) { return K == Using; } + static bool classofKind(Kind K) { return K == Using || K == UsingEnum; } }; /// Represents a C++ using-declaration. @@ -3568,6 +3568,65 @@ public: static bool classofKind(Kind K) { return K == ConstructorUsingShadow; } }; +/// Represents a C++ using-enum-declaration. +/// +/// For example: +/// \code +/// using enum SomeEnumTag ; +/// \endcode + +class UsingEnumDecl : public BaseUsingDecl, public Mergeable { + /// The source location of the 'using' keyword itself. + SourceLocation UsingLocation; + + /// Location of the 'enum' keyword. + SourceLocation EnumLocation; + + /// The enum + EnumDecl *Enum; + + UsingEnumDecl(DeclContext *DC, DeclarationName DN, SourceLocation UL, + SourceLocation EL, SourceLocation NL, EnumDecl *ED) + : BaseUsingDecl(UsingEnum, DC, NL, DN), UsingLocation(UL), + EnumLocation(EL), Enum(ED) {} + + void anchor() override; + +public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + + /// The source location of the 'using' keyword. + SourceLocation getUsingLoc() const { return UsingLocation; } + void setUsingLoc(SourceLocation L) { UsingLocation = L; } + + /// The source location of the 'enum' keyword. + SourceLocation getEnumLoc() const { return EnumLocation; } + void setEnumLoc(SourceLocation L) { EnumLocation = L; } + +public: + EnumDecl *getEnumDecl() const { return Enum; } + + static UsingEnumDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingL, SourceLocation EnumL, + SourceLocation NameL, EnumDecl *ED); + + static UsingEnumDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const override LLVM_READONLY; + + /// Retrieves the canonical declaration of this declaration. + UsingEnumDecl *getCanonicalDecl() override { + return cast(getFirstDecl()); + } + const UsingEnumDecl *getCanonicalDecl() const { + return cast(getFirstDecl()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == UsingEnum; } +}; + /// Represents a pack of using declarations that a single /// using-declarator pack-expanded into. /// diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h index a8b731a..1f35859 100644 --- a/clang/include/clang/AST/JSONNodeDumper.h +++ b/clang/include/clang/AST/JSONNodeDumper.h @@ -234,6 +234,7 @@ public: void VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD); void VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD); void VisitUsingDecl(const UsingDecl *UD); + void VisitUsingEnumDecl(const UsingEnumDecl *UED); void VisitUsingShadowDecl(const UsingShadowDecl *USD); void VisitVarDecl(const VarDecl *VD); void VisitFieldDecl(const FieldDecl *FD); diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index ab49b39..73d757f 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1593,6 +1593,8 @@ DEF_TRAVERSE_DECL(UsingDecl, { TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); }) +DEF_TRAVERSE_DECL(UsingEnumDecl, {}) + DEF_TRAVERSE_DECL(UsingPackDecl, {}) DEF_TRAVERSE_DECL(UsingDirectiveDecl, { diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index e3aa94d..4dc68d5 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -351,6 +351,7 @@ public: void VisitUsingDecl(const UsingDecl *D); void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D); void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D); + void VisitUsingEnumDecl(const UsingEnumDecl *D); void VisitUsingShadowDecl(const UsingShadowDecl *D); void VisitConstructorUsingShadowDecl(const ConstructorUsingShadowDecl *D); void VisitLinkageSpecDecl(const LinkageSpecDecl *D); diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index b3c4345..4db5629 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -1752,6 +1752,18 @@ extern const internal::VariadicDynCastAllOfMatcher usingDecl; +/// Matches using-enum declarations. +/// +/// Given +/// \code +/// namespace X { enum x {...}; } +/// using enum X::x; +/// \endcode +/// usingEnumDecl() +/// matches \code using enum X::x \endcode +extern const internal::VariadicDynCastAllOfMatcher + usingEnumDecl; + /// Matches using namespace declarations. /// /// Given @@ -6197,7 +6209,7 @@ AST_POLYMORPHIC_MATCHER_P( /// \endcode /// usingDecl(hasAnyUsingShadowDecl(hasName("b")))) /// matches \code using X::b \endcode -AST_MATCHER_P(UsingDecl, hasAnyUsingShadowDecl, +AST_MATCHER_P(BaseUsingDecl, hasAnyUsingShadowDecl, internal::Matcher, InnerMatcher) { return matchesFirstInPointerRange(InnerMatcher, Node.shadow_begin(), Node.shadow_end(), Finder, diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index ceaea52..f8ad6cf 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -73,6 +73,7 @@ def Named : DeclNode; def Concept : DeclNode