hokein created this revision. Herald added a subscriber: kadircet. Herald added a project: All. hokein requested review of this revision. Herald added projects: clang, clang-tools-extra.
This is a hacky prototype to 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; It seems to work, and improves some diagnostics. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D141280 Files: clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp clang/include/clang/Sema/DeclSpec.h clang/include/clang/Sema/Sema.h clang/lib/Parse/ParseDecl.cpp clang/lib/Parse/ParseDeclCXX.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaType.cpp clang/test/CXX/drs/dr2xx.cpp clang/test/CXX/drs/dr4xx.cpp clang/test/SemaCXX/using-decl-1.cpp
Index: clang/test/SemaCXX/using-decl-1.cpp =================================================================== --- clang/test/SemaCXX/using-decl-1.cpp +++ clang/test/SemaCXX/using-decl-1.cpp @@ -177,6 +177,10 @@ struct S { friend struct HiddenTag1; // expected-error {{tag type that does not match previous}} +#if __cplusplus < 201103L + // expected-warning@-2 {{befriending enumeration type 'struct HiddenTag1' is a C++11 extension}} +#endif + friend struct HiddenTag2; // expected-note {{conflicting declaration}} friend void HiddenFn1(); // expected-error {{cannot befriend target of using declaration}} friend void HiddenFn2(); // expected-note {{conflicting declaration}} Index: clang/test/CXX/drs/dr4xx.cpp =================================================================== --- clang/test/CXX/drs/dr4xx.cpp +++ clang/test/CXX/drs/dr4xx.cpp @@ -301,9 +301,8 @@ 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 {}; @@ -311,7 +310,7 @@ using N::H; namespace M { struct dr417::G {}; // expected-error {{namespace 'M' does not enclose}} - struct dr417::H {}; // expected-error {{namespace 'M' does not enclose}} + struct dr417::H {}; // expected-error {{namespace 'M' does not enclose}} expected-error {{forward declaration of struct cannot have}} } } Index: clang/test/CXX/drs/dr2xx.cpp =================================================================== --- clang/test/CXX/drs/dr2xx.cpp +++ clang/test/CXX/drs/dr2xx.cpp @@ -992,7 +992,7 @@ } 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 @@ -1009,7 +1009,7 @@ }; 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 } Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -1569,7 +1569,14 @@ case DeclSpec::TST_union: case DeclSpec::TST_struct: case DeclSpec::TST_interface: { - TagDecl *D = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl()); + TagDecl *D = nullptr; + UsingShadowDecl *Using = + dyn_cast_or_null<UsingShadowDecl>(DS.getRepAsOriginDecl()); + if (Using) + D = dyn_cast_or_null<TagDecl>(Using->getTargetDecl()); + else + D = dyn_cast_or_null<TagDecl>(DS.getRepAsOriginDecl()); + if (!D) { // This can happen in C++ with ambiguous lookups. Result = Context.IntTy; @@ -1587,6 +1594,8 @@ // TypeQuals handled by caller. Result = Context.getTypeDeclType(D); + if (Using) + Result = Context.getUsingType(Using, Result); // In both C and C++, make an ElaboratedType. ElaboratedTypeKeyword Keyword Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -6070,7 +6070,6 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { D.setFunctionDefinitionKind(FunctionDefinitionKind::Declaration); - // Check if we are in an `omp begin/end declare variant` scope. Handle this // declaration only if the `bind_to_declaration` extension is set. SmallVector<FunctionDecl *, 4> Bases; @@ -16573,7 +16572,7 @@ SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, bool IsTypeSpecifier, bool IsTemplateParamOrArg, - SkipBodyInfo *SkipBody) { + SkipBodyInfo *SkipBody, UsingShadowDecl** FoundUsingShadow) { // If this is not a definition, it must have a name. IdentifierInfo *OrigName = Name; assert((Name != nullptr || TUK == TUK_Definition) && @@ -17008,6 +17007,8 @@ // redefinition if either context is within the other. if (auto *Shadow = dyn_cast<UsingShadowDecl>(DirectPrevDecl)) { auto *OldTag = dyn_cast<TagDecl>(PrevDecl); + if (FoundUsingShadow) + *FoundUsingShadow = Shadow; if (SS.isEmpty() && TUK != TUK_Reference && TUK != TUK_Friend && isDeclInScope(Shadow, SearchDC, S, isMemberSpecialization) && !(OldTag && isAcceptableTagRedeclContext( Index: clang/lib/Parse/ParseDeclCXX.cpp =================================================================== --- clang/lib/Parse/ParseDeclCXX.cpp +++ clang/lib/Parse/ParseDeclCXX.cpp @@ -1933,6 +1933,7 @@ // Create the tag portion of the class or class template. DeclResult TagOrTempResult = true; // invalid TypeResult TypeResult = true; // invalid + UsingShadowDecl *FoundUsingShadow = nullptr; bool Owned = false; Sema::SkipBodyInfo SkipBody; @@ -2073,7 +2074,7 @@ DSC == DeclSpecContext::DSC_type_specifier, DSC == DeclSpecContext::DSC_template_param || DSC == DeclSpecContext::DSC_template_type_arg, - &SkipBody); + &SkipBody, &FoundUsingShadow); // If ActOnTag said the type was dependent, try again with the // less common call. @@ -2132,7 +2133,7 @@ } else if (!TagOrTempResult.isInvalid()) { Result = DS.SetTypeSpecType( TagType, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec, - DiagID, TagOrTempResult.get(), Owned, Policy); + DiagID, FoundUsingShadow? FoundUsingShadow : TagOrTempResult.get(), Owned, Policy); } else { DS.SetTypeSpecError(); return; Index: clang/lib/Parse/ParseDecl.cpp =================================================================== --- clang/lib/Parse/ParseDecl.cpp +++ clang/lib/Parse/ParseDecl.cpp @@ -4965,6 +4965,7 @@ bool IsDependent = false; const char *PrevSpec = nullptr; unsigned DiagID; + UsingShadowDecl* Using = nullptr; Decl *TagDecl = Actions.ActOnTag( getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, attrs, AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, @@ -4972,7 +4973,7 @@ DSC == DeclSpecContext::DSC_type_specifier, DSC == DeclSpecContext::DSC_template_param || DSC == DeclSpecContext::DSC_template_type_arg, - &SkipBody); + &SkipBody, &Using); if (SkipBody.ShouldSkip) { assert(TUK == Sema::TUK_Definition && "can only skip a definition"); @@ -4983,7 +4984,7 @@ if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, - PrevSpec, DiagID, TagDecl, Owned, + PrevSpec, DiagID, Using? Using : TagDecl, Owned, Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; return; @@ -5038,7 +5039,7 @@ if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, - PrevSpec, DiagID, TagDecl, Owned, + PrevSpec, DiagID, Using ? Using : TagDecl, Owned, Actions.getASTContext().getPrintingPolicy())) Diag(StartLoc, DiagID) << PrevSpec; } Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -3312,7 +3312,8 @@ bool &IsDependent, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, bool IsTypeSpecifier, bool IsTemplateParamOrArg, - SkipBodyInfo *SkipBody = nullptr); + SkipBodyInfo *SkipBody = nullptr, + UsingShadowDecl** FoundUsingShadow = nullptr); Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, Index: clang/include/clang/Sema/DeclSpec.h =================================================================== --- clang/include/clang/Sema/DeclSpec.h +++ clang/include/clang/Sema/DeclSpec.h @@ -34,6 +34,7 @@ #include "clang/Sema/ParsedAttr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" @@ -507,7 +508,13 @@ return TypeRep; } Decl *getRepAsDecl() const { - assert(isDeclRep((TST) TypeSpecType) && "DeclSpec does not store a decl"); + auto *D = getRepAsOriginDecl(); + if (const auto *Using = llvm::dyn_cast_or_null<UsingShadowDecl>(D)) + return Using->getTargetDecl(); + return D; + } + Decl *getRepAsOriginDecl() const { + assert(isDeclRep((TST)TypeSpecType) && "DeclSpec does not store a decl"); return DeclRep; } Expr *getRepAsExpr() const { Index: clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp =================================================================== --- clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -150,6 +150,9 @@ } 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) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits