sammccall updated this revision to Diff 394648. sammccall added a comment. Fix QualTypeNames bug that showed up in external testing. (Now covered by a unittest added separately)
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D114251/new/ https://reviews.llvm.org/D114251 Files: clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp clang-tools-extra/clangd/FindTarget.cpp clang-tools-extra/clangd/IncludeCleaner.cpp clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp clang-tools-extra/clangd/unittests/XRefsTests.cpp clang/docs/ReleaseNotes.rst clang/include/clang/AST/ASTContext.h clang/include/clang/AST/PropertiesBase.td clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/AST/Type.h clang/include/clang/AST/TypeLoc.h clang/include/clang/AST/TypeProperties.td clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/include/clang/Basic/TypeNodes.td clang/include/clang/Serialization/TypeBitCodes.def clang/lib/AST/ASTContext.cpp clang/lib/AST/ASTDiagnostic.cpp clang/lib/AST/ASTStructuralEquivalence.cpp clang/lib/AST/ItaniumMangle.cpp clang/lib/AST/QualTypeNames.cpp clang/lib/AST/Type.cpp clang/lib/AST/TypePrinter.cpp clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/lib/CodeGen/CGDebugInfo.cpp clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/Sema/SemaCXXScopeSpec.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTWriter.cpp clang/test/AST/ast-dump-using.cpp clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp clang/test/SemaCXX/warn-enum-compare.cpp clang/tools/libclang/CIndex.cpp clang/unittests/Tooling/StencilTest.cpp lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp =================================================================== --- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -2581,6 +2581,7 @@ case clang::Type::Typedef: case clang::Type::TypeOf: case clang::Type::TypeOfExpr: + case clang::Type::Using: type = type->getLocallyUnqualifiedSingleStepDesugaredType(); break; default: @@ -4063,6 +4064,7 @@ case clang::Type::Paren: case clang::Type::TypeOf: case clang::Type::TypeOfExpr: + case clang::Type::Using: llvm_unreachable("Handled in RemoveWrappingTypes!"); case clang::Type::UnaryTransform: break; @@ -4722,6 +4724,7 @@ case clang::Type::Typedef: case clang::Type::TypeOf: case clang::Type::TypeOfExpr: + case clang::Type::Using: llvm_unreachable("Handled in RemoveWrappingTypes!"); case clang::Type::UnaryTransform: @@ -5104,6 +5107,7 @@ case clang::Type::Typedef: case clang::Type::TypeOf: case clang::Type::TypeOfExpr: + case clang::Type::Using: llvm_unreachable("Handled in RemoveWrappingTypes!"); case clang::Type::UnaryTransform: break; Index: clang/unittests/Tooling/StencilTest.cpp =================================================================== --- clang/unittests/Tooling/StencilTest.cpp +++ clang/unittests/Tooling/StencilTest.cpp @@ -559,7 +559,7 @@ TEST_F(StencilTest, DescribeUnqualifiedType) { std::string Snippet = "using N::C; C c; c;"; - std::string Expected = "N::C"; + std::string Expected = "C"; auto StmtMatch = matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type")))); ASSERT_TRUE(StmtMatch); Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -1666,6 +1666,8 @@ return Visit(TL.getPointeeLoc()); } +bool CursorVisitor::VisitUsingTypeLoc(UsingTypeLoc TL) { return false; } + bool CursorVisitor::VisitAttributedTypeLoc(AttributedTypeLoc TL) { return Visit(TL.getModifiedLoc()); } Index: clang/test/SemaCXX/warn-enum-compare.cpp =================================================================== --- clang/test/SemaCXX/warn-enum-compare.cpp +++ clang/test/SemaCXX/warn-enum-compare.cpp @@ -78,15 +78,15 @@ while (B1 == B2); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}} while (name1::B2 == name2::B3); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}} - while (z == name2::B2); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}} + while (z == name2::B2); // expected-warning {{comparison of different enumeration types ('Baz' and 'name2::Baz')}} while (((((B1)))) == B2); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}} while (name1::B2 == (name2::B3)); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}} - while (z == ((((name2::B2))))); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}} + while (z == ((((name2::B2))))); // expected-warning {{comparison of different enumeration types ('Baz' and 'name2::Baz')}} while ((((B1))) == (((B2)))); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}} while ((name1::B2) == (((name2::B3)))); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}} - while ((((z))) == (name2::B2)); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'name2::Baz')}} + while ((((z))) == (name2::B2)); // expected-warning {{comparison of different enumeration types ('Baz' and 'name2::Baz')}} while (x == a); // expected-warning {{comparison of different enumeration types ('Foo' and 'name1::Foo')}} while (x == b); // expected-warning {{comparison of different enumeration types ('Foo' and 'oneFoo' (aka 'name1::Foo'))}} @@ -229,14 +229,14 @@ while (td == c); // expected-warning {{comparison of different enumeration types ('TD' and 'twoFoo' (aka 'name1::Foo'))}} while (td == x); // expected-warning {{comparison of different enumeration types ('TD' and 'Foo')}} while (td == y); // expected-warning {{comparison of different enumeration types ('TD' and 'Bar')}} - while (td == z); // expected-warning {{comparison of different enumeration types ('TD' and 'name1::Baz')}} + while (td == z); // expected-warning {{comparison of different enumeration types ('TD' and 'Baz')}} while (a == TD1); // expected-warning {{comparison of different enumeration types ('name1::Foo' and 'TD')}} while (b == TD2); // expected-warning {{comparison of different enumeration types ('oneFoo' (aka 'name1::Foo') and 'TD')}} while (c == TD1); // expected-warning {{comparison of different enumeration types ('twoFoo' (aka 'name1::Foo') and 'TD')}} while (x == TD2); // expected-warning {{comparison of different enumeration types ('Foo' and 'TD')}} while (y == TD1); // expected-warning {{comparison of different enumeration types ('Bar' and 'TD')}} - while (z == TD2); // expected-warning {{comparison of different enumeration types ('name1::Baz' and 'TD')}} + while (z == TD2); // expected-warning {{comparison of different enumeration types ('Baz' and 'TD')}} switch (a) { case name1::F1: break; Index: clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp =================================================================== --- clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp +++ clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp @@ -103,7 +103,7 @@ for (auto *a : A()) { // expected-error {{variable 'a' with type 'auto *' has incompatible initializer of type 'int'}} } // : is not a typo for :: here. - for (A NS:A()) { // expected-error {{no viable conversion from 'int' to 'X::A'}} + for (A NS:A()) { // expected-error {{no viable conversion from 'int' to 'A'}} } for (auto not_in_scope : not_in_scope) { // expected-error {{use of undeclared identifier 'not_in_scope'}} } Index: clang/test/AST/ast-dump-using.cpp =================================================================== --- /dev/null +++ clang/test/AST/ast-dump-using.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ast-dump %s | FileCheck -strict-whitespace %s + +namespace a { +struct S; +} +namespace b { +using a::S; +// CHECK: UsingDecl {{.*}} a::S +// CHECK-NEXT: UsingShadowDecl {{.*}} implicit CXXRecord {{.*}} 'S' +// CHECK-NEXT: `-RecordType {{.*}} 'a::S' +typedef S f; // to dump the introduced type +// CHECK: TypedefDecl +// CHECK-NEXT `-UsingType {{.*}} 'b::S' sugar +// CHECK-NEXT `-RecordType {{.*}} 'a::S' +} Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -396,6 +396,8 @@ Record.AddSourceLocation(TL.getNameLoc()); } +void TypeLocWriter::VisitUsingTypeLoc(UsingTypeLoc TL) {} + void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); } Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -6607,6 +6607,8 @@ TL.setNameLoc(readSourceLocation()); } +void TypeLocReader::VisitUsingTypeLoc(UsingTypeLoc TL) {} + void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -933,6 +933,11 @@ /// the UnresolvedUsingTypenameDecl was transformed to. QualType RebuildUnresolvedUsingType(SourceLocation NameLoc, Decl *D); + /// Build a new type found via an alias. + QualType RebuildUsingType(UsingShadowDecl *Found, QualType Underlying) { + return SemaRef.Context.getUsingType(Found, Underlying); + } + /// Build a new typedef type. QualType RebuildTypedefType(TypedefNameDecl *Typedef) { return SemaRef.Context.getTypeDeclType(Typedef); @@ -6072,9 +6077,9 @@ return Result; } -template<typename Derived> QualType -TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB, - UnresolvedUsingTypeLoc TL) { +template <typename Derived> +QualType TreeTransform<Derived>::TransformUnresolvedUsingType( + TypeLocBuilder &TLB, UnresolvedUsingTypeLoc TL) { const UnresolvedUsingType *T = TL.getTypePtr(); Decl *D = getDerived().TransformDecl(TL.getNameLoc(), T->getDecl()); if (!D) @@ -6095,6 +6100,32 @@ return Result; } +template <typename Derived> +QualType TreeTransform<Derived>::TransformUsingType(TypeLocBuilder &TLB, + UsingTypeLoc TL) { + const UsingType *T = TL.getTypePtr(); + + auto *Found = cast_or_null<UsingShadowDecl>(getDerived().TransformDecl( + TL.getLocalSourceRange().getBegin(), T->getFoundDecl())); + if (!Found) + return QualType(); + + QualType Underlying = getDerived().TransformType(T->desugar()); + if (Underlying.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || Found != T->getFoundDecl() || + Underlying != T->getUnderlyingType()) { + Result = getDerived().RebuildUsingType(Found, Underlying); + if (Result.isNull()) + return QualType(); + } + + TLB.pushTypeSpec(Result).setNameLoc(TL.getNameLoc()); + return Result; +} + template<typename Derived> QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { @@ -14462,7 +14493,6 @@ if (D->isInvalidDecl()) return QualType(); // FIXME: Doesn't account for ObjCInterfaceDecl! - TypeDecl *Ty; if (auto *UPD = dyn_cast<UsingPackDecl>(D)) { // A valid resolved using typename pack expansion decl can have multiple // UsingDecls, but they must each have exactly one type, and it must be @@ -14498,17 +14528,18 @@ // A valid resolved using typename decl points to exactly one type decl. assert(++Using->shadow_begin() == Using->shadow_end()); - NamedDecl *Target = Using->shadow_begin()->getTargetDecl(); - if (SemaRef.DiagnoseUseOfDecl(Target, Loc)) + UsingShadowDecl *Shadow = *Using->shadow_begin(); + if (SemaRef.DiagnoseUseOfDecl(Shadow->getTargetDecl(), Loc)) return QualType(); - Ty = cast<TypeDecl>(Target); + return SemaRef.Context.getUsingType( + Shadow, SemaRef.Context.getTypeDeclType( + cast<TypeDecl>(Shadow->getTargetDecl()))); } else { assert(isa<UnresolvedUsingTypenameDecl>(D) && "UnresolvedUsingTypenameDecl transformed to non-using decl"); - Ty = cast<UnresolvedUsingTypenameDecl>(D); + return SemaRef.Context.getTypeDeclType( + cast<UnresolvedUsingTypenameDecl>(D)); } - - return SemaRef.Context.getTypeDeclType(Ty); } template <typename Derived> Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -4443,6 +4443,9 @@ case Type::Decltype: T = cast<DecltypeType>(Ty)->desugar(); break; + case Type::Using: + T = cast<UsingType>(Ty)->desugar(); + break; case Type::Auto: case Type::DeducedTemplateSpecialization: T = cast<DeducedType>(Ty)->getDeducedType(); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -372,6 +372,7 @@ } NamedDecl *IIDecl = nullptr; + UsingShadowDecl *FoundUsingShadow = nullptr; switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: @@ -441,8 +442,10 @@ (AllowDeducedTemplate && getAsTypeTemplateDecl(RealRes))) { if (!IIDecl || // Make the selection of the recovery decl deterministic. - RealRes->getLocation() < IIDecl->getLocation()) + RealRes->getLocation() < IIDecl->getLocation()) { IIDecl = RealRes; + FoundUsingShadow = dyn_cast<UsingShadowDecl>(*Res); + } } } @@ -465,6 +468,7 @@ case LookupResult::Found: IIDecl = Result.getFoundDecl(); + FoundUsingShadow = dyn_cast<UsingShadowDecl>(*Result.begin()); break; } @@ -491,14 +495,20 @@ (void)DiagnoseUseOfDecl(IDecl, NameLoc); if (!HasTrailingDot) T = Context.getObjCInterfaceType(IDecl); + FoundUsingShadow = nullptr; // FIXME: Target must be a TypeDecl. } else if (auto *UD = dyn_cast<UnresolvedUsingIfExistsDecl>(IIDecl)) { (void)DiagnoseUseOfDecl(UD, NameLoc); // Recover with 'int' T = Context.IntTy; + FoundUsingShadow = nullptr; } else if (AllowDeducedTemplate) { - if (auto *TD = getAsTypeTemplateDecl(IIDecl)) + if (auto *TD = getAsTypeTemplateDecl(IIDecl)) { + // FIXME: TemplateName should include FoundUsingShadow sugar. T = Context.getDeducedTemplateSpecializationType(TemplateName(TD), QualType(), false); + // Don't wrap in a further UsingType. + FoundUsingShadow = nullptr; + } } if (T.isNull()) { @@ -507,6 +517,9 @@ return nullptr; } + if (FoundUsingShadow) + T = Context.getUsingType(FoundUsingShadow, T); + // NOTE: avoid constructing an ElaboratedType(Loc) if this is a // constructor or destructor name (in such a case, the scope specifier // will be attached to the enclosing Expr or Decl node). @@ -843,21 +856,6 @@ return false; } -/// Build a ParsedType for a simple-type-specifier with a nested-name-specifier. -static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS, - QualType T, SourceLocation NameLoc) { - ASTContext &Context = S.Context; - - TypeLocBuilder Builder; - Builder.pushTypeSpec(T).setNameLoc(NameLoc); - - T = S.getElaboratedType(ETK_None, SS, T); - ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T); - ElabTL.setElaboratedKeywordLoc(SourceLocation()); - ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); - return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); -} - Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, @@ -1134,14 +1132,28 @@ : NameClassification::TypeTemplate(Template); } + auto BuildTypeFor = [&](TypeDecl *Type, NamedDecl *Found) { + QualType T = Context.getTypeDeclType(Type); + if (const auto *USD = dyn_cast<UsingShadowDecl>(Found)) + T = Context.getUsingType(USD, T); + + if (SS.isEmpty()) // No elaborated type, trivial location info + return ParsedType::make(T); + + TypeLocBuilder Builder; + Builder.pushTypeSpec(T).setNameLoc(NameLoc); + T = getElaboratedType(ETK_None, SS, T); + ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T); + ElabTL.setElaboratedKeywordLoc(SourceLocation()); + ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); + return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); + }; + NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl(); if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) { DiagnoseUseOfDecl(Type, NameLoc); MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); - QualType T = Context.getTypeDeclType(Type); - if (SS.isNotEmpty()) - return buildNestedType(*this, SS, T, NameLoc); - return ParsedType::make(T); + return BuildTypeFor(Type, *Result.begin()); } ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(FirstDecl); @@ -1190,10 +1202,7 @@ isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) { TypeDecl *Type = Result.getAsSingle<TypeDecl>(); DiagnoseUseOfDecl(Type, NameLoc); - QualType T = Context.getTypeDeclType(Type); - if (SS.isNotEmpty()) - return buildNestedType(*this, SS, T, NameLoc); - return ParsedType::make(T); + return BuildTypeFor(Type, *Result.begin()); } // If we already know which single declaration is referenced, just annotate Index: clang/lib/Sema/SemaCXXScopeSpec.cpp =================================================================== --- clang/lib/Sema/SemaCXXScopeSpec.cpp +++ clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -736,8 +736,15 @@ QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD->getUnderlyingDecl())); + + if (T->isEnumeralType()) + Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); + TypeLocBuilder TLB; - if (isa<InjectedClassNameType>(T)) { + if (const auto *USD = dyn_cast<UsingShadowDecl>(SD)) { + T = Context.getUsingType(USD, T); + TLB.pushTypeSpec(T).setNameLoc(IdInfo.IdentifierLoc); + } else if (isa<InjectedClassNameType>(T)) { InjectedClassNameTypeLoc InjectedTL = TLB.push<InjectedClassNameTypeLoc>(T); InjectedTL.setNameLoc(IdInfo.IdentifierLoc); @@ -770,9 +777,6 @@ llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier"); } - if (T->isEnumeralType()) - Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); - SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T), IdInfo.CCLoc); return false; Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -2202,6 +2202,7 @@ case Type::Record: case Type::Enum: case Type::Elaborated: + case Type::Using: case Type::TemplateSpecialization: case Type::ObjCTypeParam: case Type::ObjCObject: Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -3353,6 +3353,9 @@ case Type::Elaborated: T = cast<ElaboratedType>(T)->getNamedType(); break; + case Type::Using: + T = cast<UsingType>(T)->getUnderlyingType(); + break; case Type::Paren: T = cast<ParenType>(T)->getInnerType(); break; @@ -3545,6 +3548,7 @@ case Type::Decayed: case Type::DeducedTemplateSpecialization: case Type::Elaborated: + case Type::Using: case Type::Paren: case Type::MacroQualified: case Type::SubstTemplateTypeParm: Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -228,6 +228,7 @@ REGISTER_MATCHER(eachOf); REGISTER_MATCHER(elaboratedType); REGISTER_MATCHER(elaboratedTypeLoc); + REGISTER_MATCHER(usingType); REGISTER_MATCHER(enumConstantDecl); REGISTER_MATCHER(enumDecl); REGISTER_MATCHER(enumType); Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -1059,6 +1059,7 @@ const AstTypeMatcher<RecordType> recordType; const AstTypeMatcher<TagType> tagType; const AstTypeMatcher<ElaboratedType> elaboratedType; +const AstTypeMatcher<UsingType> usingType; const AstTypeMatcher<SubstTemplateTypeParmType> substTemplateTypeParmType; const AstTypeMatcher<TemplateTypeParmType> templateTypeParmType; const AstTypeMatcher<InjectedClassNameType> injectedClassNameType; Index: clang/lib/AST/TypePrinter.cpp =================================================================== --- clang/lib/AST/TypePrinter.cpp +++ clang/lib/AST/TypePrinter.cpp @@ -212,6 +212,7 @@ case Type::Builtin: case Type::Complex: case Type::UnresolvedUsing: + case Type::Using: case Type::Typedef: case Type::TypeOfExpr: case Type::TypeOf: @@ -1046,6 +1047,12 @@ void TypePrinter::printUnresolvedUsingAfter(const UnresolvedUsingType *T, raw_ostream &OS) {} +void TypePrinter::printUsingBefore(const UsingType *T, raw_ostream &OS) { + printTypeSpec(T->getFoundDecl(), OS); +} + +void TypePrinter::printUsingAfter(const UsingType *T, raw_ostream &OS) {} + void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) { printTypeSpec(T->getDecl(), OS); } Index: clang/lib/AST/Type.cpp =================================================================== --- clang/lib/AST/Type.cpp +++ clang/lib/AST/Type.cpp @@ -3407,6 +3407,17 @@ return getDecl()->getUnderlyingType(); } +UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying, + QualType Canon) + : Type(Using, Canon, Underlying->getDependence()), + Found(const_cast<UsingShadowDecl *>(Found)) { + assert(Underlying == getUnderlyingType()); +} + +QualType UsingType::getUnderlyingType() const { + return QualType(cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(), 0); +} + QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); } QualType MacroQualifiedType::getModifiedType() const { Index: clang/lib/AST/QualTypeNames.cpp =================================================================== --- clang/lib/AST/QualTypeNames.cpp +++ clang/lib/AST/QualTypeNames.cpp @@ -418,6 +418,13 @@ return QT; } + // We don't consider the alias introduced by `using a::X` as a new type. + // The qualified name is still a::X. + if (auto *UT = dyn_cast<UsingType>(QT.getTypePtr())) { + return getFullyQualifiedType(UT->getUnderlyingType(), Ctx, + WithGlobalNsPrefix); + } + // Remove the part of the type related to the type being a template // parameter (we won't report it as part of the 'type name' and it // is actually make the code below to be more complex (to handle Index: clang/lib/AST/ItaniumMangle.cpp =================================================================== --- clang/lib/AST/ItaniumMangle.cpp +++ clang/lib/AST/ItaniumMangle.cpp @@ -2380,6 +2380,9 @@ break; } + case Type::Using: + return mangleUnresolvedTypeOrSimpleId(cast<UsingType>(Ty)->desugar(), + Prefix); case Type::Elaborated: return mangleUnresolvedTypeOrSimpleId( cast<ElaboratedType>(Ty)->getNamedType(), Prefix); Index: clang/lib/AST/ASTStructuralEquivalence.cpp =================================================================== --- clang/lib/AST/ASTStructuralEquivalence.cpp +++ clang/lib/AST/ASTStructuralEquivalence.cpp @@ -945,6 +945,12 @@ return false; break; + case Type::Using: + if (!IsStructurallyEquivalent(Context, cast<UsingType>(T1)->getFoundDecl(), + cast<UsingType>(T2)->getFoundDecl())) + return false; + break; + case Type::Typedef: if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(), cast<TypedefType>(T2)->getDecl())) Index: clang/lib/AST/ASTDiagnostic.cpp =================================================================== --- clang/lib/AST/ASTDiagnostic.cpp +++ clang/lib/AST/ASTDiagnostic.cpp @@ -38,6 +38,11 @@ QT = ET->desugar(); continue; } + // ... or a using type ... + if (const UsingType *UT = dyn_cast<UsingType>(Ty)) { + QT = UT->desugar(); + continue; + } // ... or a paren type ... if (const ParenType *PT = dyn_cast<ParenType>(Ty)) { QT = PT->desugar(); Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -2349,6 +2349,9 @@ case Type::ObjCTypeParam: return getTypeInfo(cast<ObjCTypeParamType>(T)->desugar().getTypePtr()); + case Type::Using: + return getTypeInfo(cast<UsingType>(T)->desugar().getTypePtr()); + case Type::Typedef: { const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl(); TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); @@ -4593,6 +4596,27 @@ return QualType(newType, 0); } +QualType ASTContext::getUsingType(const UsingShadowDecl *Found, + QualType Underlying) const { + llvm::FoldingSetNodeID ID; + UsingType::Profile(ID, Found); + + void *InsertPos = nullptr; + UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + assert(!Underlying.hasQualifiers()); + assert(Underlying == getTypeDeclType(cast<TypeDecl>(Found->getTargetDecl()))); + QualType Canon = Underlying.getCanonicalType(); + + UsingType *NewType = + new (*this, TypeAlignment) UsingType(Found, Underlying, Canon); + Types.push_back(NewType); + UsingTypes.InsertNode(NewType, InsertPos); + return QualType(NewType, 0); +} + QualType ASTContext::getRecordType(const RecordDecl *Decl) const { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); Index: clang/include/clang/Serialization/TypeBitCodes.def =================================================================== --- clang/include/clang/Serialization/TypeBitCodes.def +++ clang/include/clang/Serialization/TypeBitCodes.def @@ -62,5 +62,6 @@ TYPE_BIT_CODE(DependentBitInt, DEPENDENT_BIT_INT, 51) TYPE_BIT_CODE(ConstantMatrix, CONSTANT_MATRIX, 52) TYPE_BIT_CODE(DependentSizedMatrix, DEPENDENT_SIZE_MATRIX, 53) +TYPE_BIT_CODE(Using, USING, 54) #undef TYPE_BIT_CODE Index: clang/include/clang/Basic/TypeNodes.td =================================================================== --- clang/include/clang/Basic/TypeNodes.td +++ clang/include/clang/Basic/TypeNodes.td @@ -75,6 +75,7 @@ def FunctionType : TypeNode<Type, 1>; def FunctionProtoType : TypeNode<FunctionType>; def FunctionNoProtoType : TypeNode<FunctionType>; +def UsingType : TypeNode<Type>, NeverCanonical; def UnresolvedUsingType : TypeNode<Type>, AlwaysDependent; def ParenType : TypeNode<Type>, NeverCanonical; def TypedefType : TypeNode<Type>, NeverCanonical; Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1049,6 +1049,9 @@ if (const auto *S = dyn_cast<UnresolvedUsingType>(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } + if (const auto *S = dyn_cast<UsingType>(&Node)) { + return matchesDecl(S->getFoundDecl(), Finder, Builder); + } if (const auto *S = dyn_cast<ObjCObjectType>(&Node)) { return matchesDecl(S->getInterface(), Finder, Builder); } @@ -1221,7 +1224,7 @@ ElaboratedType, InjectedClassNameType, LabelStmt, AddrLabelExpr, MemberExpr, QualType, RecordType, TagType, TemplateSpecializationType, TemplateTypeParmType, TypedefType, - UnresolvedUsingType, ObjCIvarRefExpr>; + UnresolvedUsingType, UsingType, ObjCIvarRefExpr>; /// A Matcher that allows binding the node it matches to an id. /// Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -3535,6 +3535,7 @@ /// - for CXXConstructExpr, the declaration of the constructor /// - for CXXNewExpr, the declaration of the operator new /// - for ObjCIvarExpr, the declaration of the ivar +/// - for UsingType, the UsingShadowDecl aliasing the type's declaration /// /// For type nodes, hasDeclaration will generally match the declaration of the /// sugared type. Given @@ -3558,7 +3559,7 @@ /// Matcher<MemberExpr>, Matcher<QualType>, Matcher<RecordType>, /// Matcher<TagType>, Matcher<TemplateSpecializationType>, /// Matcher<TemplateTypeParmType>, Matcher<TypedefType>, -/// Matcher<UnresolvedUsingType> +/// Matcher<UnresolvedUsingType>, Matcher<UsingType> inline internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher<Decl>> @@ -6843,7 +6844,7 @@ AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType, AST_POLYMORPHIC_SUPPORTED_TYPES(AutoType)); -/// Matches \c DecltypeType nodes to find out the underlying type. +/// Matches \c DecltypeType or \c UsingType nodes to find the underlying type. /// /// Given /// \code @@ -6853,9 +6854,10 @@ /// decltypeType(hasUnderlyingType(isInteger())) /// matches the type of "a" /// -/// Usable as: Matcher<DecltypeType> +/// Usable as: Matcher<DecltypeType>, Matcher<UsingType> AST_TYPE_TRAVERSE_MATCHER(hasUnderlyingType, getUnderlyingType, - AST_POLYMORPHIC_SUPPORTED_TYPES(DecltypeType)); + AST_POLYMORPHIC_SUPPORTED_TYPES(DecltypeType, + UsingType)); /// Matches \c FunctionType nodes. /// @@ -7183,6 +7185,18 @@ return InnerMatcher.matches(Node.getNamedType(), Finder, Builder); } +/// Matches types specified through a using declaration. +/// +/// Given +/// \code +/// namespace a { struct S {}; } +/// using a::S; +/// S s; +/// \endcode +/// +/// \c usingType() matches the type of the variable declaration of \c s. +extern const AstTypeMatcher<UsingType> usingType; + /// Matches types that represent the result of substituting a type for a /// template type parameter. /// Index: clang/include/clang/AST/TypeProperties.td =================================================================== --- clang/include/clang/AST/TypeProperties.td +++ clang/include/clang/AST/TypeProperties.td @@ -362,6 +362,19 @@ }]>; } +let Class = UsingType in { + def : Property<"foundDeclaration", UsingShadowDeclRef> { + let Read = [{ node->getFoundDecl() }]; + } + def : Property<"underlyingType", QualType> { + let Read = [{ node->getUnderlyingType() }]; + } + + def : Creator<[{ + return ctx.getUsingType(foundDeclaration, underlyingType); + }]>; +} + let Class = TypedefType in { def : Property<"declaration", DeclRef> { let Read = [{ node->getDecl() }]; Index: clang/include/clang/AST/TypeLoc.h =================================================================== --- clang/include/clang/AST/TypeLoc.h +++ clang/include/clang/AST/TypeLoc.h @@ -665,6 +665,16 @@ } }; +/// Wrapper for source info for types used via transparent aliases. +class UsingTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + UsingTypeLoc, UsingType> { +public: + QualType getUnderlyingType() const { + return getTypePtr()->getUnderlyingType(); + } + UsingShadowDecl *getFoundDecl() const { return getTypePtr()->getFoundDecl(); } +}; + /// Wrapper for source info for typedefs. class TypedefTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, TypedefTypeLoc, Index: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -129,6 +129,7 @@ class TemplateTypeParmDecl; class TypedefNameDecl; class UnresolvedUsingTypenameDecl; +class UsingShadowDecl; using CanQualType = CanQual<Type>; @@ -4368,6 +4369,27 @@ } }; +class UsingType : public Type, public llvm::FoldingSetNode { + UsingShadowDecl *Found; + friend class ASTContext; // ASTContext creates these. + + UsingType(const UsingShadowDecl *Found, QualType Underlying, QualType Canon); + +public: + UsingShadowDecl *getFoundDecl() const { return Found; } + QualType getUnderlyingType() const; + + bool isSugared() const { return true; } + QualType desugar() const { return getUnderlyingType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Found); } + static void Profile(llvm::FoldingSetNodeID &ID, + const UsingShadowDecl *Found) { + ID.AddPointer(Found); + } + static bool classof(const Type *T) { return T->getTypeClass() == Using; } +}; + class TypedefType : public Type { TypedefNameDecl *Decl; Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -981,6 +981,7 @@ TRY_TO(TraverseStmt(NE)); }) +DEF_TRAVERSE_TYPE(UsingType, {}) DEF_TRAVERSE_TYPE(UnresolvedUsingType, {}) DEF_TRAVERSE_TYPE(TypedefType, {}) @@ -1252,6 +1253,7 @@ TRY_TO(TraverseStmt(NE)); }) +DEF_TRAVERSE_TYPELOC(UsingType, {}) DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {}) DEF_TRAVERSE_TYPELOC(TypedefType, {}) @@ -2095,7 +2097,13 @@ } if (VisitBody) { - TRY_TO(TraverseStmt(D->getBody())); // Function body. + TRY_TO(TraverseStmt(D->getBody())); + // Body may contain using declarations whose shadows are parented to the + // FunctionDecl itself. + for (auto *Child : D->decls()) { + if (isa<UsingShadowDecl>(Child)) + TRY_TO(TraverseDecl(Child)); + } } return true; } Index: clang/include/clang/AST/PropertiesBase.td =================================================================== --- clang/include/clang/AST/PropertiesBase.td +++ clang/include/clang/AST/PropertiesBase.td @@ -107,6 +107,8 @@ SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>; def TemplateTemplateParmDeclRef : SubclassPropertyType<"TemplateTemplateParmDecl", DeclRef>; + def UsingShadowDeclRef : + SubclassPropertyType<"UsingShadowDecl", DeclRef>; def ValueDeclRef : SubclassPropertyType<"ValueDecl", DeclRef>; def ElaboratedTypeKeyword : EnumPropertyType; Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -248,6 +248,7 @@ mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&> TemplateSpecializationTypes; mutable llvm::FoldingSet<ParenType> ParenTypes; + mutable llvm::FoldingSet<UsingType> UsingTypes; mutable llvm::FoldingSet<ElaboratedType> ElaboratedTypes; mutable llvm::FoldingSet<DependentNameType> DependentNameTypes; mutable llvm::ContextualFoldingSet<DependentTemplateSpecializationType, @@ -1555,6 +1556,9 @@ return getTypeDeclTypeSlow(Decl); } + QualType getUsingType(const UsingShadowDecl *Found, + QualType Underlying) const; + /// Return the unique reference to the type for the specified /// typedef-name decl. QualType getTypedefType(const TypedefNameDecl *Decl, Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -244,7 +244,9 @@ Internal API Changes -------------------- -- ... +- A new sugar ``Type`` AST node represents types accessed via a C++ using + declaration. Given code ``using std::error_code; error_code x;``, ``x`` has + a ``UsingType`` which desugars to the previous ``RecordType``. Build System Changes -------------------- @@ -269,6 +271,10 @@ - The ``hasAnyCapture`` matcher now only accepts an inner matcher of type ``Matcher<LambdaCapture>``. The matcher originally accepted an inner matcher of type ``Matcher<CXXThisExpr>`` or ``Matcher<VarDecl>``. +- The ``usingType`` matcher is now available and needed to refer to types that + are referred to via using C++ using declarations. + The associated ``UsingShadowDecl`` can be matched using ``hasDeclaration`` + and the underlying ``Type`` with ``hasUnderlyingType``. clang-format ------------ Index: clang-tools-extra/clangd/unittests/XRefsTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -1372,7 +1372,7 @@ R"cpp( namespace ns { class [[Foo]] {}; } - using ns::Foo; + using ns::[[Foo]]; F^oo f; )cpp", Index: clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp +++ clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp @@ -85,6 +85,10 @@ "struct Foo; struct ^Foo{}; typedef Foo ^Bar;", "Bar b;", }, + { + "namespace ns { class X; }; using ns::^X;", + "X *y;", + }, // MemberExpr { "struct ^X{int ^a;}; X ^foo();", @@ -198,14 +202,6 @@ { "enum class ^Color : char {};", "Color *c;", - }, - { - // When a type is resolved via a using declaration, the - // UsingShadowDecl is not referenced in the AST. - // Compare to TypedefType, or DeclRefExpr::getFoundDecl(). - // ^ - "namespace ns { class ^X; }; using ns::X;", - "X *y;", }}; for (const TestCase &T : Cases) { TestTU TU; Index: clang-tools-extra/clangd/IncludeCleaner.cpp =================================================================== --- clang-tools-extra/clangd/IncludeCleaner.cpp +++ clang-tools-extra/clangd/IncludeCleaner.cpp @@ -74,6 +74,11 @@ return true; } + bool VisitUsingType(UsingType *UT) { + add(UT->getFoundDecl()); + return true; + } + bool VisitTypedefType(TypedefType *TT) { add(TT->getDecl()); return true; Index: clang-tools-extra/clangd/FindTarget.cpp =================================================================== --- clang-tools-extra/clangd/FindTarget.cpp +++ clang-tools-extra/clangd/FindTarget.cpp @@ -364,6 +364,10 @@ Outer.add(ET->desugar(), Flags); } + void VisitUsingType(const UsingType *ET) { + Outer.add(ET->getFoundDecl(), Flags); + } + void VisitInjectedClassNameType(const InjectedClassNameType *ICNT) { Outer.add(ICNT->getDecl(), Flags); } @@ -855,6 +859,13 @@ } } + void VisitUsingTypeLoc(UsingTypeLoc L) { + Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(), + L.getLocalSourceRange().getBegin(), + /*IsDecl=*/false, + {L.getFoundDecl()}}); + } + void VisitTagTypeLoc(TagTypeLoc L) { Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(), L.getNameLoc(), Index: clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp +++ clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp @@ -70,6 +70,13 @@ TL.getAs<TypedefTypeLoc>().getTypePtr()->getDecl()->getName())) return false; break; + case TypeLoc::Using: + if (visitUnqualName(TL.getAs<UsingTypeLoc>() + .getTypePtr() + ->getFoundDecl() + ->getName())) + return false; + break; default: break; } Index: clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp +++ clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp @@ -45,6 +45,7 @@ return DeclMatcher.matches(*TD, Finder, Builder); return false; } + } // namespace // A function that helps to tell whether a TargetDecl in a UsingDecl will be @@ -60,13 +61,10 @@ void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher(usingDecl(isExpansionInMainFile()).bind("using"), this); auto DeclMatcher = hasDeclaration(namedDecl().bind("used")); - Finder->addMatcher(loc(enumType(DeclMatcher)), this); - Finder->addMatcher(loc(recordType(DeclMatcher)), this); Finder->addMatcher(loc(templateSpecializationType(DeclMatcher)), this); Finder->addMatcher(loc(deducedTemplateSpecializationType( refsToTemplatedDecl(namedDecl().bind("used")))), this); - Finder->addMatcher(declRefExpr().bind("used"), this); Finder->addMatcher(callExpr(callee(unresolvedLookupExpr().bind("used"))), this); Finder->addMatcher( @@ -76,6 +74,13 @@ Finder->addMatcher(loc(templateSpecializationType(forEachTemplateArgument( templateArgument().bind("used")))), this); + // Cases where we can identify the UsingShadowDecl directly, rather than + // just its target. + // FIXME: cover more cases in this way, as the AST supports it. + Finder->addMatcher( + declRefExpr(throughUsingDecl(namedDecl().bind("usedShadow"))), this); + Finder->addMatcher( + loc(usingType(hasDeclaration(namedDecl().bind("usedShadow")))), this); } void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) { @@ -137,6 +142,12 @@ return; } + if (const auto *UsedShadow = + Result.Nodes.getNodeAs<UsingShadowDecl>("usedShadow")) { + removeFromFoundDecls(UsedShadow->getTargetDecl()); + return; + } + if (const auto *Used = Result.Nodes.getNodeAs<TemplateArgument>("used")) { if (Used->getKind() == TemplateArgument::Template) { if (const auto *TD = Used->getAsTemplate().getAsTemplateDecl()) Index: clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp +++ clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp @@ -196,6 +196,12 @@ usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(TestCaseTypeAlias))) .bind("using"), this); + Finder->addMatcher( + typeLoc(loc(usingType(hasUnderlyingType( + typedefType(hasDeclaration(TestCaseTypeAlias))))), + unless(hasAncestor(decl(isImplicit()))), LocationFilter) + .bind("typeloc"), + this); } static llvm::StringRef getNewMethodName(llvm::StringRef CurrentName) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits