[clang] b2d0c16 - [clang] p1099 using enum part 2
Nathan Sidwell via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 8 11:12:29 PDT 2021
Author: Nathan Sidwell
Date: 2021-06-08T11:11:46-07:00
New Revision: b2d0c16e91f39def3646b71e5afebfaea262cca1
URL: https://github.com/llvm/llvm-project/commit/b2d0c16e91f39def3646b71e5afebfaea262cca1
DIFF: https://github.com/llvm/llvm-project/commit/b2d0c16e91f39def3646b71e5afebfaea262cca1.diff
LOG: [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
Added:
clang/test/AST/ast-dump-using-enum.cpp
clang/test/SemaCXX/cxx20-using-enum.cpp
Modified:
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/tools/libclang/CIndex.cpp
clang/unittests/AST/ASTImporterTest.cpp
clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index 9068fffcbd40..b68e5c6c1e89 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -181,6 +181,9 @@ struct TargetFinder {
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
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 22588a61f6ff..f103ec6deb1f 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -518,6 +518,17 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// 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;
@@ -886,30 +897,38 @@ class ASTContext : public RefCountedBase<ASTContext> {
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 c8095bb2ca2b..e9f9da6bd4bc 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -3366,7 +3366,7 @@ class BaseUsingDecl : public NamedDecl {
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 @@ class ConstructorUsingShadowDecl final : public UsingShadowDecl {
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.
///
diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h
index a8b731a7cd31..1f3585910a40 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -234,6 +234,7 @@ class JSONNodeDumper
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 ab49b39307be..73d757f0255a 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 e3aa94d5a1e8..4dc68d5237b4 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -351,6 +351,7 @@ class TextNodeDumper
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 b3c43458fce7..4db562910c53 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -1752,6 +1752,18 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt,
/// 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 @@ 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<UsingShadowDecl>, 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 ceaea521f118..f8ad6cf5b262 100644
--- a/clang/include/clang/Basic/DeclNodes.td
+++ b/clang/include/clang/Basic/DeclNodes.td
@@ -73,6 +73,7 @@ def Named : DeclNode<Decl, "named declarations", 1>;
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>;
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index c99ce6dfa246..aecc5859c718 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -580,6 +580,12 @@ def warn_cxx98_compat_noexcept_decl : Warning<
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<
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 21672ed09559..ba55095a8266 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -554,8 +554,6 @@ def warn_cxx17_compat_using_decl_class_member_enumerator : Warning<
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<
@@ -598,6 +596,9 @@ def note_empty_using_if_exists_here : Note<
"using declaration annotated with 'using_if_exists' here">;
def err_using_if_exists_on_ctor : Error<
"'using_if_exists' attribute cannot be applied to an inheriting constructor">;
+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">,
@@ -1760,6 +1761,8 @@ def warn_cxx98_compat_sfinae_access_control : Warning<
// 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">;
diff --git a/clang/include/clang/Index/IndexSymbol.h b/clang/include/clang/Index/IndexSymbol.h
index de98b8147e8a..2ba81986c2fe 100644
--- a/clang/include/clang/Index/IndexSymbol.h
+++ b/clang/include/clang/Index/IndexSymbol.h
@@ -75,6 +75,7 @@ enum class SymbolSubKind : uint8_t {
AccessorSetter,
UsingTypename,
UsingValue,
+ UsingEnum,
};
typedef uint16_t SymbolPropertySet;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c122b991af9e..940630c6508d 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5701,6 +5701,7 @@ class Sema final {
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,
@@ -5721,14 +5722,16 @@ class Sema final {
const LookupResult *R = nullptr,
const UsingDecl *UD = nullptr);
- NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
- SourceLocation UsingLoc,
- bool HasTypenameKeyword,
- SourceLocation TypenameLoc, CXXScopeSpec &SS,
- DeclarationNameInfo NameInfo,
- SourceLocation EllipsisLoc,
- const ParsedAttributesView &AttrList,
- bool IsInstantiation, bool IsUsingIfExists);
+ NamedDecl *BuildUsingDeclaration(
+ Scope *S, AccessSpecifier AS, SourceLocation UsingLoc,
+ bool HasTypenameKeyword, SourceLocation TypenameLoc, CXXScopeSpec &SS,
+ DeclarationNameInfo NameInfo, SourceLocation EllipsisLoc,
+ const ParsedAttributesView &AttrList, bool IsInstantiation,
+ bool IsUsingIfExists);
+ NamedDecl *BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
+ SourceLocation UsingLoc,
+ SourceLocation EnumLoc,
+ SourceLocation NameLoc, EnumDecl *ED);
NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom,
ArrayRef<NamedDecl *> Expansions);
@@ -5746,6 +5749,9 @@ class Sema final {
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,
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 0dcaf565591b..540d2c9aa87e 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -537,6 +537,8 @@ enum class TemplateSubstitutionKind : char {
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.
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index ff316904c0a3..edf8987d61a6 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1339,6 +1339,9 @@ enum DeclCode {
/// A UsingDecl record.
DECL_USING,
+ /// A UsingEnumDecl record.
+ DECL_USING_ENUM,
+
/// A UsingPackDecl record.
DECL_USING_PACK,
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 76f84c728bc6..a1f3baf99704 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1571,6 +1571,21 @@ ASTContext::setInstantiatedFromUsingDecl(NamedDecl *Inst, NamedDecl *Pattern) {
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
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index c27a50eba1d8..0fd1401e9e9f 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -512,6 +512,8 @@ namespace clang {
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);
@@ -4564,6 +4566,19 @@ ExpectedDecl ASTNodeImporter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
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;
@@ -4603,15 +4618,44 @@ ExpectedDecl ASTNodeImporter::VisitUsingDecl(UsingDecl *D) {
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) {
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index c5c8f473dda9..27b34d3d1699 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1370,6 +1370,7 @@ LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D,
case Decl::NamespaceAlias:
case Decl::ParmVar:
case Decl::Using:
+ case Decl::UsingEnum:
case Decl::UsingShadow:
case Decl::UsingDirective:
return LinkageInfo::none();
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 4e6d2da1e0d5..80b591e2a81a 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -784,6 +784,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Using:
case UsingPack:
+ case UsingEnum:
return IDNS_Using;
case ObjCProtocol:
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 10d59bce3f5c..628dff786c6e 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -3082,6 +3082,23 @@ SourceRange UsingDecl::getSourceRange() const {
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,
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 90391cab08d6..516be54b90f6 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -98,6 +98,7 @@ namespace {
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 @@ void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
Out << *D;
}
+void DeclPrinter::VisitUsingEnumDecl(UsingEnumDecl *D) {
+ Out << "using enum " << D->getEnumDecl();
+}
+
void
DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
Out << "using typename ";
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 5d5388880e67..d2835583a0f2 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -756,6 +756,10 @@ void JSONNodeDumper::VisitUsingDecl(const UsingDecl *UD) {
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()));
}
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index cb5b4230a5ab..d17db0a0c9fe 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -2058,6 +2058,11 @@ void TextNodeDumper::VisitUsingDecl(const UsingDecl *D) {
OS << D->getDeclName();
}
+void TextNodeDumper::VisitUsingEnumDecl(const UsingEnumDecl *D) {
+ OS << ' ';
+ dumpBareDeclRef(D->getEnumDecl());
+}
+
void TextNodeDumper::VisitUnresolvedUsingTypenameDecl(
const UnresolvedUsingTypenameDecl *D) {
OS << ' ';
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 7c4eb6dd77ca..169ce3b83980 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -841,6 +841,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, ParenListExpr> parenListExpr;
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>
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 31b4f601faf4..0048f1133ca2 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -561,6 +561,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(userDefinedLiteral);
REGISTER_MATCHER(usesADL);
REGISTER_MATCHER(usingDecl);
+ REGISTER_MATCHER(usingEnumDecl);
REGISTER_MATCHER(usingDirectiveDecl);
REGISTER_MATCHER(valueDecl);
REGISTER_MATCHER(varDecl);
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index b1db8a889b3f..1367ef46d85d 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -5002,6 +5002,17 @@ void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
}
}
+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;
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index e9ead90aafb5..9c52bc75475f 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -508,6 +508,9 @@ class CGDebugInfo {
/// 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);
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 7948f431299c..e9a7836bab47 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -138,6 +138,10 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
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);
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index c93339a211f3..7efc97c51eda 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -5740,6 +5740,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
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));
diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp
index 0d2e557cdd36..68e457de5265 100644
--- a/clang/lib/Index/IndexSymbol.cpp
+++ b/clang/lib/Index/IndexSymbol.cpp
@@ -329,6 +329,11 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
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 @@ StringRef index::getSymbolSubKindString(SymbolSubKind K) {
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");
}
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index eebbb545f060..37a5ae1f1377 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -667,10 +667,48 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
/// alias-declaration: C++11 [dcl.dcl]p1
/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
///
-Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
+/// 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,
ParsedAttributesWithRange &PrefixAttrs, 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);
+
+ DiagnoseCXX11AttributeExtension(PrefixAttrs);
+
+ 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);
@@ -768,8 +806,9 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
// 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);
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 87059eb45085..1c8f6329bd67 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -240,7 +240,6 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
///
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 @@ bool Sema::RequireCompleteEnumDecl(EnumDecl *EnumD, SourceLocation L,
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;
}
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 0bde8eaf7550..1ab9c50709a9 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -3915,6 +3915,9 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) {
case Decl::UnresolvedUsingTypename:
return CXCursor_UsingDeclaration;
+ case Decl::UsingEnum:
+ return CXCursor_EnumDecl;
+
case Decl::ObjCPropertyImpl:
switch (cast<ObjCPropertyImplDecl>(D)->getPropertyImplementation()) {
case ObjCPropertyImplDecl::Dynamic:
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 1a8745ea9a27..c1d7217e4548 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1835,9 +1835,11 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
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:
@@ -11604,11 +11606,44 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS,
}
}
- NamedDecl *UD = BuildUsingDeclaration(
- S, AS, UsingLoc, TypenameLoc.isValid(), TypenameLoc, SS, TargetNameInfo,
- EllipsisLoc, AttrList,
- /*IsInstantiation=*/false,
- AttrList.hasAttribute(ParsedAttr::AT_UsingIfExists));
+ NamedDecl *UD =
+ BuildUsingDeclaration(S, AS, UsingLoc, TypenameLoc.isValid(), TypenameLoc,
+ SS, TargetNameInfo, EllipsisLoc, AttrList,
+ /*IsInstantiation*/ false,
+ AttrList.hasAttribute(ParsedAttr::AT_UsingIfExists));
+ 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);
@@ -11712,7 +11747,7 @@ bool Sema::CheckUsingShadowDecl(BaseUsingDecl *BUD, NamedDecl *Orig,
// 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)) {
@@ -12014,6 +12049,29 @@ class UsingValidatorCCC final : public CorrectionCandidateCallback {
};
} // 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
@@ -12047,21 +12105,7 @@ NamedDecl *Sema::BuildUsingDeclaration(
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())
@@ -12287,6 +12331,61 @@ NamedDecl *Sema::BuildUsingDeclaration(
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) ||
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f1b34693f45d..10945963352b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3013,6 +3013,53 @@ Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
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 = nullptr;
+ if (auto *EmptyD =
+ dyn_cast<UnresolvedUsingIfExistsDecl>(Shadow->getTargetDecl())) {
+ InstTarget = UnresolvedUsingIfExistsDecl::Create(
+ SemaRef.Context, Owner, EmptyD->getLocation(), EmptyD->getDeclName());
+ } else {
+ 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
@@ -3038,11 +3085,9 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
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);
@@ -3063,13 +3108,13 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
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);
@@ -3083,49 +3128,34 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
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 = nullptr;
- if (auto *EmptyD =
- dyn_cast<UnresolvedUsingIfExistsDecl>(Shadow->getTargetDecl())) {
- InstTarget = UnresolvedUsingIfExistsDecl::Create(
- SemaRef.Context, Owner, EmptyD->getLocation(), EmptyD->getDeclName());
- } else {
- 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) {
diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp
index fb0438db7605..5fe1f96327dd 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -394,6 +394,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::NonTypeTemplateParm:
case Decl::TemplateTemplateParm:
case Decl::Using:
+ case Decl::UsingEnum:
case Decl::UsingPack:
case Decl::ObjCMethod:
case Decl::ObjCCategory:
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 41b44c0e5260..1d9bae5d3129 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -390,6 +390,7 @@ namespace clang {
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);
@@ -1652,6 +1653,17 @@ void ASTDeclReader::VisitUsingDecl(UsingDecl *D) {
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>();
@@ -3844,6 +3856,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
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;
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 03f2a0c451c8..e9315f67d553 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -114,6 +114,7 @@ namespace clang {
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);
@@ -1278,6 +1279,16 @@ void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) {
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);
diff --git a/clang/test/AST/ast-dump-using-enum.cpp b/clang/test/AST/ast-dump-using-enum.cpp
new file mode 100644
index 000000000000..3f848ca96626
--- /dev/null
+++ b/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'
diff --git a/clang/test/SemaCXX/cxx20-using-enum.cpp b/clang/test/SemaCXX/cxx20-using-enum.cpp
new file mode 100644
index 000000000000..daf35ebfefbb
--- /dev/null
+++ b/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 at -2{{is a C++20 extension}}
+#endif
+using enum Bob::B; // expected-error{{no enum named 'B'}}
+#if __cplusplus < 202002
+// expected-warning at -2{{is a C++20 extension}}
+#endif
+using enum Bob::C; // expected-error{{tag type that does not match}}
+#if __cplusplus < 202002
+// expected-warning at -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 at -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 at -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
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 3ec41c9b025c..89f7063b7364 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -6541,6 +6541,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
}
case Decl::Using:
+ case Decl::UsingEnum:
return MakeCursorOverloadedDeclRef(cast<BaseUsingDecl>(D), D->getLocation(),
TU);
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 4ed4a09b03b9..040adec3d5d7 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -844,7 +844,15 @@ TEST_P(ImportDecl, ImportUsingDecl) {
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 @@ const internal::VariadicDynCastAllOfMatcher<Decl,
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) {
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index c179ce11fefb..99d4b9bc626d 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1428,6 +1428,22 @@ TEST_P(ASTMatchersTest, UsingDecl_MatchesShadowUsingDelcarations) {
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;
More information about the cfe-commits
mailing list