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
/// 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;
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);
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.
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.
///
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);
TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
})
+DEF_TRAVERSE_DECL(UsingEnumDecl, {})
+
DEF_TRAVERSE_DECL(UsingPackDecl, {})
DEF_TRAVERSE_DECL(UsingDirectiveDecl, {
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);
/// 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
/// \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,
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>;
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<
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<
"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">,
// 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">;
AccessorSetter,
UsingTypename,
UsingValue,
+ UsingEnum,
};
typedef uint16_t SymbolPropertySet;
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,
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);
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,
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.
/// A UsingDecl record.
DECL_USING,
+ /// A UsingEnumDecl record.
+ DECL_USING_ENUM,
+
/// A UsingPackDecl record.
DECL_USING_PACK,
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
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);
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;
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) {
case Decl::NamespaceAlias:
case Decl::ParmVar:
case Decl::Using:
+ case Decl::UsingEnum:
case Decl::UsingShadow:
case Decl::UsingDirective:
return LinkageInfo::none();
case Using:
case UsingPack:
+ case UsingEnum:
return IDNS_Using;
case ObjCProtocol:
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,
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);
Out << *D;
}
+void DeclPrinter::VisitUsingEnumDecl(UsingEnumDecl *D) {
+ Out << "using enum " << D->getEnumDecl();
+}
+
void
DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
Out << "using typename ";
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()));
}
OS << D->getDeclName();
}
+void TextNodeDumper::VisitUsingEnumDecl(const UsingEnumDecl *D) {
+ OS << ' ';
+ dumpBareDeclRef(D->getEnumDecl());
+}
+
void TextNodeDumper::VisitUnresolvedUsingTypenameDecl(
const UnresolvedUsingTypenameDecl *D) {
OS << ' ';
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>
REGISTER_MATCHER(userDefinedLiteral);
REGISTER_MATCHER(usesADL);
REGISTER_MATCHER(usingDecl);
+ REGISTER_MATCHER(usingEnumDecl);
REGISTER_MATCHER(usingDirectiveDecl);
REGISTER_MATCHER(valueDecl);
REGISTER_MATCHER(varDecl);
}
}
+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;
/// 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);
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);
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));
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;
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");
}
/// 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);
// 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);
///
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;
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;
}
case Decl::UnresolvedUsingTypename:
return CXCursor_UsingDeclaration;
+ case Decl::UsingEnum:
+ return CXCursor_EnumDecl;
+
case Decl::ObjCPropertyImpl:
switch (cast<ObjCPropertyImplDecl>(D)->getPropertyImplementation()) {
case ObjCPropertyImplDecl::Dynamic:
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:
}
}
- 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);
// 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)) {
};
} // 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
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())
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) ||
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
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);
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);
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) {
case Decl::NonTypeTemplateParm:
case Decl::TemplateTemplateParm:
case Decl::Using:
+ case Decl::UsingEnum:
case Decl::UsingPack:
case Decl::ObjCMethod:
case Decl::ObjCCategory:
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);
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>();
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;
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);
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);
--- /dev/null
+// 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'
--- /dev/null
+// 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
}
case Decl::Using:
+ case Decl::UsingEnum:
return MakeCursorOverloadedDeclRef(cast<BaseUsingDecl>(D), D->getLocation(),
TU);
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
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) {
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;