DeclRelation::Underlying, Resolver)});
}
+ void VisitUsingEnumDecl(const UsingEnumDecl *D) {
+ // "using enum ns::E" is a non-declaration reference.
+ // The reference is covered by the embedded typeloc.
+ // Don't use the default VisitNamedDecl, which would report a declaration.
+ }
+
void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
// For namespace alias, "namespace Foo = Target;", we add two references.
// Add a declaration reference for Foo.
)cpp",
"0: targets = {ns}\n"
"1: targets = {ns::global}, qualifier = 'ns::'\n"},
+ // Using enum declarations.
+ {R"cpp(
+ namespace ns { enum class A {}; }
+ void foo() {
+ using enum $0^ns::$1^A;
+ }
+ )cpp",
+ "0: targets = {ns}\n"
+ "1: targets = {ns::A}, qualifier = 'ns::'\n"},
// Simple types.
{R"cpp(
struct Struct { int a; };
void func() { [[__^func__]]; }
)cpp",
"PredefinedExpr"},
+
+ // using enum
+ {R"cpp(
+ namespace ns { enum class A {}; };
+ using enum ns::[[^A]];
+ )cpp",
+ "EnumTypeLoc"},
+ {R"cpp(
+ namespace ns { enum class A {}; using B = A; };
+ using enum ns::[[^B]];
+ )cpp",
+ "TypedefTypeLoc"},
+ {R"cpp(
+ namespace ns { enum class A {}; };
+ using enum [[^ns::]]A;
+ )cpp",
+ "NestedNameSpecifierLoc"},
+ {R"cpp(
+ namespace ns { enum class A {}; };
+ [[using ^enum ns::A]];
+ )cpp",
+ "UsingEnumDecl"},
+ {R"cpp(
+ namespace ns { enum class A {}; };
+ [[^using enum ns::A]];
+ )cpp",
+ "UsingEnumDecl"},
};
for (const Case &C : Cases) {
TU.Code = std::string(Test.code());
TU.ExtraArgs.push_back("-xobjective-c++");
+ TU.ExtraArgs.push_back("-std=c++20");
auto AST = TU.build();
auto T = makeSelectionTree(C.Code, AST);
typedef int $Primitive_decl[[MyTypedef]];
enum $Enum_decl[[MyEnum]] : $Primitive[[MyTypedef]] {};
)cpp",
+ // Using enum
+ R"cpp(
+ enum class $Enum_decl[[Color]] { $EnumConstant_decl_readonly[[Black]] };
+ namespace $Namespace_decl[[ns]] {
+ using enum $Enum[[Color]];
+ $Enum[[Color]] $Variable_decl[[ModelT]] = $EnumConstant[[Black]];
+ }
+ )cpp",
// Issue 1096
R"cpp(
void $Function_decl[[Foo]]();
class UsingEnumDecl : public BaseUsingDecl, public Mergeable<UsingEnumDecl> {
/// The source location of the 'using' keyword itself.
SourceLocation UsingLocation;
-
- /// Location of the 'enum' keyword.
+ /// The source location of the 'enum' keyword.
SourceLocation EnumLocation;
-
- /// The enum
- EnumDecl *Enum;
+ /// 'qual::SomeEnum' as an EnumType, possibly with Elaborated/Typedef sugar.
+ TypeSourceInfo *EnumType;
UsingEnumDecl(DeclContext *DC, DeclarationName DN, SourceLocation UL,
- SourceLocation EL, SourceLocation NL, EnumDecl *ED)
- : BaseUsingDecl(UsingEnum, DC, NL, DN), UsingLocation(UL),
- EnumLocation(EL), Enum(ED) {}
+ SourceLocation EL, SourceLocation NL, TypeSourceInfo *EnumType)
+ : BaseUsingDecl(UsingEnum, DC, NL, DN), UsingLocation(UL), EnumLocation(EL),
+ EnumType(EnumType){}
void anchor() override;
/// The source location of the 'enum' keyword.
SourceLocation getEnumLoc() const { return EnumLocation; }
void setEnumLoc(SourceLocation L) { EnumLocation = L; }
+ NestedNameSpecifier *getQualifier() const {
+ return getQualifierLoc().getNestedNameSpecifier();
+ }
+ NestedNameSpecifierLoc getQualifierLoc() const {
+ if (auto ETL = EnumType->getTypeLoc().getAs<ElaboratedTypeLoc>())
+ return ETL.getQualifierLoc();
+ return NestedNameSpecifierLoc();
+ }
+ // Returns the "qualifier::Name" part as a TypeLoc.
+ TypeLoc getEnumTypeLoc() const {
+ return EnumType->getTypeLoc();
+ }
+ TypeSourceInfo *getEnumType() const {
+ return EnumType;
+ }
+ void setEnumType(TypeSourceInfo *TSI) { EnumType = TSI; }
public:
- EnumDecl *getEnumDecl() const { return Enum; }
+ EnumDecl *getEnumDecl() const { return cast<EnumDecl>(EnumType->getType()->getAsTagDecl()); }
static UsingEnumDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation UsingL, SourceLocation EnumL,
- SourceLocation NameL, EnumDecl *ED);
+ SourceLocation NameL, TypeSourceInfo *EnumType);
static UsingEnumDecl *CreateDeserialized(ASTContext &C, unsigned ID);
TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo()));
})
-DEF_TRAVERSE_DECL(UsingEnumDecl, {})
+DEF_TRAVERSE_DECL(UsingEnumDecl,
+ { TRY_TO(TraverseTypeLoc(D->getEnumTypeLoc())); })
DEF_TRAVERSE_DECL(UsingPackDecl, {})
NamedDecl *BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
SourceLocation EnumLoc,
- SourceLocation NameLoc, EnumDecl *ED);
+ SourceLocation NameLoc,
+ TypeSourceInfo *EnumType, EnumDecl *ED);
NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom,
ArrayRef<NamedDecl *> Expansions);
Error Err = Error::success();
auto ToUsingLoc = importChecked(Err, D->getUsingLoc());
auto ToEnumLoc = importChecked(Err, D->getEnumLoc());
- auto ToEnumDecl = importChecked(Err, D->getEnumDecl());
+ auto ToNameLoc = importChecked(Err, D->getLocation());
+ auto *ToEnumType = importChecked(Err, D->getEnumType());
if (Err)
return std::move(Err);
UsingEnumDecl *ToUsingEnum;
if (GetImportedOrCreateDecl(ToUsingEnum, D, Importer.getToContext(), DC,
- ToUsingLoc, ToEnumLoc, Loc, ToEnumDecl))
+ ToUsingLoc, ToEnumLoc, ToNameLoc, ToEnumType))
return ToUsingEnum;
ToUsingEnum->setLexicalDeclContext(LexicalDC);
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);
+ SourceLocation UL,
+ SourceLocation EL,
+ SourceLocation NL,
+ TypeSourceInfo *EnumType) {
+ assert(isa<EnumDecl>(EnumType->getType()->getAsTagDecl()));
+ return new (C, DC)
+ UsingEnumDecl(DC, EnumType->getType()->getAsTagDecl()->getDeclName(), UL, EL, NL, EnumType);
}
UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- return new (C, ID) UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(),
- SourceLocation(), SourceLocation(), nullptr);
+ return new (C, ID)
+ UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(),
+ SourceLocation(), SourceLocation(), nullptr);
}
SourceRange UsingEnumDecl::getSourceRange() const {
- return SourceRange(EnumLocation, getLocation());
+ return SourceRange(UsingLocation, EnumType->getTypeLoc().getEndLoc());
}
void UsingPackDecl::anchor() {}
SourceLocation IdentLoc,
IdentifierInfo &II, CXXScopeSpec *SS) {
assert(!SS->isInvalid() && "ScopeSpec is invalid");
- ParsedType TypeRep = getTypeName(II, IdentLoc, S, SS);
- if (!TypeRep) {
+ TypeSourceInfo *TSI = nullptr;
+ QualType EnumTy = GetTypeFromParser(
+ getTypeName(II, IdentLoc, S, SS, /*isClassName=*/false,
+ /*HasTrailingDot=*/false,
+ /*ObjectType=*/nullptr, /*IsCtorOrDtorName=*/false,
+ /*WantNontrivialTypeSourceInfo=*/true),
+ &TSI);
+ if (EnumTy.isNull()) {
Diag(IdentLoc, SS && isDependentScopeSpecifier(*SS)
? diag::err_using_enum_is_dependent
: diag::err_unknown_typename)
return nullptr;
}
- auto *Enum = dyn_cast_if_present<EnumDecl>(TypeRep.get()->getAsTagDecl());
+ auto *Enum = dyn_cast_if_present<EnumDecl>(EnumTy->getAsTagDecl());
if (!Enum) {
- Diag(IdentLoc, diag::err_using_enum_not_enum) << TypeRep.get();
+ Diag(IdentLoc, diag::err_using_enum_not_enum) << EnumTy;
return nullptr;
}
if (auto *Def = Enum->getDefinition())
Enum = Def;
+ if (TSI == nullptr)
+ TSI = Context.getTrivialTypeSourceInfo(EnumTy, IdentLoc);
+
auto *UD =
- BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, IdentLoc, Enum);
+ BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, IdentLoc, TSI, Enum);
+
if (UD)
PushOnScopeChains(UD, S, /*AddToContext*/ false);
SourceLocation UsingLoc,
SourceLocation EnumLoc,
SourceLocation NameLoc,
+ TypeSourceInfo *EnumType,
EnumDecl *ED) {
bool Invalid = false;
Invalid = true;
UsingEnumDecl *UD = UsingEnumDecl::Create(Context, CurContext, UsingLoc,
- EnumLoc, NameLoc, ED);
+ EnumLoc, NameLoc, EnumType);
UD->setAccess(AS);
CurContext->addDecl(UD);
if (SemaRef.RequireCompleteEnumDecl(EnumD, EnumD->getLocation()))
return nullptr;
+ TypeSourceInfo *TSI = SemaRef.SubstType(D->getEnumType(), TemplateArgs,
+ D->getLocation(), D->getDeclName());
UsingEnumDecl *NewUD =
UsingEnumDecl::Create(SemaRef.Context, Owner, D->getUsingLoc(),
- D->getEnumLoc(), D->getLocation(), EnumD);
+ D->getEnumLoc(), D->getLocation(), TSI);
SemaRef.Context.setInstantiatedFromUsingEnumDecl(NewUD, D);
NewUD->setAccess(D->getAccess());
VisitNamedDecl(D);
D->setUsingLoc(readSourceLocation());
D->setEnumLoc(readSourceLocation());
- D->Enum = readDeclAs<EnumDecl>();
+ D->setEnumType(Record.readTypeSourceInfo());
D->FirstUsingShadow.setPointer(readDeclAs<UsingShadowDecl>());
if (auto *Pattern = readDeclAs<UsingEnumDecl>())
Reader.getContext().setInstantiatedFromUsingEnumDecl(D, Pattern);
VisitNamedDecl(D);
Record.AddSourceLocation(D->getUsingLoc());
Record.AddSourceLocation(D->getEnumLoc());
- Record.AddDeclRef(D->getEnumDecl());
+ Record.AddTypeSourceInfo(D->getEnumType());
Record.AddDeclRef(D->FirstUsingShadow.getPointer());
Record.AddDeclRef(Context.getInstantiatedFromUsingEnumDecl(D));
Code = serialization::DECL_USING_ENUM;
// CHECK-NEXT: `-EnumConstantDecl {{.*}} Foo_b 'Bob::Foo'
// CHECK-LABEL: Dumping Foo:
-// CHECK-NEXT: UsingEnumDecl {{.*}} Enum {{.*}} 'Foo'
+// CHECK-NEXT: UsingEnumDecl {{.*}} <{{.*}}:16:1, col:17> {{.*}} Enum {{.*}} 'Foo'
// CHECK-LABEL: Dumping Foo_a:
// CHECK-NEXT: UsingShadowDecl {{.*}} implicit EnumConstant {{.*}} 'Foo_a' 'Bob::Foo'
TypeLocVisitor::Lang_C));
}
+TEST(RecursiveASTVisitor, VisitsUsingEnumType) {
+ TypeLocVisitor Visitor;
+ Visitor.ExpectMatch("::A", 2, 12);
+ EXPECT_TRUE(Visitor.runOver("enum class A {}; \n"
+ "using enum ::A;\n",
+ TypeLocVisitor::Lang_CXX2a));
+}
+
} // end anonymous namespace