urnathan updated this revision to Diff 347405. urnathan added a comment. Address davrec's comments
CHANGES SINCE LAST ACTION https://reviews.llvm.org/D102241/new/ https://reviews.llvm.org/D102241 Files: clang-tools-extra/clangd/FindTarget.cpp clang/include/clang/AST/ASTContext.h clang/include/clang/AST/DeclCXX.h clang/include/clang/AST/JSONNodeDumper.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/AST/TextNodeDumper.h clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/Basic/DeclNodes.td clang/include/clang/Basic/DiagnosticParseKinds.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Index/IndexSymbol.h clang/include/clang/Sema/Sema.h clang/include/clang/Sema/Template.h clang/include/clang/Serialization/ASTBitCodes.h clang/lib/AST/ASTContext.cpp clang/lib/AST/ASTImporter.cpp clang/lib/AST/Decl.cpp clang/lib/AST/DeclBase.cpp clang/lib/AST/DeclCXX.cpp clang/lib/AST/DeclPrinter.cpp clang/lib/AST/JSONNodeDumper.cpp clang/lib/AST/TextNodeDumper.cpp clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/lib/CodeGen/CGDebugInfo.cpp clang/lib/CodeGen/CGDebugInfo.h clang/lib/CodeGen/CGDecl.cpp clang/lib/CodeGen/CodeGenModule.cpp clang/lib/Index/IndexSymbol.cpp clang/lib/Parse/ParseDeclCXX.cpp clang/lib/Sema/SemaCXXScopeSpec.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/lib/Serialization/ASTCommon.cpp clang/lib/Serialization/ASTReaderDecl.cpp clang/lib/Serialization/ASTWriterDecl.cpp clang/test/AST/ast-dump-using-enum.cpp clang/test/SemaCXX/cxx20-using-enum.cpp clang/tools/libclang/CIndex.cpp clang/unittests/AST/ASTImporterTest.cpp clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -1428,6 +1428,22 @@ usingDecl(hasAnyUsingShadowDecl(hasName("a"))))); } +TEST_P(ASTMatchersTest, UsingEnumDecl_MatchesUsingEnumDeclarations) { + if (!GetParam().isCXX20OrLater()) { + return; + } + EXPECT_TRUE( + matches("namespace X { enum x {}; } using enum X::x;", usingEnumDecl())); +} + +TEST_P(ASTMatchersTest, UsingEnumDecl_MatchesShadowUsingDeclarations) { + if (!GetParam().isCXX20OrLater()) { + return; + } + EXPECT_TRUE(matches("namespace f { enum a {b}; } using enum f::a;", + usingEnumDecl(hasAnyUsingShadowDecl(hasName("b"))))); +} + TEST_P(ASTMatchersTest, UsingDirectiveDecl_MatchesUsingNamespace) { if (!GetParam().isCXX()) { return; Index: clang/unittests/AST/ASTImporterTest.cpp =================================================================== --- clang/unittests/AST/ASTImporterTest.cpp +++ clang/unittests/AST/ASTImporterTest.cpp @@ -844,7 +844,15 @@ testImport("namespace foo { int bar; }" "void declToImport() { using foo::bar; }", Lang_CXX03, "", Lang_CXX03, Verifier, - functionDecl(hasDescendant(usingDecl()))); + functionDecl(hasDescendant(usingDecl(hasName("bar"))))); +} + +TEST_P(ImportDecl, ImportUsingEnumDecl) { + MatchVerifier<Decl> Verifier; + testImport("namespace foo { enum bar { baz, toto, quux }; }" + "void declToImport() { using enum foo::bar; }", + Lang_CXX20, "", Lang_CXX20, Verifier, + functionDecl(hasDescendant(usingEnumDecl(hasName("bar"))))); } /// \brief Matches shadow declarations introduced into a scope by a @@ -862,10 +870,16 @@ TEST_P(ImportDecl, ImportUsingShadowDecl) { MatchVerifier<Decl> Verifier; + // from using-decl testImport("namespace foo { int bar; }" "namespace declToImport { using foo::bar; }", Lang_CXX03, "", Lang_CXX03, Verifier, - namespaceDecl(has(usingShadowDecl()))); + namespaceDecl(has(usingShadowDecl(hasName("bar"))))); + // from using-enum-decl + testImport("namespace foo { enum bar {baz, toto, quux }; }" + "namespace declToImport { using enum foo::bar; }", + Lang_CXX20, "", Lang_CXX20, Verifier, + namespaceDecl(has(usingShadowDecl(hasName("baz"))))); } TEST_P(ImportExpr, ImportUnresolvedLookupExpr) { Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -6540,6 +6540,7 @@ } case Decl::Using: + case Decl::UsingEnum: return MakeCursorOverloadedDeclRef(cast<BaseUsingDecl>(D), D->getLocation(), TU); Index: clang/test/SemaCXX/cxx20-using-enum.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/cxx20-using-enum.cpp @@ -0,0 +1,233 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s + +// p1099 'using enum ELABORATED-ENUM-SPECIFIER ;' + +namespace One { +namespace Bob { +enum A { a, // expected-note{{declared here}} + b, + c }; +class C; // expected-note{{previous use}} +enum class D : int; +enum class D { d, + e, + f }; +enum class D : int; +} // namespace Bob + +using enum Bob::A; +#if __cplusplus < 202002 +// expected-warning@-2{{is a C++20 extension}} +#endif +using enum Bob::B; // expected-error{{no enum named 'B'}} +#if __cplusplus < 202002 +// expected-warning@-2{{is a C++20 extension}} +#endif +using enum Bob::C; // expected-error{{tag type that does not match}} +#if __cplusplus < 202002 +// expected-warning@-2{{is a C++20 extension}} +#endif +auto v = a; + +A g; // expected-error{{unknown type name 'A'}} + +int A; + +using enum Bob::D; +#if __cplusplus < 202002 +// expected-warning@-2{{is a C++20 extension}} +#endif +} // namespace One + +namespace Two { +namespace Kevin { +enum class B { d, + e, + f }; +} + +using enum Kevin::B; +#if __cplusplus < 202002 +// expected-warning@-2{{is a C++20 extension}} +#endif +auto w = e; + +} // namespace Two + +#if __cplusplus >= 202002 +// Now only check c++20 onwards + +namespace Three { +namespace Stuart { +enum class C : int; // expected-note{{declared here}} +} + +using enum Stuart::C; // expected-error{{is incomplete}} +} // namespace Three + +namespace Four { +class Dave { +public: + enum D { a, + b, + c }; + +private: + enum class E { d, // expected-note{{declared private here}} + e, + f }; +}; + +using enum Dave::D; +using enum Dave::E; // expected-error{{is a private member}} + +} // namespace Four + +namespace Five { +enum class A { b, + c }; +class Dave { +public: + using enum A; + A f = b; +}; + +} // namespace Five + +namespace Six { +template <typename T> class TPL; +template <> class TPL<int> { +public: + enum A { a }; +}; + +template <typename T> class USR { + using enum TPL<T>::B; // expected-error{{cannot name a dependent type}} + using enum TPL<int>::A; +}; +} // namespace Six + +// Now instantiate things +namespace Seven { +namespace Stuart { +enum class A { a, + b, + c }; +} + +static_assert(!int(Stuart::A::a)); +constexpr int Bar() { + using enum Stuart::A; + return int(b); +} +static_assert(Bar() == 1); + +template <int I> constexpr int Foo() { + using enum Stuart::A; + return int(b) + I; +} + +static_assert(Foo<10>() == 11); + +template <int I> struct C { + using enum Stuart::A; + static constexpr int V = int(c) + I; + + enum class D { d, + e, + f }; + using enum D; + + static constexpr int W = int(f) + I; +}; + +static_assert(C<2>::V == 4); +static_assert(C<20>::W == 22); + +} // namespace Seven + +namespace Eight { +enum class Bob : int {}; +using enum Bob; +} // namespace Eight + +namespace Nine { +template <int I> struct C { + enum class D { i = I }; + enum class E : int; // expected-note{{declared here}} +}; + +using enum C<2>::D; + +constexpr auto d = i; +static_assert(unsigned(d) == 2); + +using enum C<2>::E; // expected-error{{instantiation of undefined member}} +} // namespace Nine + +namespace Ten { +enum class Bob { a }; + +void Foo() { + extern void a(); +} + +// We don't see the hidden extern a fn! +using enum Bob; + +auto v = a; +} // namespace Ten + +namespace Eleven { +enum class Bob { a }; // expected-note{{conflicting declaration}} + +struct Base { + enum { a }; // expected-note{{target of using}} +}; + +template <typename B> +class TPLa : B { + using enum Bob; + using B::a; // expected-error{{target of using declaration}} +}; + +TPLa<Base> a; // expected-note{{in instantiation}} + +} // namespace Eleven + +namespace Twelve { +enum class Bob { a }; // expected-note{{target of using}} + +struct Base { + enum { a }; +}; + +template <typename B> +class TPLb : B { + using B::a; // expected-note{{conflicting declaration}} + using enum Bob; // expected-error{{target of using declaration}} +}; + +TPLb<Base> b; + +} // namespace Twelve + +namespace Thirteen { +enum class Bob { a }; +class Foo { + using enum Bob; // expected-note{{previous using-enum}} + using enum Bob; // expected-error{{redeclaration of using-enum}} +}; + +template <typename B> +class TPLa { + using enum Bob; // expected-note{{previous using-enum}} + using enum Bob; // expected-error{{redeclaration of using-enum}} +}; + +TPLa<int> a; + +} // namespace Thirteen + +#endif Index: clang/test/AST/ast-dump-using-enum.cpp =================================================================== --- /dev/null +++ clang/test/AST/ast-dump-using-enum.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++20 -ast-dump -ast-dump-filter Foo %s | FileCheck -strict-whitespace %s + +// Test with serialization: +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown -emit-pch -o %t %s +// RUN: %clang_cc1 -x c++ -std=c++20 -triple x86_64-unknown-unknown -include-pch %t \ +// RUN: -ast-dump-all -ast-dump-filter Foo /dev/null \ +// RUN: | FileCheck --strict-whitespace %s + +namespace Bob { +enum class Foo { + Foo_a, + Foo_b +}; +}; // namespace Bob + +using enum Bob::Foo; + +// CHECK-LABEL: Dumping Bob::Foo +// CHECK-NEXT: EnumDecl {{.*}} class Foo 'int' +// CHECK-NEXT: |-EnumConstantDecl {{.*}} Foo_a 'Bob::Foo' +// CHECK-NEXT: `-EnumConstantDecl {{.*}} Foo_b 'Bob::Foo' + +// CHECK-LABEL: Dumping Foo: +// CHECK-NEXT: UsingEnumDecl {{.*}} Enum {{.*}} 'Foo' + +// CHECK-LABEL: Dumping Foo_a: +// CHECK-NEXT: UsingShadowDecl {{.*}} implicit EnumConstant {{.*}} 'Foo_a' 'Bob::Foo' + +// CHECK-LABEL: Dumping Foo_b: +// CHECK-NEXT: UsingShadowDecl {{.*}} implicit EnumConstant {{.*}} 'Foo_b' 'Bob::Foo' Index: clang/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- clang/lib/Serialization/ASTWriterDecl.cpp +++ clang/lib/Serialization/ASTWriterDecl.cpp @@ -113,6 +113,7 @@ void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); void VisitUsingDecl(UsingDecl *D); + void VisitUsingEnumDecl(UsingEnumDecl *D); void VisitUsingPackDecl(UsingPackDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D); @@ -1277,6 +1278,16 @@ Code = serialization::DECL_USING; } +void ASTDeclWriter::VisitUsingEnumDecl(UsingEnumDecl *D) { + VisitNamedDecl(D); + Record.AddSourceLocation(D->getUsingLoc()); + Record.AddSourceLocation(D->getEnumLoc()); + Record.AddDeclRef(D->getEnumDecl()); + Record.AddDeclRef(D->FirstUsingShadow.getPointer()); + Record.AddDeclRef(Context.getInstantiatedFromUsingEnumDecl(D)); + Code = serialization::DECL_USING_ENUM; +} + void ASTDeclWriter::VisitUsingPackDecl(UsingPackDecl *D) { Record.push_back(D->NumExpansions); VisitNamedDecl(D); Index: clang/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- clang/lib/Serialization/ASTReaderDecl.cpp +++ clang/lib/Serialization/ASTReaderDecl.cpp @@ -389,6 +389,7 @@ void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); void VisitUsingDecl(UsingDecl *D); + void VisitUsingEnumDecl(UsingEnumDecl *D); void VisitUsingPackDecl(UsingPackDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitConstructorUsingShadowDecl(ConstructorUsingShadowDecl *D); @@ -1651,6 +1652,17 @@ mergeMergeable(D); } +void ASTDeclReader::VisitUsingEnumDecl(UsingEnumDecl *D) { + VisitNamedDecl(D); + D->setUsingLoc(readSourceLocation()); + D->setEnumLoc(readSourceLocation()); + D->Enum = readDeclAs<EnumDecl>(); + D->FirstUsingShadow.setPointer(readDeclAs<UsingShadowDecl>()); + if (auto *Pattern = readDeclAs<UsingEnumDecl>()) + Reader.getContext().setInstantiatedFromUsingEnumDecl(D, Pattern); + mergeMergeable(D); +} + void ASTDeclReader::VisitUsingPackDecl(UsingPackDecl *D) { VisitNamedDecl(D); D->InstantiatedFrom = readDeclAs<NamedDecl>(); @@ -3838,6 +3850,9 @@ case DECL_USING_SHADOW: D = UsingShadowDecl::CreateDeserialized(Context, ID); break; + case DECL_USING_ENUM: + D = UsingEnumDecl::CreateDeserialized(Context, ID); + break; case DECL_CONSTRUCTOR_USING_SHADOW: D = ConstructorUsingShadowDecl::CreateDeserialized(Context, ID); break; Index: clang/lib/Serialization/ASTCommon.cpp =================================================================== --- clang/lib/Serialization/ASTCommon.cpp +++ clang/lib/Serialization/ASTCommon.cpp @@ -394,6 +394,7 @@ case Decl::NonTypeTemplateParm: case Decl::TemplateTemplateParm: case Decl::Using: + case Decl::UsingEnum: case Decl::UsingPack: case Decl::ObjCMethod: case Decl::ObjCCategory: Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2979,6 +2979,47 @@ return Inst; } +Decl *TemplateDeclInstantiator::VisitBaseUsingDecls(BaseUsingDecl *D, + BaseUsingDecl *Inst, + LookupResult *Lookup) { + + bool isFunctionScope = Owner->isFunctionOrMethod(); + + for (auto *Shadow : D->shadows()) { + // FIXME: UsingShadowDecl doesn't preserve its immediate target, so + // reconstruct it in the case where it matters. Hm, can we extract it from + // the DeclSpec when parsing and save it in the UsingDecl itself? + NamedDecl *OldTarget = Shadow->getTargetDecl(); + if (auto *CUSD = dyn_cast<ConstructorUsingShadowDecl>(Shadow)) + if (auto *BaseShadow = CUSD->getNominatedBaseClassShadowDecl()) + OldTarget = BaseShadow; + + NamedDecl *InstTarget = + cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl( + Shadow->getLocation(), OldTarget, TemplateArgs)); + if (!InstTarget) + return nullptr; + + UsingShadowDecl *PrevDecl = nullptr; + if (Lookup && + SemaRef.CheckUsingShadowDecl(Inst, InstTarget, *Lookup, PrevDecl)) + continue; + + if (UsingShadowDecl *OldPrev = getPreviousDeclForInstantiation(Shadow)) + PrevDecl = cast_or_null<UsingShadowDecl>(SemaRef.FindInstantiatedDecl( + Shadow->getLocation(), OldPrev, TemplateArgs)); + + UsingShadowDecl *InstShadow = SemaRef.BuildUsingShadowDecl( + /*Scope*/ nullptr, Inst, InstTarget, PrevDecl); + SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow); + + if (isFunctionScope) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(Shadow, InstShadow); + } + + return Inst; +} + Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { // The nested name specifier may be dependent, for example @@ -3004,11 +3045,9 @@ NameInfo.setName(SemaRef.Context.DeclarationNames.getCXXConstructorName( SemaRef.Context.getCanonicalType(SemaRef.Context.getRecordType(RD)))); - // We only need to do redeclaration lookups if we're in a class - // scope (in fact, it's not really even possible in non-class - // scopes). + // We only need to do redeclaration lookups if we're in a class scope (in + // fact, it's not really even possible in non-class scopes). bool CheckRedeclaration = Owner->isRecord(); - LookupResult Prev(SemaRef, NameInfo, Sema::LookupUsingDeclName, Sema::ForVisibleRedeclaration); @@ -3029,13 +3068,13 @@ D->hasTypename(), SS, D->getLocation(), Prev)) NewUD->setInvalidDecl(); - } if (!NewUD->isInvalidDecl() && SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), D->hasTypename(), SS, NameInfo, D->getLocation(), nullptr, D)) NewUD->setInvalidDecl(); + SemaRef.Context.setInstantiatedFromUsingDecl(NewUD, D); NewUD->setAccess(D->getAccess()); Owner->addDecl(NewUD); @@ -3049,43 +3088,34 @@ if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) SemaRef.CheckInheritingConstructorUsingDecl(NewUD); - bool isFunctionScope = Owner->isFunctionOrMethod(); + return VisitBaseUsingDecls(D, NewUD, CheckRedeclaration ? &Prev : nullptr); +} - // Process the shadow decls. - for (auto *Shadow : D->shadows()) { - // FIXME: UsingShadowDecl doesn't preserve its immediate target, so - // reconstruct it in the case where it matters. - NamedDecl *OldTarget = Shadow->getTargetDecl(); - if (auto *CUSD = dyn_cast<ConstructorUsingShadowDecl>(Shadow)) - if (auto *BaseShadow = CUSD->getNominatedBaseClassShadowDecl()) - OldTarget = BaseShadow; +Decl *TemplateDeclInstantiator::VisitUsingEnumDecl(UsingEnumDecl *D) { + // Cannot be a dependent type, but still could be an instantiation + EnumDecl *EnumD = cast_or_null<EnumDecl>(SemaRef.FindInstantiatedDecl( + D->getLocation(), D->getEnumDecl(), TemplateArgs)); - NamedDecl *InstTarget = - cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl( - Shadow->getLocation(), OldTarget, TemplateArgs)); - if (!InstTarget) - return nullptr; + if (SemaRef.RequireCompleteEnumDecl(EnumD, EnumD->getLocation())) + return nullptr; - UsingShadowDecl *PrevDecl = nullptr; - if (CheckRedeclaration) { - if (SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev, PrevDecl)) - continue; - } else if (UsingShadowDecl *OldPrev = - getPreviousDeclForInstantiation(Shadow)) { - PrevDecl = cast_or_null<UsingShadowDecl>(SemaRef.FindInstantiatedDecl( - Shadow->getLocation(), OldPrev, TemplateArgs)); - } + UsingEnumDecl *NewUD = + UsingEnumDecl::Create(SemaRef.Context, Owner, D->getUsingLoc(), + D->getEnumLoc(), D->getLocation(), EnumD); - UsingShadowDecl *InstShadow = - SemaRef.BuildUsingShadowDecl(/*Scope*/nullptr, NewUD, InstTarget, - PrevDecl); - SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow); + SemaRef.Context.setInstantiatedFromUsingEnumDecl(NewUD, D); + NewUD->setAccess(D->getAccess()); + Owner->addDecl(NewUD); - if (isFunctionScope) - SemaRef.CurrentInstantiationScope->InstantiatedLocal(Shadow, InstShadow); - } + // Don't process the shadow decls for an invalid decl. + if (NewUD->isInvalidDecl()) + return NewUD; + + // We don't have to recheck for duplication of the UsingEnumDecl itself, as it + // cannot be dependent, and will therefore have been checked during template + // definition. - return NewUD; + return VisitBaseUsingDecls(D, NewUD, nullptr); } Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) { Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -1835,9 +1835,11 @@ case Decl::UsingDirective: case Decl::UnresolvedUsingTypename: case Decl::UnresolvedUsingValue: + case Decl::UsingEnum: // - static_assert-declarations // - using-declarations, // - using-directives, + // - using-enum-declaration continue; case Decl::Typedef: @@ -11607,7 +11609,40 @@ NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, TypenameLoc.isValid(), TypenameLoc, SS, TargetNameInfo, EllipsisLoc, AttrList, - /*IsInstantiation*/false); + /*IsInstantiation*/ false); + if (UD) + PushOnScopeChains(UD, S, /*AddToContext*/ false); + + return UD; +} + +Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS, + SourceLocation UsingLoc, + SourceLocation EnumLoc, + const DeclSpec &DS) { + switch (DS.getTypeSpecType()) { + case DeclSpec::TST_error: + // This will already have been diagnosed + return nullptr; + + case DeclSpec::TST_enum: + break; + + case DeclSpec::TST_typename: + Diag(DS.getTypeSpecTypeLoc(), diag::err_using_enum_is_dependent); + return nullptr; + + default: + llvm_unreachable("unexpected DeclSpec type"); + } + + // As with enum-decls, we ignore attributes for now. + auto *Enum = cast<EnumDecl>(DS.getRepAsDecl()); + if (auto *Def = Enum->getDefinition()) + Enum = Def; + + auto *UD = BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, + DS.getTypeSpecTypeNameLoc(), Enum); if (UD) PushOnScopeChains(UD, S, /*AddToContext*/ false); @@ -11705,7 +11740,7 @@ // We can have UsingDecls in our Previous results because we use the same // LookupResult for checking whether the UsingDecl itself is a valid // redeclaration. - if (isa<UsingDecl>(D) || isa<UsingPackDecl>(D)) + if (isa<UsingDecl>(D) || isa<UsingPackDecl>(D) || isa<UsingEnumDecl>(D)) continue; if (auto *RD = dyn_cast<CXXRecordDecl>(D)) { @@ -11993,6 +12028,29 @@ }; } // end anonymous namespace +/// Remove decls we can't actually see from a lookup being used to declare +/// shadow using decls. +/// +/// \param S - The scope of the potential shadow decl +/// \param Previous - The lookup of a potential shadow decl's name. +void Sema::FilterUsingLookup(Scope *S, LookupResult &Previous) { + // It is really dumb that we have to do this. + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (!isDeclInScope(D, CurContext, S)) + F.erase(); + // If we found a local extern declaration that's not ordinarily visible, + // and this declaration is being added to a non-block scope, ignore it. + // We're only checking for scope conflicts here, not also for violations + // of the linkage rules. + else if (!CurContext->isFunctionOrMethod() && D->isLocalExternDecl() && + !(D->getIdentifierNamespace() & Decl::IDNS_Ordinary)) + F.erase(); + } + F.done(); +} + /// Builds a using declaration. /// /// \param IsInstantiation - Whether this call arises from an @@ -12025,21 +12083,7 @@ if (S) { LookupName(Previous, S); - // It is really dumb that we have to do this. - LookupResult::Filter F = Previous.makeFilter(); - while (F.hasNext()) { - NamedDecl *D = F.next(); - if (!isDeclInScope(D, CurContext, S)) - F.erase(); - // If we found a local extern declaration that's not ordinarily visible, - // and this declaration is being added to a non-block scope, ignore it. - // We're only checking for scope conflicts here, not also for violations - // of the linkage rules. - else if (!CurContext->isFunctionOrMethod() && D->isLocalExternDecl() && - !(D->getIdentifierNamespace() & Decl::IDNS_Ordinary)) - F.erase(); - } - F.done(); + FilterUsingLookup(S, Previous); } else { assert(IsInstantiation && "no scope in non-instantiation"); if (CurContext->isRecord()) @@ -12251,6 +12295,61 @@ return UD; } +NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS, + SourceLocation UsingLoc, + SourceLocation EnumLoc, + SourceLocation NameLoc, + EnumDecl *ED) { + bool Invalid = false; + + if (CurContext->getRedeclContext()->isRecord()) { + /// In class scope, check if this is a duplicate, for better a diagnostic. + DeclarationNameInfo UsingEnumName(ED->getDeclName(), NameLoc); + LookupResult Previous(*this, UsingEnumName, LookupUsingDeclName, + ForVisibleRedeclaration); + + LookupName(Previous, S); + + for (NamedDecl *D : Previous) + if (UsingEnumDecl *UED = dyn_cast<UsingEnumDecl>(D)) + if (UED->getEnumDecl() == ED) { + Diag(UsingLoc, diag::err_using_enum_decl_redeclaration) + << SourceRange(EnumLoc, NameLoc); + Diag(D->getLocation(), diag::note_using_enum_decl) << 1; + Invalid = true; + break; + } + } + + if (RequireCompleteEnumDecl(ED, NameLoc)) + Invalid = true; + + UsingEnumDecl *UD = UsingEnumDecl::Create(Context, CurContext, UsingLoc, + EnumLoc, NameLoc, ED); + UD->setAccess(AS); + CurContext->addDecl(UD); + + if (Invalid) { + UD->setInvalidDecl(); + return UD; + } + + // Create the shadow decls for each enumerator + for (EnumConstantDecl *EC : ED->enumerators()) { + UsingShadowDecl *PrevDecl = nullptr; + DeclarationNameInfo DNI(EC->getDeclName(), EC->getLocation()); + LookupResult Previous(*this, DNI, LookupOrdinaryName, + ForVisibleRedeclaration); + LookupName(Previous, S); + FilterUsingLookup(S, Previous); + + if (!CheckUsingShadowDecl(UD, EC, Previous, PrevDecl)) + BuildUsingShadowDecl(S, UD, EC, PrevDecl); + } + + return UD; +} + NamedDecl *Sema::BuildUsingPackDecl(NamedDecl *InstantiatedFrom, ArrayRef<NamedDecl *> Expansions) { assert(isa<UnresolvedUsingValueDecl>(InstantiatedFrom) || Index: clang/lib/Sema/SemaCodeComplete.cpp =================================================================== --- clang/lib/Sema/SemaCodeComplete.cpp +++ clang/lib/Sema/SemaCodeComplete.cpp @@ -3915,6 +3915,9 @@ case Decl::UnresolvedUsingTypename: return CXCursor_UsingDeclaration; + case Decl::UsingEnum: + return CXCursor_EnumDecl; + case Decl::ObjCPropertyImpl: switch (cast<ObjCPropertyImplDecl>(D)->getPropertyImplementation()) { case ObjCPropertyImplDecl::Dynamic: Index: clang/lib/Sema/SemaCXXScopeSpec.cpp =================================================================== --- clang/lib/Sema/SemaCXXScopeSpec.cpp +++ clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -240,7 +240,6 @@ /// bool Sema::RequireCompleteEnumDecl(EnumDecl *EnumD, SourceLocation L, CXXScopeSpec *SS) { - assert (SS && "missing scope"); if (EnumD->isCompleteDefinition()) { // If we know about the definition but it is not visible, complain. NamedDecl *SuggestedDef = nullptr; @@ -264,16 +263,22 @@ if (InstantiateEnum(L, EnumD, Pattern, getTemplateInstantiationArgs(EnumD), TSK_ImplicitInstantiation)) { - SS->SetInvalid(SS->getRange()); + if (SS) + SS->SetInvalid(SS->getRange()); return true; } return false; } } - Diag(L, diag::err_incomplete_nested_name_spec) - << QualType(EnumD->getTypeForDecl(), 0) << SS->getRange(); - SS->SetInvalid(SS->getRange()); + if (SS) { + Diag(L, diag::err_incomplete_nested_name_spec) + << QualType(EnumD->getTypeForDecl(), 0) << SS->getRange(); + SS->SetInvalid(SS->getRange()); + } else { + Diag(L, diag::err_incomplete_enum) << QualType(EnumD->getTypeForDecl(), 0); + Diag(EnumD->getLocation(), diag::note_declared_at); + } return true; } Index: clang/lib/Parse/ParseDeclCXX.cpp =================================================================== --- clang/lib/Parse/ParseDeclCXX.cpp +++ clang/lib/Parse/ParseDeclCXX.cpp @@ -670,11 +670,46 @@ /// alias-declaration: C++11 [dcl.dcl]p1 /// 'using' identifier attribute-specifier-seq[opt] = type-id ; /// +/// using-enum-declaration: [C++20, dcl.enum] +/// 'using' elaborated-enum-specifier ; +/// +/// elaborated-enum-specifier: +/// 'enum' nested-name-specifier[opt] identifier Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, SourceLocation &DeclEnd, AccessSpecifier AS) { + SourceLocation UELoc; + if (TryConsumeToken(tok::kw_enum, UELoc)) { + // C++20 using-enum + Diag(UELoc, getLangOpts().CPlusPlus20 + ? diag::warn_cxx17_compat_using_enum_declaration + : diag::ext_using_enum_declaration); + + DeclSpec DS(AttrFactory); + ParseEnumSpecifier(UELoc, DS, TemplateInfo, AS, + // DSC_trailing has the semantics we desire + DeclSpecContext::DSC_trailing); + + if (TemplateInfo.Kind) { + SourceRange R = TemplateInfo.getSourceRange(); + Diag(UsingLoc, diag::err_templated_using_directive_declaration) + << 1 /* declaration */ << R << FixItHint::CreateRemoval(R); + + return nullptr; + } + + Decl *UED = Actions.ActOnUsingEnumDeclaration(getCurScope(), AS, UsingLoc, + UELoc, DS); + DeclEnd = Tok.getLocation(); + if (ExpectAndConsume(tok::semi, diag::err_expected_after, + "using-enum declaration")) + SkipUntil(tok::semi); + + return Actions.ConvertDeclToDeclGroup(UED); + } + // Check for misplaced attributes before the identifier in an // alias-declaration. ParsedAttributesWithRange MisplacedAttrs(AttrFactory); @@ -771,8 +806,9 @@ // Eat ';'. DeclEnd = Tok.getLocation(); if (ExpectAndConsume(tok::semi, diag::err_expected_after, - !Attrs.empty() ? "attributes list" - : "using declaration")) + !Attrs.empty() ? "attributes list" + : UELoc.isValid() ? "using-enum declaration" + : "using declaration")) SkipUntil(tok::semi); return Actions.BuildDeclaratorGroup(DeclsInGroup); Index: clang/lib/Index/IndexSymbol.cpp =================================================================== --- clang/lib/Index/IndexSymbol.cpp +++ clang/lib/Index/IndexSymbol.cpp @@ -329,6 +329,11 @@ Info.Kind = SymbolKind::Using; Info.Lang = SymbolLanguage::CXX; break; + case Decl::UsingEnum: + Info.Kind = SymbolKind::Using; + Info.Lang = SymbolLanguage::CXX; + Info.SubKind = SymbolSubKind::UsingEnum; + break; case Decl::Binding: Info.Kind = SymbolKind::Variable; Info.Lang = SymbolLanguage::CXX; @@ -542,6 +547,8 @@ case SymbolSubKind::AccessorSetter: return "acc-set"; case SymbolSubKind::UsingTypename: return "using-typename"; case SymbolSubKind::UsingValue: return "using-value"; + case SymbolSubKind::UsingEnum: + return "using-enum"; } llvm_unreachable("invalid symbol subkind"); } Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -5733,6 +5733,10 @@ if (CGDebugInfo *DI = getModuleDebugInfo()) DI->EmitUsingDecl(cast<UsingDecl>(*D)); break; + case Decl::UsingEnum: // using enum X; [C++] + if (CGDebugInfo *DI = getModuleDebugInfo()) + DI->EmitUsingEnumDecl(cast<UsingEnumDecl>(*D)); + break; case Decl::NamespaceAlias: if (CGDebugInfo *DI = getModuleDebugInfo()) DI->EmitNamespaceAlias(cast<NamespaceAliasDecl>(*D)); Index: clang/lib/CodeGen/CGDecl.cpp =================================================================== --- clang/lib/CodeGen/CGDecl.cpp +++ clang/lib/CodeGen/CGDecl.cpp @@ -137,6 +137,10 @@ if (CGDebugInfo *DI = getDebugInfo()) DI->EmitUsingDecl(cast<UsingDecl>(D)); return; + case Decl::UsingEnum: // using enum X; [C++] + if (CGDebugInfo *DI = getDebugInfo()) + DI->EmitUsingEnumDecl(cast<UsingEnumDecl>(D)); + return; case Decl::UsingPack: for (auto *Using : cast<UsingPackDecl>(D).expansions()) EmitDecl(*Using); Index: clang/lib/CodeGen/CGDebugInfo.h =================================================================== --- clang/lib/CodeGen/CGDebugInfo.h +++ clang/lib/CodeGen/CGDebugInfo.h @@ -508,6 +508,9 @@ /// Emit C++ using declaration. void EmitUsingDecl(const UsingDecl &UD); + /// Emit C++ using-enum declaration. + void EmitUsingEnumDecl(const UsingEnumDecl &UD); + /// Emit an @import declaration. void EmitImportDecl(const ImportDecl &ID); Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -5002,6 +5002,17 @@ } } +void CGDebugInfo::EmitUsingEnumDecl(const UsingEnumDecl &UD) { + if (!CGM.getCodeGenOpts().hasReducedDebugInfo()) + return; + assert(UD.shadow_size() && + "We shouldn't be codegening an invalid UsingEnumDecl" + " containing no decls"); + + for (const auto *USD : UD.shadows()) + EmitUsingShadowDecl(*USD); +} + void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) { if (CGM.getCodeGenOpts().getDebuggerTuning() != llvm::DebuggerKind::LLDB) return; Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -561,6 +561,7 @@ REGISTER_MATCHER(userDefinedLiteral); REGISTER_MATCHER(usesADL); REGISTER_MATCHER(usingDecl); + REGISTER_MATCHER(usingEnumDecl); REGISTER_MATCHER(usingDirectiveDecl); REGISTER_MATCHER(valueDecl); REGISTER_MATCHER(varDecl); Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -841,6 +841,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, SubstNonTypeTemplateParmExpr> substNonTypeTemplateParmExpr; const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl; +const internal::VariadicDynCastAllOfMatcher<Decl, UsingEnumDecl> usingEnumDecl; const internal::VariadicDynCastAllOfMatcher<Decl, UsingDirectiveDecl> usingDirectiveDecl; const internal::VariadicDynCastAllOfMatcher<Stmt, UnresolvedLookupExpr> Index: clang/lib/AST/TextNodeDumper.cpp =================================================================== --- clang/lib/AST/TextNodeDumper.cpp +++ clang/lib/AST/TextNodeDumper.cpp @@ -2053,6 +2053,11 @@ OS << D->getDeclName(); } +void TextNodeDumper::VisitUsingEnumDecl(const UsingEnumDecl *D) { + OS << ' '; + dumpBareDeclRef(D->getEnumDecl()); +} + void TextNodeDumper::VisitUnresolvedUsingTypenameDecl( const UnresolvedUsingTypenameDecl *D) { OS << ' '; Index: clang/lib/AST/JSONNodeDumper.cpp =================================================================== --- clang/lib/AST/JSONNodeDumper.cpp +++ clang/lib/AST/JSONNodeDumper.cpp @@ -756,6 +756,10 @@ JOS.attribute("name", Name); } +void JSONNodeDumper::VisitUsingEnumDecl(const UsingEnumDecl *UED) { + JOS.attribute("target", createBareDeclRef(UED->getEnumDecl())); +} + void JSONNodeDumper::VisitUsingShadowDecl(const UsingShadowDecl *USD) { JOS.attribute("target", createBareDeclRef(USD->getTargetDecl())); } Index: clang/lib/AST/DeclPrinter.cpp =================================================================== --- clang/lib/AST/DeclPrinter.cpp +++ clang/lib/AST/DeclPrinter.cpp @@ -98,6 +98,7 @@ void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitUsingDecl(UsingDecl *D); + void VisitUsingEnumDecl(UsingEnumDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); void VisitOMPAllocateDecl(OMPAllocateDecl *D); @@ -1609,6 +1610,10 @@ Out << *D; } +void DeclPrinter::VisitUsingEnumDecl(UsingEnumDecl *D) { + Out << "using enum " << D->getEnumDecl(); +} + void DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { Out << "using typename "; Index: clang/lib/AST/DeclCXX.cpp =================================================================== --- clang/lib/AST/DeclCXX.cpp +++ clang/lib/AST/DeclCXX.cpp @@ -3082,6 +3082,23 @@ return SourceRange(Begin, getNameInfo().getEndLoc()); } +void UsingEnumDecl::anchor() {} + +UsingEnumDecl *UsingEnumDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation UL, SourceLocation EL, + SourceLocation NL, EnumDecl *Enum) { + return new (C, DC) UsingEnumDecl(DC, Enum->getDeclName(), UL, EL, NL, Enum); +} + +UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) { + return new (C, ID) UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(), + SourceLocation(), SourceLocation(), nullptr); +} + +SourceRange UsingEnumDecl::getSourceRange() const { + return SourceRange(EnumLocation, getLocation()); +} + void UsingPackDecl::anchor() {} UsingPackDecl *UsingPackDecl::Create(ASTContext &C, DeclContext *DC, Index: clang/lib/AST/DeclBase.cpp =================================================================== --- clang/lib/AST/DeclBase.cpp +++ clang/lib/AST/DeclBase.cpp @@ -784,6 +784,7 @@ case Using: case UsingPack: + case UsingEnum: return IDNS_Using; case ObjCProtocol: Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -1370,6 +1370,7 @@ case Decl::NamespaceAlias: case Decl::ParmVar: case Decl::Using: + case Decl::UsingEnum: case Decl::UsingShadow: case Decl::UsingDirective: return LinkageInfo::none(); Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -512,6 +512,8 @@ ExpectedDecl VisitUsingDecl(UsingDecl *D); ExpectedDecl VisitUsingShadowDecl(UsingShadowDecl *D); ExpectedDecl VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + ExpectedDecl ImportUsingShadowDecls(BaseUsingDecl *D, BaseUsingDecl *ToSI); + ExpectedDecl VisitUsingEnumDecl(UsingEnumDecl *D); ExpectedDecl VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); ExpectedDecl VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); ExpectedDecl VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D); @@ -4562,6 +4564,19 @@ return ToLinkageSpec; } +ExpectedDecl ASTNodeImporter::ImportUsingShadowDecls(BaseUsingDecl *D, + BaseUsingDecl *ToSI) { + for (UsingShadowDecl *FromShadow : D->shadows()) { + if (Expected<UsingShadowDecl *> ToShadowOrErr = import(FromShadow)) + ToSI->addShadowDecl(*ToShadowOrErr); + else + // FIXME: We return error here but the definition is already created + // and available with lookups. How to fix this?.. + return ToShadowOrErr.takeError(); + } + return ToSI; +} + ExpectedDecl ASTNodeImporter::VisitUsingDecl(UsingDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -4601,15 +4616,44 @@ return ToPatternOrErr.takeError(); } - for (UsingShadowDecl *FromShadow : D->shadows()) { - if (Expected<UsingShadowDecl *> ToShadowOrErr = import(FromShadow)) - ToUsing->addShadowDecl(*ToShadowOrErr); + return ImportUsingShadowDecls(D, ToUsing); +} + +ExpectedDecl ASTNodeImporter::VisitUsingEnumDecl(UsingEnumDecl *D) { + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + NamedDecl *ToD = nullptr; + if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) + return std::move(Err); + if (ToD) + return ToD; + + Error Err = Error::success(); + auto ToUsingLoc = importChecked(Err, D->getUsingLoc()); + auto ToEnumLoc = importChecked(Err, D->getEnumLoc()); + auto ToEnumDecl = importChecked(Err, D->getEnumDecl()); + if (Err) + return std::move(Err); + + UsingEnumDecl *ToUsingEnum; + if (GetImportedOrCreateDecl(ToUsingEnum, D, Importer.getToContext(), DC, + ToUsingLoc, ToEnumLoc, Loc, ToEnumDecl)) + return ToUsingEnum; + + ToUsingEnum->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(ToUsingEnum); + + if (UsingEnumDecl *FromPattern = + Importer.getFromContext().getInstantiatedFromUsingEnumDecl(D)) { + if (Expected<UsingEnumDecl *> ToPatternOrErr = import(FromPattern)) + Importer.getToContext().setInstantiatedFromUsingEnumDecl(ToUsingEnum, + *ToPatternOrErr); else - // FIXME: We return error here but the definition is already created - // and available with lookups. How to fix this?.. - return ToShadowOrErr.takeError(); + return ToPatternOrErr.takeError(); } - return ToUsing; + + return ImportUsingShadowDecls(D, ToUsingEnum); } ExpectedDecl ASTNodeImporter::VisitUsingShadowDecl(UsingShadowDecl *D) { Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -1571,6 +1571,21 @@ InstantiatedFromUsingDecl[Inst] = Pattern; } +UsingEnumDecl * +ASTContext::getInstantiatedFromUsingEnumDecl(UsingEnumDecl *UUD) { + auto Pos = InstantiatedFromUsingEnumDecl.find(UUD); + if (Pos == InstantiatedFromUsingEnumDecl.end()) + return nullptr; + + return Pos->second; +} + +void ASTContext::setInstantiatedFromUsingEnumDecl(UsingEnumDecl *Inst, + UsingEnumDecl *Pattern) { + assert(!InstantiatedFromUsingEnumDecl[Inst] && "pattern already exists"); + InstantiatedFromUsingEnumDecl[Inst] = Pattern; +} + UsingShadowDecl * ASTContext::getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst) { llvm::DenseMap<UsingShadowDecl*, UsingShadowDecl*>::const_iterator Pos Index: clang/include/clang/Serialization/ASTBitCodes.h =================================================================== --- clang/include/clang/Serialization/ASTBitCodes.h +++ clang/include/clang/Serialization/ASTBitCodes.h @@ -1339,6 +1339,9 @@ /// A UsingDecl record. DECL_USING, + /// A UsingEnumDecl record. + DECL_USING_ENUM, + /// A UsingPackDecl record. DECL_USING_PACK, Index: clang/include/clang/Sema/Template.h =================================================================== --- clang/include/clang/Sema/Template.h +++ clang/include/clang/Sema/Template.h @@ -537,6 +537,8 @@ Decl *VisitDecl(Decl *D); Decl *VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate, ArrayRef<BindingDecl *> *Bindings = nullptr); + Decl *VisitBaseUsingDecls(BaseUsingDecl *D, BaseUsingDecl *Inst, + LookupResult *Lookup); // Enable late instantiation of attributes. Late instantiated attributes // will be stored in LA. Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -5674,6 +5674,7 @@ SourceLocation IdentLoc, IdentifierInfo *Ident); + void FilterUsingLookup(Scope *S, LookupResult &lookup); void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); bool CheckUsingShadowDecl(BaseUsingDecl *BUD, NamedDecl *Target, const LookupResult &PreviousDecls, @@ -5699,6 +5700,10 @@ bool HasTypenameKeyword, SourceLocation TypenameLoc, CXXScopeSpec &SS, DeclarationNameInfo NameInfo, SourceLocation EllipsisLoc, const ParsedAttributesView &AttrList, bool IsInstantiation); + NamedDecl *BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS, + SourceLocation UsingLoc, + SourceLocation EnumLoc, + SourceLocation NameLoc, EnumDecl *ED); NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom, ArrayRef<NamedDecl *> Expansions); @@ -5716,6 +5721,9 @@ SourceLocation TypenameLoc, CXXScopeSpec &SS, UnqualifiedId &Name, SourceLocation EllipsisLoc, const ParsedAttributesView &AttrList); + Decl *ActOnUsingEnumDeclaration(Scope *CurScope, AccessSpecifier AS, + SourceLocation UsingLoc, + SourceLocation EnumLoc, const DeclSpec &); Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS, MultiTemplateParamsArg TemplateParams, SourceLocation UsingLoc, UnqualifiedId &Name, Index: clang/include/clang/Index/IndexSymbol.h =================================================================== --- clang/include/clang/Index/IndexSymbol.h +++ clang/include/clang/Index/IndexSymbol.h @@ -75,6 +75,7 @@ AccessorSetter, UsingTypename, UsingValue, + UsingEnum, }; typedef uint16_t SymbolPropertySet; Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -550,8 +550,6 @@ def ext_using_decl_class_member_enumerator : ExtWarn< "member using declaration naming a non-member enumerator is " "a C++20 extension">, InGroup<CXX20>; -def err_using_enum_lacks_definition : Error< - "enum named by using-enum declaration lacks a definition">; def err_using_enum_is_dependent : Error< "using-enum cannot name a dependent type">; def err_ambiguous_inherited_constructor : Error< @@ -588,6 +586,9 @@ def note_using_decl : Note<"%select{|previous }0using declaration">; def err_using_decl_redeclaration_expansion : Error< "using declaration pack expansion at block scope produces multiple values">; +def err_using_enum_decl_redeclaration : Error< + "redeclaration of using-enum declaration">; +def note_using_enum_decl : Note<"%select{|previous }0using-enum declaration">; def warn_access_decl_deprecated : Warning< "access declarations are deprecated; use using declarations instead">, @@ -1750,6 +1751,8 @@ // C++ name lookup def err_incomplete_nested_name_spec : Error< "incomplete type %0 named in nested name specifier">; +def err_incomplete_enum : Error< + "enumeration %0 is incomplete">; def err_dependent_nested_name_spec : Error< "nested name specifier for a declaration cannot depend on a template " "parameter">; Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -580,6 +580,12 @@ def err_expected_catch : Error<"expected catch">; def err_using_namespace_in_class : Error< "'using namespace' is not allowed in classes">; +def warn_cxx17_compat_using_enum_declaration : Warning< + "using enum declaration is incompatible with C++ standards before C++20">, + InGroup<CXXPre20Compat>, DefaultIgnore; +def ext_using_enum_declaration : ExtWarn< + "using enum declaration is a C++20 extension">, + InGroup<CXX20>; def err_constructor_bad_name : Error< "missing return type for function %0; did you mean the constructor name %1?">; def err_destructor_tilde_identifier : Error< Index: clang/include/clang/Basic/DeclNodes.td =================================================================== --- clang/include/clang/Basic/DeclNodes.td +++ clang/include/clang/Basic/DeclNodes.td @@ -73,6 +73,7 @@ def Concept : DeclNode<Template>; def BaseUsing : DeclNode<Named, "", 1>; def Using : DeclNode<BaseUsing>; + def UsingEnum : DeclNode<BaseUsing>; def UsingPack : DeclNode<Named>; def UsingShadow : DeclNode<Named>; def ConstructorUsingShadow : DeclNode<UsingShadow>; Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -1752,6 +1752,18 @@ /// matches \code using X::x \endcode extern const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> 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<Decl, UsingEnumDecl> + usingEnumDecl; + /// Matches using namespace declarations. /// /// Given @@ -6197,7 +6209,7 @@ /// \endcode /// usingDecl(hasAnyUsingShadowDecl(hasName("b")))) /// matches \code using X::b \endcode -AST_MATCHER_P(UsingDecl, hasAnyUsingShadowDecl, +AST_MATCHER_P(BaseUsingDecl, hasAnyUsingShadowDecl, internal::Matcher<UsingShadowDecl>, InnerMatcher) { return matchesFirstInPointerRange(InnerMatcher, Node.shadow_begin(), Node.shadow_end(), Finder, Index: clang/include/clang/AST/TextNodeDumper.h =================================================================== --- clang/include/clang/AST/TextNodeDumper.h +++ clang/include/clang/AST/TextNodeDumper.h @@ -350,6 +350,7 @@ 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); Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -1593,6 +1593,8 @@ TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); }) +DEF_TRAVERSE_DECL(UsingEnumDecl, {}) + DEF_TRAVERSE_DECL(UsingPackDecl, {}) DEF_TRAVERSE_DECL(UsingDirectiveDecl, { Index: clang/include/clang/AST/JSONNodeDumper.h =================================================================== --- clang/include/clang/AST/JSONNodeDumper.h +++ clang/include/clang/AST/JSONNodeDumper.h @@ -234,6 +234,7 @@ 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); Index: clang/include/clang/AST/DeclCXX.h =================================================================== --- clang/include/clang/AST/DeclCXX.h +++ clang/include/clang/AST/DeclCXX.h @@ -3365,7 +3365,7 @@ 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. @@ -3567,6 +3567,65 @@ 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<UsingEnumDecl> { + /// 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<UsingEnumDecl>(getFirstDecl()); + } + const UsingEnumDecl *getCanonicalDecl() const { + return cast<UsingEnumDecl>(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. /// Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -517,6 +517,17 @@ /// B<int> to the UnresolvedUsingDecl in B<T>. llvm::DenseMap<NamedDecl *, NamedDecl *> 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<UsingEnumDecl *, UsingEnumDecl *> + InstantiatedFromUsingEnumDecl; + + /// Simlarly maps instantiated UsingShadowDecls to their origin. llvm::DenseMap<UsingShadowDecl*, UsingShadowDecl*> InstantiatedFromUsingShadowDecl; @@ -885,15 +896,15 @@ 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); @@ -906,9 +917,19 @@ /// 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 a + /// (possibly unresolved) using decl from a template instantiation, + /// 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); Index: clang-tools-extra/clangd/FindTarget.cpp =================================================================== --- clang-tools-extra/clangd/FindTarget.cpp +++ clang-tools-extra/clangd/FindTarget.cpp @@ -181,6 +181,9 @@ for (const UsingShadowDecl *S : UD->shadows()) add(S->getUnderlyingDecl(), Flags); Flags |= Rel::Alias; // continue with the alias. + } else if (const UsingEnumDecl *UED = dyn_cast<UsingEnumDecl>(D)) { + add(UED->getEnumDecl(), Flags); + Flags |= Rel::Alias; // continue with the alias. } else if (const auto *NAD = dyn_cast<NamespaceAliasDecl>(D)) { add(NAD->getUnderlyingDecl(), Flags | Rel::Underlying); Flags |= Rel::Alias; // continue with the alias
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits