diff --git a/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp b/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp index d943b7a1a2705f..4c6d898d4cf77a 100644 --- a/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp +++ b/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp @@ -196,6 +196,12 @@ void UpgradeGoogletestCaseCheck::registerMatchers(MatchFinder *Finder) { 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) { diff --git a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp index 04dff8dfefe06e..9265504a76511a 100644 --- a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp @@ -45,6 +45,7 @@ AST_MATCHER_P(DeducedTemplateSpecializationType, refsToTemplatedDecl, 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 @@ static bool shouldCheckDecl(const Decl *TargetDecl) { 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,12 @@ void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) { 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. + auto ThroughShadowMatcher = throughUsingDecl(namedDecl().bind("usedShadow")); + Finder->addMatcher(declRefExpr(ThroughShadowMatcher), this); + Finder->addMatcher(loc(usingType(ThroughShadowMatcher)), this); } void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) { @@ -137,6 +141,12 @@ void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) { return; } + if (const auto *UsedShadow = + Result.Nodes.getNodeAs("usedShadow")) { + removeFromFoundDecls(UsedShadow->getTargetDecl()); + return; + } + if (const auto *Used = Result.Nodes.getNodeAs("used")) { if (Used->getKind() == TemplateArgument::Template) { if (const auto *TD = Used->getAsTemplate().getAsTemplateDecl()) diff --git a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp index d8d9e28d598d17..d5c9fa7de811ee 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp @@ -70,6 +70,13 @@ struct UnqualNameVisitor : public RecursiveASTVisitor { TL.getAs().getTypePtr()->getDecl()->getName())) return false; break; + case TypeLoc::Using: + if (visitUnqualName(TL.getAs() + .getTypePtr() + ->getFoundDecl() + ->getName())) + return false; + break; default: break; } diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index 70e1d423f54225..8b363efc991960 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -364,6 +364,10 @@ struct TargetFinder { 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 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) { } } + 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(), diff --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp index 043fb8c3c6a50f..9e51f5430be801 100644 --- a/clang-tools-extra/clangd/IncludeCleaner.cpp +++ b/clang-tools-extra/clangd/IncludeCleaner.cpp @@ -74,6 +74,11 @@ class ReferencedLocationCrawler return true; } + bool VisitUsingType(UsingType *UT) { + add(UT->getFoundDecl()); + return true; + } + bool VisitTypedefType(TypedefType *TT) { add(TT->getDecl()); return true; diff --git a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp index 5c82332c9baf28..12bcc9440f2de1 100644 --- a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp +++ b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp @@ -85,6 +85,10 @@ TEST(IncludeCleaner, ReferencedLocations) { "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 @@ TEST(IncludeCleaner, ReferencedLocations) { { "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; diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp index d567e0d77b39c3..f85035a6c2a15b 100644 --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -1372,7 +1372,7 @@ TEST(LocateSymbol, Alias) { R"cpp( namespace ns { class [[Foo]] {}; } - using ns::Foo; + using ns::[[Foo]]; F^oo f; )cpp", diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2993b20f763436..44485fcd7e26fa 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -244,7 +244,9 @@ Floating Point Support in Clang 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,12 @@ AST Matchers - The ``hasAnyCapture`` matcher now only accepts an inner matcher of type ``Matcher``. The matcher originally accepted an inner matcher of type ``Matcher`` or ``Matcher``. +- 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 ``throughUsingDecl`` + and the underlying ``Type`` with ``hasUnderlyingType``. + ``hasDeclaration`` continues to see through the alias and apply to the + underlying type. clang-format ------------ diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index ebe8fc8faf910e..63f2c948c79bbc 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -248,6 +248,7 @@ class ASTContext : public RefCountedBase { mutable llvm::ContextualFoldingSet TemplateSpecializationTypes; mutable llvm::FoldingSet ParenTypes; + mutable llvm::FoldingSet UsingTypes; mutable llvm::FoldingSet ElaboratedTypes; mutable llvm::FoldingSet DependentNameTypes; mutable llvm::ContextualFoldingSet { 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, diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index a087cb406b290d..9282b24eb68c2f 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -107,6 +107,8 @@ def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; } SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>; def TemplateTemplateParmDeclRef : SubclassPropertyType<"TemplateTemplateParmDecl", DeclRef>; + def UsingShadowDeclRef : + SubclassPropertyType<"UsingShadowDecl", DeclRef>; def ValueDeclRef : SubclassPropertyType<"ValueDecl", DeclRef>; def ElaboratedTypeKeyword : EnumPropertyType; diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 3801c180c795ee..8bcee8790e7b19 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -981,6 +981,7 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, { TRY_TO(TraverseStmt(NE)); }) +DEF_TRAVERSE_TYPE(UsingType, {}) DEF_TRAVERSE_TYPE(UnresolvedUsingType, {}) DEF_TRAVERSE_TYPE(TypedefType, {}) @@ -1252,6 +1253,7 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, { TRY_TO(TraverseStmt(NE)); }) +DEF_TRAVERSE_TYPELOC(UsingType, {}) DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {}) DEF_TRAVERSE_TYPELOC(TypedefType, {}) @@ -2095,7 +2097,13 @@ bool RecursiveASTVisitor::TraverseFunctionHelper(FunctionDecl *D) { } 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(Child)) + TRY_TO(TraverseDecl(Child)); + } } return true; } diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 0eb0031de11f2e..41bbf2ec593aa8 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -311,6 +311,7 @@ class TextNodeDumper void VisitFunctionType(const FunctionType *T); void VisitFunctionProtoType(const FunctionProtoType *T); void VisitUnresolvedUsingType(const UnresolvedUsingType *T); + void VisitUsingType(const UsingType *T); void VisitTypedefType(const TypedefType *T); void VisitUnaryTransformType(const UnaryTransformType *T); void VisitTagType(const TagType *T); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 8abaae56194c9a..a69c0ae67d0a08 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -129,6 +129,7 @@ class TemplateArgumentLoc; class TemplateTypeParmDecl; class TypedefNameDecl; class UnresolvedUsingTypenameDecl; +class UsingShadowDecl; using CanQualType = CanQual; @@ -4368,6 +4369,27 @@ class UnresolvedUsingType : public Type { } }; +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; diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index 223c1b607972ba..7a036836e8c48a 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -665,6 +665,16 @@ class BuiltinTypeLoc : public ConcreteTypeLoc { +public: + QualType getUnderlyingType() const { + return getTypePtr()->getUnderlyingType(); + } + UsingShadowDecl *getFoundDecl() const { return getTypePtr()->getFoundDecl(); } +}; + /// Wrapper for source info for typedefs. class TypedefTypeLoc : public InheritingConcreteTypeLoc; } +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() }]; diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 0b86b4a9ba0357..55cce324b43621 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -4128,25 +4128,34 @@ AST_MATCHER_P(DeclRefExpr, to, internal::Matcher, InnerMatcher.matches(*DeclNode, Finder, Builder)); } -/// Matches a \c DeclRefExpr that refers to a declaration through a -/// specific using shadow declaration. +/// Matches if a node refers to a declaration through a specific +/// using shadow declaration. /// -/// Given +/// Examples: /// \code -/// namespace a { void f() {} } +/// namespace a { int f(); } /// using a::f; -/// void g() { -/// f(); // Matches this .. -/// a::f(); // .. but not this. -/// } +/// int x = f(); /// \endcode /// declRefExpr(throughUsingDecl(anything())) -/// matches \c f() -AST_MATCHER_P(DeclRefExpr, throughUsingDecl, - internal::Matcher, InnerMatcher) { +/// matches \c f +/// +/// \code +/// namespace a { class X{}; } +/// using a::X; +/// X x; +/// \code +/// typeLoc(loc(usingType(throughUsingDecl(anything())))) +/// matches \c X +/// +/// Usable as: Matcher, Matcher +AST_POLYMORPHIC_MATCHER_P(throughUsingDecl, + AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr, + UsingType), + internal::Matcher, Inner) { const NamedDecl *FoundDecl = Node.getFoundDecl(); if (const UsingShadowDecl *UsingDecl = dyn_cast(FoundDecl)) - return InnerMatcher.matches(*UsingDecl, Finder, Builder); + return Inner.matches(*UsingDecl, Finder, Builder); return false; } @@ -6843,7 +6852,7 @@ extern const AstTypeMatcher decltypeType; 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 +6862,10 @@ AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType, /// decltypeType(hasUnderlyingType(isInteger())) /// matches the type of "a" /// -/// Usable as: Matcher +/// Usable as: Matcher, Matcher AST_TYPE_TRAVERSE_MATCHER(hasUnderlyingType, getUnderlyingType, - AST_POLYMORPHIC_SUPPORTED_TYPES(DecltypeType)); + AST_POLYMORPHIC_SUPPORTED_TYPES(DecltypeType, + UsingType)); /// Matches \c FunctionType nodes. /// @@ -7183,6 +7193,18 @@ AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher, 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; + /// Matches types that represent the result of substituting a type for a /// template type parameter. /// diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index a77611001fb149..ab7a445dbcd49a 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1090,6 +1090,12 @@ class HasDeclarationMatcher : public MatcherInterface { if (const auto *S = dyn_cast(&Node)) { return matchesSpecialized(S->desugar(), Finder, Builder); } + // Similarly types found via using declarations. + // These are *usually* meaningless sugar, and this matches the historical + // behavior prior to the introduction of UsingType. + if (const auto *S = dyn_cast(&Node)) { + return matchesSpecialized(S->desugar(), Finder, Builder); + } return false; } diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td index 3152b2a2cb161e..b65e8ab521c037 100644 --- a/clang/include/clang/Basic/TypeNodes.td +++ b/clang/include/clang/Basic/TypeNodes.td @@ -75,6 +75,7 @@ def DependentSizedMatrixType : TypeNode, AlwaysDependent; def FunctionType : TypeNode; def FunctionProtoType : TypeNode; def FunctionNoProtoType : TypeNode; +def UsingType : TypeNode, NeverCanonical; def UnresolvedUsingType : TypeNode, AlwaysDependent; def ParenType : TypeNode, NeverCanonical; def TypedefType : TypeNode, NeverCanonical; diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def index 745d0bab5925ee..85571ea290f734 100644 --- a/clang/include/clang/Serialization/TypeBitCodes.def +++ b/clang/include/clang/Serialization/TypeBitCodes.def @@ -62,5 +62,6 @@ TYPE_BIT_CODE(BitInt, BIT_INT, 50) 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 diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 22020119b9f50e..58bd7b6a4a8cc2 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2349,6 +2349,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case Type::ObjCTypeParam: return getTypeInfo(cast(T)->desugar().getTypePtr()); + case Type::Using: + return getTypeInfo(cast(T)->desugar().getTypePtr()); + case Type::Typedef: { const TypedefNameDecl *Typedef = cast(T)->getDecl(); TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); @@ -4591,6 +4594,27 @@ QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl, 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.hasLocalQualifiers()); + assert(Underlying == getTypeDeclType(cast(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); diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 2e512195fd15ea..724ede272fbfac 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -38,6 +38,11 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, QT = ET->desugar(); continue; } + // ... or a using type ... + if (const UsingType *UT = dyn_cast(Ty)) { + QT = UT->desugar(); + continue; + } // ... or a paren type ... if (const ParenType *PT = dyn_cast(Ty)) { QT = PT->desugar(); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 13490f1cf89d72..7f78da10e0b36f 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -354,6 +354,7 @@ namespace clang { ExpectedType VisitTypeOfExprType(const TypeOfExprType *T); // FIXME: DependentTypeOfExprType ExpectedType VisitTypeOfType(const TypeOfType *T); + ExpectedType VisitUsingType(const UsingType *T); ExpectedType VisitDecltypeType(const DecltypeType *T); ExpectedType VisitUnaryTransformType(const UnaryTransformType *T); ExpectedType VisitAutoType(const AutoType *T); @@ -1340,6 +1341,17 @@ ExpectedType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) { return Importer.getToContext().getTypeOfType(*ToUnderlyingTypeOrErr); } +ExpectedType ASTNodeImporter::VisitUsingType(const UsingType *T) { + Expected FoundOrErr = import(T->getFoundDecl()); + if (!FoundOrErr) + return FoundOrErr.takeError(); + Expected UnderlyingOrErr = import(T->getUnderlyingType()); + if (!UnderlyingOrErr) + return UnderlyingOrErr.takeError(); + + return Importer.getToContext().getUsingType(*FoundOrErr, *UnderlyingOrErr); +} + ExpectedType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) { // FIXME: Make sure that the "to" context supports C++0x! ExpectedExpr ToExprOrErr = import(T->getUnderlyingExpr()); diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 9883f6fd69bafd..0813a5204a5e2f 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -945,6 +945,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; + case Type::Using: + if (!IsStructurallyEquivalent(Context, cast(T1)->getFoundDecl(), + cast(T2)->getFoundDecl())) + return false; + break; + case Type::Typedef: if (!IsStructurallyEquivalent(Context, cast(T1)->getDecl(), cast(T2)->getDecl())) diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index c39daa3ce8dfe1..7afc1250a36f40 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2380,6 +2380,9 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, break; } + case Type::Using: + return mangleUnresolvedTypeOrSimpleId(cast(Ty)->desugar(), + Prefix); case Type::Elaborated: return mangleUnresolvedTypeOrSimpleId( cast(Ty)->getNamedType(), Prefix); diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index 67382107834555..561757b1ba6450 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -418,6 +418,13 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, 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 (isa(QT.getTypePtr())) { + return getFullyQualifiedType(QT.getSingleStepDesugaredType(Ctx), 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 diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index b21e806e307cd8..67c934847c7f9f 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1534,6 +1534,10 @@ void TextNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { dumpDeclRef(T->getDecl()); } +void TextNodeDumper::VisitUsingType(const UsingType *T) { + dumpDeclRef(T->getFoundDecl()); +} + void TextNodeDumper::VisitTypedefType(const TypedefType *T) { dumpDeclRef(T->getDecl()); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index e5a39f88d8c08c..c771fe264b0c81 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3407,6 +3407,17 @@ QualType TypedefType::desugar() const { return getDecl()->getUnderlyingType(); } +UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying, + QualType Canon) + : Type(Using, Canon, Underlying->getDependence()), + Found(const_cast(Found)) { + assert(Underlying == getUnderlyingType()); +} + +QualType UsingType::getUnderlyingType() const { + return QualType(cast(Found->getTargetDecl())->getTypeForDecl(), 0); +} + QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); } QualType MacroQualifiedType::getModifiedType() const { diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 4044518609abc5..2a33a69f288d44 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -212,6 +212,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::Builtin: case Type::Complex: case Type::UnresolvedUsing: + case Type::Using: case Type::Typedef: case Type::TypeOfExpr: case Type::TypeOf: @@ -1046,6 +1047,21 @@ void TypePrinter::printUnresolvedUsingBefore(const UnresolvedUsingType *T, void TypePrinter::printUnresolvedUsingAfter(const UnresolvedUsingType *T, raw_ostream &OS) {} +void TypePrinter::printUsingBefore(const UsingType *T, raw_ostream &OS) { + // After `namespace b { using a::X }`, is the type X within B a::X or b::X? + // + // - b::X is more formally correct given the UsingType model + // - b::X makes sense if "re-exporting" a symbol in a new namespace + // - a::X makes sense if "importing" a symbol for convenience + // + // The "importing" use seems much more common, so we print a::X. + // This could be a policy option, but the right choice seems to rest more + // with the intent of the code than the caller. + printTypeSpec(T->getFoundDecl()->getUnderlyingDecl(), OS); +} + +void TypePrinter::printUsingAfter(const UsingType *T, raw_ostream &OS) {} + void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) { printTypeSpec(T->getDecl(), OS); } diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 7680eb38283e7d..815058f32de4c9 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -1059,6 +1059,7 @@ const AstTypeMatcher unaryTransformType; const AstTypeMatcher recordType; const AstTypeMatcher tagType; const AstTypeMatcher elaboratedType; +const AstTypeMatcher usingType; const AstTypeMatcher substTemplateTypeParmType; const AstTypeMatcher templateTypeParmType; const AstTypeMatcher injectedClassNameType; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 878547923d27e9..4f3efdb0a6630e 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -228,6 +228,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(eachOf); REGISTER_MATCHER(elaboratedType); REGISTER_MATCHER(elaboratedTypeLoc); + REGISTER_MATCHER(usingType); REGISTER_MATCHER(enumConstantDecl); REGISTER_MATCHER(enumDecl); REGISTER_MATCHER(enumType); diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 89ec9f1b7e8fd4..6e189a61dd206d 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -3355,6 +3355,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { case Type::Elaborated: T = cast(T)->getNamedType(); break; + case Type::Using: + T = cast(T)->getUnderlyingType(); + break; case Type::Paren: T = cast(T)->getInnerType(); break; @@ -3547,6 +3550,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit, case Type::Decayed: case Type::DeducedTemplateSpecialization: case Type::Elaborated: + case Type::Using: case Type::Paren: case Type::MacroQualified: case Type::SubstTemplateTypeParm: diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 4c488bcd552ff7..702495df9db6af 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2199,6 +2199,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { case Type::Record: case Type::Enum: case Type::Elaborated: + case Type::Using: case Type::TemplateSpecialization: case Type::ObjCTypeParam: case Type::ObjCObject: diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index c4826b5a6e8f9e..8cecf6c6ab4f60 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -736,8 +736,15 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, QualType T = Context.getTypeDeclType(cast(SD->getUnderlyingDecl())); + + if (T->isEnumeralType()) + Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); + TypeLocBuilder TLB; - if (isa(T)) { + if (const auto *USD = dyn_cast(SD)) { + T = Context.getUsingType(USD, T); + TLB.pushTypeSpec(T).setNameLoc(IdInfo.IdentifierLoc); + } else if (isa(T)) { InjectedClassNameTypeLoc InjectedTL = TLB.push(T); InjectedTL.setNameLoc(IdInfo.IdentifierLoc); @@ -770,9 +777,6 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, 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; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2af71661b78261..3c58f1d19c04ba 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -372,6 +372,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, } NamedDecl *IIDecl = nullptr; + UsingShadowDecl *FoundUsingShadow = nullptr; switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: @@ -441,8 +442,10 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, (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(*Res); + } } } @@ -465,6 +468,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, case LookupResult::Found: IIDecl = Result.getFoundDecl(); + FoundUsingShadow = dyn_cast(*Result.begin()); break; } @@ -491,14 +495,20 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, (void)DiagnoseUseOfDecl(IDecl, NameLoc); if (!HasTrailingDot) T = Context.getObjCInterfaceType(IDecl); + FoundUsingShadow = nullptr; // FIXME: Target must be a TypeDecl. } else if (auto *UD = dyn_cast(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 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, 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 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, 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(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 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, : NameClassification::TypeTemplate(Template); } + auto BuildTypeFor = [&](TypeDecl *Type, NamedDecl *Found) { + QualType T = Context.getTypeDeclType(Type); + if (const auto *USD = dyn_cast(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(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(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(FirstDecl); @@ -1190,10 +1202,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) { TypeDecl *Type = Result.getAsSingle(); 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 diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 82e881476d35c9..d32b3f217aa021 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4443,6 +4443,9 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::Decltype: T = cast(Ty)->desugar(); break; + case Type::Using: + T = cast(Ty)->desugar(); + break; case Type::Auto: case Type::DeducedTemplateSpecialization: T = cast(Ty)->getDeducedType(); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 31f4c475d3458a..39b659753dfa5b 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -933,6 +933,11 @@ class TreeTransform { /// 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 @@ QualType TreeTransform::TransformFunctionNoProtoType( return Result; } -template QualType -TreeTransform::TransformUnresolvedUsingType(TypeLocBuilder &TLB, - UnresolvedUsingTypeLoc TL) { +template +QualType TreeTransform::TransformUnresolvedUsingType( + TypeLocBuilder &TLB, UnresolvedUsingTypeLoc TL) { const UnresolvedUsingType *T = TL.getTypePtr(); Decl *D = getDerived().TransformDecl(TL.getNameLoc(), T->getDecl()); if (!D) @@ -6095,6 +6100,32 @@ TreeTransform::TransformUnresolvedUsingType(TypeLocBuilder &TLB, return Result; } +template +QualType TreeTransform::TransformUsingType(TypeLocBuilder &TLB, + UsingTypeLoc TL) { + const UsingType *T = TL.getTypePtr(); + + auto *Found = cast_or_null(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 QualType TreeTransform::TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { @@ -14462,7 +14493,6 @@ QualType TreeTransform::RebuildUnresolvedUsingType(SourceLocation Loc, if (D->isInvalidDecl()) return QualType(); // FIXME: Doesn't account for ObjCInterfaceDecl! - TypeDecl *Ty; if (auto *UPD = dyn_cast(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 @@ QualType TreeTransform::RebuildUnresolvedUsingType(SourceLocation Loc, // 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(Target); + return SemaRef.Context.getUsingType( + Shadow, SemaRef.Context.getTypeDeclType( + cast(Shadow->getTargetDecl()))); } else { assert(isa(D) && "UnresolvedUsingTypenameDecl transformed to non-using decl"); - Ty = cast(D); + return SemaRef.Context.getTypeDeclType( + cast(D)); } - - return SemaRef.Context.getTypeDeclType(Ty); } template diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 08f93465ea4d0c..d16697b48ca93a 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6607,6 +6607,10 @@ void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } +void TypeLocReader::VisitUsingTypeLoc(UsingTypeLoc TL) { + TL.setNameLoc(readSourceLocation()); +} + void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(readSourceLocation()); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index f3bccf99acc14b..3e4153b3b61224 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -396,6 +396,10 @@ void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); } +void TypeLocWriter::VisitUsingTypeLoc(UsingTypeLoc TL) { + Record.AddSourceLocation(TL.getNameLoc()); +} + void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); } diff --git a/clang/test/AST/ast-dump-using.cpp b/clang/test/AST/ast-dump-using.cpp new file mode 100644 index 00000000000000..5c98556d84ddb9 --- /dev/null +++ b/clang/test/AST/ast-dump-using.cpp @@ -0,0 +1,16 @@ +// 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 {{.*}} 'a::S' sugar +// CHECK-NEXT: |-UsingShadow {{.*}} 'S' +// CHECK-NEXT: `-RecordType {{.*}} 'a::S' +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index b66cf577f1f13f..c59c5709b6fa2f 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1666,6 +1666,8 @@ bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { return Visit(TL.getPointeeLoc()); } +bool CursorVisitor::VisitUsingTypeLoc(UsingTypeLoc TL) { return false; } + bool CursorVisitor::VisitAttributedTypeLoc(AttributedTypeLoc TL) { return Visit(TL.getModifiedLoc()); } diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 9e8bee9c10b3b1..04da7988fc308f 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -562,6 +562,15 @@ TEST_P(ImportType, ImportAtomicType) { functionDecl(hasDescendant(typedefDecl(has(atomicType()))))); } +TEST_P(ImportType, ImportUsingType) { + MatchVerifier Verifier; + testImport("struct C {};" + "void declToImport() { using ::C; new C{}; }", + Lang_CXX11, "", Lang_CXX11, Verifier, + functionDecl(hasDescendant( + cxxNewExpr(hasType(pointerType(pointee(usingType()))))))); +} + TEST_P(ImportDecl, ImportFunctionTemplateDecl) { MatchVerifier Verifier; testImport("template void declToImport() { };", Lang_CXX03, "", diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 9b6327754f6c54..0df95594eea2d9 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -2581,6 +2581,7 @@ RemoveWrappingTypes(QualType type, ArrayRef mask = {}) { 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 @@ TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) { 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 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, 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 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) { 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;