Skip to content

Commit

Permalink
[clang] Build UsingType for elaborated type specifiers.
Browse files Browse the repository at this point in the history
Support building UsingType for elaborated type specifiers:

```
namespace ns { class Foo {}; }

using ns::Foo;

// The TypeLoc of `Foo` below should be a ElaboratedTypeLoc with an
// inner UsingTypeLoc rather than the underlying `CXXRecordTypeLoc`
class Foo foo;
```

Differential Revision: https://reviews.llvm.org/D141280
  • Loading branch information
hokein committed Jan 19, 2023
1 parent 1119c15 commit e70ca7b
Show file tree
Hide file tree
Showing 11 changed files with 41 additions and 18 deletions.
3 changes: 3 additions & 0 deletions clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ TEST(WalkAST, Using) {
}
using ns::$explicit^Y;)cpp",
"^Y<int> x;");
testWalk(R"cpp(
namespace ns { class Foo {}; }
)cpp", "using ns::$explicit^Foo; class ^Foo foo;");
}

TEST(WalkAST, Namespaces) {
Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,8 +506,16 @@ class DeclSpec {
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
return TypeRep;
}
// Returns the underlying decl, if any.
Decl *getRepAsDecl() const {
assert(isDeclRep((TST) TypeSpecType) && "DeclSpec does not store a decl");
auto *D = getRepAsFoundDecl();
if (const auto *Using = dyn_cast_or_null<UsingShadowDecl>(D))
return Using->getTargetDecl();
return D;
}
// Returns the originally found decl, if any.
Decl *getRepAsFoundDecl() const {
assert(isDeclRep((TST)TypeSpecType) && "DeclSpec does not store a decl");
return DeclRep;
}
Expr *getRepAsExpr() const {
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -3324,7 +3324,9 @@ class Sema final {
SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
bool IsTypeSpecifier, bool IsTemplateParamOrArg,
OffsetOfKind OOK, SkipBodyInfo *SkipBody = nullptr);
OffsetOfKind OOK,
UsingShadowDecl*& FoundUsingShadow,
SkipBodyInfo *SkipBody = nullptr);

DeclResult ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
unsigned TagSpec, SourceLocation TagLoc,
Expand Down
11 changes: 6 additions & 5 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4965,6 +4965,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool IsDependent = false;
const char *PrevSpec = nullptr;
unsigned DiagID;
UsingShadowDecl* FoundUsing = nullptr;
Decl *TagDecl =
Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS,
Name, NameLoc, attrs, AS, DS.getModulePrivateSpecLoc(),
Expand All @@ -4973,7 +4974,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
BaseType, DSC == DeclSpecContext::DSC_type_specifier,
DSC == DeclSpecContext::DSC_template_param ||
DSC == DeclSpecContext::DSC_template_type_arg,
OffsetOfState, &SkipBody).get();
OffsetOfState, FoundUsing, &SkipBody).get();

if (SkipBody.ShouldSkip) {
assert(TUK == Sema::TUK_Definition && "can only skip a definition");
Expand All @@ -4983,8 +4984,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
T.skipToEnd();

if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
NameLoc.isValid() ? NameLoc : StartLoc,
PrevSpec, DiagID, TagDecl, Owned,
NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
DiagID, FoundUsing ? FoundUsing : TagDecl, Owned,
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
return;
Expand Down Expand Up @@ -5038,8 +5039,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
}

if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
NameLoc.isValid() ? NameLoc : StartLoc,
PrevSpec, DiagID, TagDecl, Owned,
NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
DiagID, FoundUsing ? FoundUsing : TagDecl, Owned,
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
}
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1934,6 +1934,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Create the tag portion of the class or class template.
DeclResult TagOrTempResult = true; // invalid
TypeResult TypeResult = true; // invalid
UsingShadowDecl *FoundUsing = nullptr;

bool Owned = false;
Sema::SkipBodyInfo SkipBody;
Expand Down Expand Up @@ -2074,7 +2075,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
DSC == DeclSpecContext::DSC_type_specifier,
DSC == DeclSpecContext::DSC_template_param ||
DSC == DeclSpecContext::DSC_template_type_arg,
OffsetOfState, &SkipBody);
OffsetOfState, FoundUsing, &SkipBody);

// If ActOnTag said the type was dependent, try again with the
// less common call.
Expand Down Expand Up @@ -2133,7 +2134,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else if (!TagOrTempResult.isInvalid()) {
Result = DS.SetTypeSpecType(
TagType, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
DiagID, TagOrTempResult.get(), Owned, Policy);
DiagID, FoundUsing ? FoundUsing : TagOrTempResult.get(), Owned, Policy);
} else {
DS.SetTypeSpecError();
return;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16592,7 +16592,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
bool &IsDependent, SourceLocation ScopedEnumKWLoc,
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
bool IsTypeSpecifier, bool IsTemplateParamOrArg,
OffsetOfKind OOK, SkipBodyInfo *SkipBody) {
OffsetOfKind OOK, UsingShadowDecl *&FoundUsingShadow,
SkipBodyInfo *SkipBody) {
// If this is not a definition, it must have a name.
IdentifierInfo *OrigName = Name;
assert((Name != nullptr || TUK == TUK_Definition) &&
Expand Down Expand Up @@ -17027,6 +17028,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
// redefinition if either context is within the other.
if (auto *Shadow = dyn_cast<UsingShadowDecl>(DirectPrevDecl)) {
auto *OldTag = dyn_cast<TagDecl>(PrevDecl);
FoundUsingShadow = Shadow;
if (SS.isEmpty() && TUK != TUK_Reference && TUK != TUK_Friend &&
isDeclInScope(Shadow, SearchDC, S, isMemberSpecialization) &&
!(OldTag && isAcceptableTagRedeclContext(
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16972,6 +16972,7 @@ DeclResult Sema::ActOnTemplatedFriendTag(
if (SS.isEmpty()) {
bool Owned = false;
bool IsDependent = false;
UsingShadowDecl* FoundUsing = nullptr;
return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr,
AS_public,
/*ModulePrivateLoc=*/SourceLocation(),
Expand All @@ -16980,7 +16981,7 @@ DeclResult Sema::ActOnTemplatedFriendTag(
/*ScopedEnumUsesClassTag=*/false,
/*UnderlyingType=*/TypeResult(),
/*IsTypeSpecifier=*/false,
/*IsTemplateParamOrArg=*/false, /*OOK=*/OOK_Outside);
/*IsTemplateParamOrArg=*/false, /*OOK=*/OOK_Outside, FoundUsing);
}

NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10181,11 +10181,14 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc,

bool Owned = false;
bool IsDependent = false;
Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name,
NameLoc, Attr, AS_none, /*ModulePrivateLoc=*/SourceLocation(),
UsingShadowDecl* FoundUsing = nullptr;
Decl *TagD =
ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, NameLoc, Attr,
AS_none, /*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(), Owned, IsDependent, SourceLocation(),
false, TypeResult(), /*IsTypeSpecifier*/ false,
/*IsTemplateParamOrArg*/ false, /*OOK=*/OOK_Outside).get();
/*IsTemplateParamOrArg*/ false, /*OOK=*/OOK_Outside, FoundUsing)
.get();
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");

if (!TagD)
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1588,6 +1588,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {

// TypeQuals handled by caller.
Result = Context.getTypeDeclType(D);
if (const auto *Using =
dyn_cast_or_null<UsingShadowDecl>(DS.getRepAsFoundDecl()))
Result = Context.getUsingType(Using, Result);

// In both C and C++, make an ElaboratedType.
ElaboratedTypeKeyword Keyword
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CXX/drs/dr2xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,7 @@ namespace dr284 { // dr284: no
}
struct B::V {}; // expected-error {{no struct named 'V'}}
struct B::W {};
struct B::X {}; // FIXME: ill-formed
struct B::X {}; // expected-error {{forward declaration of struct cannot have}}
enum B::Y e; // ok per dr417
class B::Z z; // ok per dr417

Expand All @@ -1009,7 +1009,7 @@ namespace dr284 { // dr284: no
};
struct D::V {}; // expected-error {{no struct named 'V'}}
struct D::W {};
struct D::X {}; // FIXME: ill-formed
struct D::X {}; // expected-error {{forward declaration of struct cannot have}}
enum D::Y e2; // ok per dr417
class D::Z z2; // ok per dr417
}
Expand Down
3 changes: 1 addition & 2 deletions clang/test/CXX/drs/dr4xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,8 @@ namespace dr417 { // dr417: no
struct F;
struct H;
}
// FIXME: This is ill-formed.
using N::D;
struct dr417::D {}; // expected-warning {{extra qualification}}
struct dr417::D {}; // expected-error {{forward declaration of struct cannot}} expected-warning {{extra qualification}}
using namespace N;
struct dr417::E {}; // expected-warning {{extra qualification}} expected-error {{no struct named 'E'}}
struct N::F {};
Expand Down

0 comments on commit e70ca7b

Please sign in to comment.