mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 15:41:46 +00:00
[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
This commit is contained in:
parent
de98da2ece
commit
b2d0c16e91
@ -181,6 +181,9 @@ public:
|
||||
for (const UsingShadowDecl *S : UD->shadows())
|
||||
add(S->getUnderlyingDecl(), Flags);
|
||||
Flags |= Rel::Alias; // continue with the alias.
|
||||
} else if (const UsingEnumDecl *UED = dyn_cast<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
|
||||
|
@ -518,6 +518,17 @@ private:
|
||||
/// 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 @@ public:
|
||||
MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
|
||||
const VarDecl *Var);
|
||||
|
||||
TemplateOrSpecializationInfo
|
||||
getTemplateOrSpecializationInfo(const VarDecl *Var);
|
||||
|
||||
/// Note that the static data member \p Inst is an instantiation of
|
||||
/// the static data member template \p Tmpl of a class template.
|
||||
void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
|
||||
TemplateSpecializationKind TSK,
|
||||
SourceLocation PointOfInstantiation = SourceLocation());
|
||||
|
||||
TemplateOrSpecializationInfo
|
||||
getTemplateOrSpecializationInfo(const VarDecl *Var);
|
||||
|
||||
void setTemplateOrSpecializationInfo(VarDecl *Inst,
|
||||
TemplateOrSpecializationInfo TSI);
|
||||
|
||||
/// If the given using decl \p Inst is an instantiation of a
|
||||
/// (possibly unresolved) using decl from a template instantiation,
|
||||
/// return it.
|
||||
/// If the given using decl \p Inst is an instantiation of
|
||||
/// another (possibly unresolved) using decl, return it.
|
||||
NamedDecl *getInstantiatedFromUsingDecl(NamedDecl *Inst);
|
||||
|
||||
/// Remember that the using decl \p Inst is an instantiation
|
||||
/// of the using decl \p Pattern of a class template.
|
||||
void setInstantiatedFromUsingDecl(NamedDecl *Inst, NamedDecl *Pattern);
|
||||
|
||||
/// If the given using-enum decl \p Inst is an instantiation of
|
||||
/// another using-enum decl, return it.
|
||||
UsingEnumDecl *getInstantiatedFromUsingEnumDecl(UsingEnumDecl *Inst);
|
||||
|
||||
/// Remember that the using enum decl \p Inst is an instantiation
|
||||
/// of the using enum decl \p Pattern of a class template.
|
||||
void setInstantiatedFromUsingEnumDecl(UsingEnumDecl *Inst,
|
||||
UsingEnumDecl *Pattern);
|
||||
|
||||
UsingShadowDecl *getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst);
|
||||
void setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst,
|
||||
UsingShadowDecl *Pattern);
|
||||
UsingShadowDecl *getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst);
|
||||
|
||||
FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field);
|
||||
|
||||
|
@ -3366,7 +3366,7 @@ public:
|
||||
void removeShadowDecl(UsingShadowDecl *S);
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == Using; }
|
||||
static bool classofKind(Kind K) { return K == Using || K == UsingEnum; }
|
||||
};
|
||||
|
||||
/// Represents a C++ using-declaration.
|
||||
@ -3568,6 +3568,65 @@ public:
|
||||
static bool classofKind(Kind K) { return K == ConstructorUsingShadow; }
|
||||
};
|
||||
|
||||
/// Represents a C++ using-enum-declaration.
|
||||
///
|
||||
/// For example:
|
||||
/// \code
|
||||
/// using enum SomeEnumTag ;
|
||||
/// \endcode
|
||||
|
||||
class UsingEnumDecl : public BaseUsingDecl, public Mergeable<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.
|
||||
///
|
||||
|
@ -234,6 +234,7 @@ public:
|
||||
void VisitUsingDirectiveDecl(const UsingDirectiveDecl *UDD);
|
||||
void VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD);
|
||||
void VisitUsingDecl(const UsingDecl *UD);
|
||||
void VisitUsingEnumDecl(const UsingEnumDecl *UED);
|
||||
void VisitUsingShadowDecl(const UsingShadowDecl *USD);
|
||||
void VisitVarDecl(const VarDecl *VD);
|
||||
void VisitFieldDecl(const FieldDecl *FD);
|
||||
|
@ -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, {
|
||||
|
@ -351,6 +351,7 @@ public:
|
||||
void VisitUsingDecl(const UsingDecl *D);
|
||||
void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D);
|
||||
void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D);
|
||||
void VisitUsingEnumDecl(const UsingEnumDecl *D);
|
||||
void VisitUsingShadowDecl(const UsingShadowDecl *D);
|
||||
void VisitConstructorUsingShadowDecl(const ConstructorUsingShadowDecl *D);
|
||||
void VisitLinkageSpecDecl(const LinkageSpecDecl *D);
|
||||
|
@ -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,
|
||||
|
@ -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>;
|
||||
|
@ -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<
|
||||
|
@ -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">;
|
||||
|
@ -75,6 +75,7 @@ enum class SymbolSubKind : uint8_t {
|
||||
AccessorSetter,
|
||||
UsingTypename,
|
||||
UsingValue,
|
||||
UsingEnum,
|
||||
};
|
||||
|
||||
typedef uint16_t SymbolPropertySet;
|
||||
|
@ -5701,6 +5701,7 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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,
|
||||
|
@ -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.
|
||||
|
@ -1339,6 +1339,9 @@ enum DeclCode {
|
||||
/// A UsingDecl record.
|
||||
DECL_USING,
|
||||
|
||||
/// A UsingEnumDecl record.
|
||||
DECL_USING_ENUM,
|
||||
|
||||
/// A UsingPackDecl record.
|
||||
DECL_USING_PACK,
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -784,6 +784,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
||||
|
||||
case Using:
|
||||
case UsingPack:
|
||||
case UsingEnum:
|
||||
return IDNS_Using;
|
||||
|
||||
case ObjCProtocol:
|
||||
|
@ -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,
|
||||
|
@ -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 ";
|
||||
|
@ -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()));
|
||||
}
|
||||
|
@ -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 << ' ';
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -508,6 +508,9 @@ public:
|
||||
/// 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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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 @@ private:
|
||||
};
|
||||
} // 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) ||
|
||||
|
@ -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;
|
||||
|
||||
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 VisitBaseUsingDecls(D, NewUD, nullptr);
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) {
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
30
clang/test/AST/ast-dump-using-enum.cpp
Normal file
30
clang/test/AST/ast-dump-using-enum.cpp
Normal file
@ -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'
|
233
clang/test/SemaCXX/cxx20-using-enum.cpp
Normal file
233
clang/test/SemaCXX/cxx20-using-enum.cpp
Normal file
@ -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
|
@ -6541,6 +6541,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
|
||||
}
|
||||
|
||||
case Decl::Using:
|
||||
case Decl::UsingEnum:
|
||||
return MakeCursorOverloadedDeclRef(cast<BaseUsingDecl>(D), D->getLocation(),
|
||||
TU);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user