diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -364,6 +364,12 @@ Outer.add(ET->desugar(), Flags); } + void VisitUsingType(const UsingType *ET) { + if (auto *USD = llvm::dyn_cast(ET->getFoundDecl())) + Outer.add(USD, Flags); + Outer.add(ET->desugar(), Flags); + } + void VisitInjectedClassNameType(const InjectedClassNameType *ICNT) { Outer.add(ICNT->getDecl(), Flags); } @@ -855,6 +861,13 @@ } } + void VisitUsingTypeLoc(UsingTypeLoc L) { + Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(), + L.getLocalSourceRange().getBegin(), + /*IsDecl=*/false, + {L.getTypePtr()->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 --- a/clang-tools-extra/clangd/IncludeCleaner.cpp +++ b/clang-tools-extra/clangd/IncludeCleaner.cpp @@ -45,6 +45,7 @@ } bool VisitTagType(TagType *TT) { + TT->dump(); add(TT->getDecl()); return true; } @@ -69,6 +70,11 @@ 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/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp --- a/clang-tools-extra/clangd/Selection.cpp +++ b/clang-tools-extra/clangd/Selection.cpp @@ -741,6 +741,12 @@ } else if (const auto *CCI = N.get()) { // : [[b_]](42) return CCI->getMemberLocation(); + } else if (const auto UTL = N.get()) { + // using std::vector + // vector x; + // UUUUUU UsingType + // TTTTTTTTTTT `-TemplateSpecialializationType + return UTL->getLocalSourceRange(); } return SourceRange(); } diff --git a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp --- a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp +++ b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp @@ -175,11 +175,7 @@ "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;", + "namespace ns { class ^X; }; using ns::^X;", "X *y;", }}; for (const TestCase &T : Cases) { diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/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", diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -248,6 +248,7 @@ mutable llvm::ContextualFoldingSet TemplateSpecializationTypes; mutable llvm::FoldingSet ParenTypes; + mutable llvm::FoldingSet UsingTypes; mutable llvm::FoldingSet ElaboratedTypes; mutable llvm::FoldingSet DependentNameTypes; mutable llvm::ContextualFoldingSetgetUnderlyingType())); }) DEF_TRAVERSE_TYPE(UnresolvedUsingType, {}) DEF_TRAVERSE_TYPE(TypedefType, {}) @@ -1252,6 +1253,8 @@ TRY_TO(TraverseStmt(NE)); }) +DEF_TRAVERSE_TYPELOC(UsingType, + { TRY_TO(TraverseTypeLoc(TL.getUnderlyingLoc())); }) DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {}) DEF_TRAVERSE_TYPELOC(TypedefType, {}) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -4368,6 +4368,31 @@ } }; +class UsingType : public Type, public llvm::FoldingSetNode { + QualType UnderlyingTy; + NamedDecl *Found; + friend class ASTContext; // ASTContext creates these. + + UsingType(const NamedDecl *Found, QualType UnderlyingTy, QualType CanonTy) + : Type(Using, CanonTy, UnderlyingTy->getDependence()), + UnderlyingTy(UnderlyingTy), Found(const_cast(Found)) {} + +public: + NamedDecl *getFoundDecl() const { return Found; } + QualType getUnderlyingType() const { return UnderlyingTy; } + + bool isSugared() const { return true; } + QualType desugar() const { return getUnderlyingType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Found, UnderlyingTy); } + static void Profile(llvm::FoldingSetNodeID &ID, const NamedDecl *Found, + QualType UnderlyingTy) { + ID.AddPointer(Found); + UnderlyingTy.Profile(ID); + } + 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 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -665,6 +665,21 @@ } }; +struct UsingLocInfo {}; + +/// Wrapper for source info for types used via transparent aliases. +class UsingTypeLoc : public ConcreteTypeLoc { +public: + QualType getInnerType() const { return getTypePtr()->getUnderlyingType(); } + TypeLoc getUnderlyingLoc() const { return getInnerTypeLoc(); } + SourceRange getLocalSourceRange() const { + return getUnderlyingLoc().getLocalSourceRange().getBegin(); + } + void initializeLocal(ASTContext &Context, SourceLocation Loc) {} + unsigned getLocalDataSize() const { return 0; } +}; + /// Wrapper for source info for typedefs. class TypedefTypeLoc : public InheritingConcreteTypeLoc; } +let Class = UsingType in { + def : Property<"foundDeclaration", NamedDeclRef> { + 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/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td --- a/clang/include/clang/Basic/TypeNodes.td +++ b/clang/include/clang/Basic/TypeNodes.td @@ -75,6 +75,7 @@ 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 --- a/clang/include/clang/Serialization/TypeBitCodes.def +++ b/clang/include/clang/Serialization/TypeBitCodes.def @@ -62,5 +62,6 @@ TYPE_BIT_CODE(DependentExtInt, DEPENDENT_EXT_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 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2349,6 +2349,9 @@ 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()); @@ -4593,6 +4596,25 @@ return QualType(newType, 0); } +QualType ASTContext::getUsingType(const NamedDecl *Found, + QualType Underlying) const { + llvm::FoldingSetNodeID ID; + UsingType::Profile(ID, Found, Underlying); + + void *InsertPos = nullptr; + UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + QualType Canon = Underlying; + if (!Canon.isCanonical()) + Canon = getCanonicalType(Underlying); + UsingType *NewType = new 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 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -37,6 +37,11 @@ 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/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -945,6 +945,16 @@ return false; break; + case Type::Using: + if (!IsStructurallyEquivalent(Context, cast(T1)->getFoundDecl(), + cast(T2)->getFoundDecl())) + return false; + if (!IsStructurallyEquivalent(Context, + cast(T1)->getUnderlyingType(), + cast(T2)->getUnderlyingType())) + 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 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2380,6 +2380,9 @@ 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/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1816,6 +1816,10 @@ return Visit(T->getNamedType()); } + Type *VisitUsingType(const UsingType *T) { + return Visit(T->getUnderlyingType()); + } + Type *VisitPointerType(const PointerType *T) { return Visit(T->getPointeeType()); } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/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); } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -3353,6 +3353,9 @@ case Type::Elaborated: T = cast(T)->getNamedType(); break; + case Type::Using: + T = cast(T)->getUnderlyingType(); + break; case Type::Paren: T = cast(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: diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/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: diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -372,6 +372,7 @@ } NamedDecl *IIDecl = nullptr; + NamedDecl *FoundDecl = 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; + FoundDecl = *Res; + } } } @@ -465,6 +468,7 @@ case LookupResult::Found: IIDecl = Result.getFoundDecl(); + FoundDecl = *Result.begin(); break; } @@ -507,23 +511,30 @@ return nullptr; } + QualType BeforeUsing = T; + if (FoundDecl != IIDecl) { + BeforeUsing = T; + T = Context.getUsingType(FoundDecl, T); + } + QualType BeforeElaboration = 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). if (SS && SS->isNotEmpty() && !IsCtorOrDtorName && !isa(IIDecl)) { + T = getElaboratedType(ETK_None, *SS, T); + if (WantNontrivialTypeSourceInfo) { - // Construct a type with type-source information. + // Construct a ParsedType with type-source information. TypeLocBuilder Builder; - Builder.pushTypeSpec(T).setNameLoc(NameLoc); - - T = getElaboratedType(ETK_None, *SS, T); + Builder.pushTypeSpec(BeforeUsing).setNameLoc(NameLoc); + if (BeforeUsing != BeforeElaboration) + Builder.push(BeforeElaboration); ElaboratedTypeLoc ElabTL = Builder.push(T); ElabTL.setElaboratedKeywordLoc(SourceLocation()); ElabTL.setQualifierLoc(SS->getWithLocInContext(Context)); return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); - } else { - T = getElaboratedType(ETK_None, *SS, T); } } @@ -843,21 +854,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(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,19 +1130,37 @@ : NameClassification::TypeTemplate(Template); } + auto BuildTypeFor = [&](TypeDecl *Type, NamedDecl *Found) { + QualType Original = Context.getTypeDeclType(Type); + QualType Using = + (Type == Found) ? Original : Context.getUsingType(Found, Original); + + if (SS.isEmpty()) // No elaborated type, trivial location info + return ParsedType::make(Using); + + TypeLocBuilder Builder; + Builder.pushTypeSpec(Original).setNameLoc(NameLoc); + if (Using != Original) + Builder.push(Using); + + QualType Elaborated = getElaboratedType(ETK_None, SS, Using); + ElaboratedTypeLoc ElabTL = Builder.push(Elaborated); + ElabTL.setElaboratedKeywordLoc(SourceLocation()); + ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); + return CreateParsedType(Elaborated, + Builder.getTypeSourceInfo(Context, Elaborated)); + }; + 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); if (!Class) { - // FIXME: It's unfortunate that we don't have a Type node for handling this. + // FIXME: use UsingType for this. if (ObjCCompatibleAliasDecl *Alias = dyn_cast(FirstDecl)) Class = Alias->getClassInterface(); @@ -1190,10 +1204,7 @@ 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 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4443,6 +4443,9 @@ 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/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -992,6 +992,8 @@ SS.Adopt(ET.getQualifierLoc()); TL = ET.getNamedTypeLoc(); } + while (auto UT = TL.getAs()) + TL = UT.getUnderlyingLoc(); if (auto DTST = TL.getAs()) { TemplateName Name = DTST.getTypePtr()->getTemplateName(); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/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(NamedDecl *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 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) @@ -6087,11 +6092,48 @@ return QualType(); } + // Result may be wrapped in UsingTypes with trivial location info. + QualType Underlying = Result; + llvm::SmallVector UsingTypes; + while (const UsingType *UT = dyn_cast(Underlying)) { + UsingTypes.push_back(Underlying); + Underlying = UT->desugar(); + } + // We might get an arbitrary type spec type back. We should at // least always get a type spec type, though. - TypeSpecTypeLoc NewTL = TLB.pushTypeSpec(Result); + TypeSpecTypeLoc NewTL = TLB.pushTypeSpec(Underlying); NewTL.setNameLoc(TL.getNameLoc()); + for (QualType UT : UsingTypes) + TLB.push(UT); + + return Result; +} + +template +QualType TreeTransform::TransformUsingType(TypeLocBuilder &TLB, + UsingTypeLoc TL) { + const UsingType *T = TL.getTypePtr(); + + NamedDecl *Found = cast_or_null(getDerived().TransformDecl( + TL.getLocalSourceRange().getBegin(), T->getFoundDecl())); + if (!Found) + return QualType(); + + QualType Underlying = getDerived().TransformType(TLB, TL.getUnderlyingLoc()); + 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.push(Result); return Result; } @@ -14452,7 +14494,6 @@ 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 @@ -14488,17 +14529,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(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 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/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()); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -343,6 +343,8 @@ Record.AddSourceLocation(TL.getNameLoc()); } +void TypeLocWriter::VisitUsingTypeLoc(UsingTypeLoc TL) {} + void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); } diff --git a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp --- a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp +++ b/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'}} } diff --git a/clang/test/SemaCXX/warn-enum-compare.cpp b/clang/test/SemaCXX/warn-enum-compare.cpp --- a/clang/test/SemaCXX/warn-enum-compare.cpp +++ b/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; diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1666,6 +1666,10 @@ return Visit(TL.getPointeeLoc()); } +bool CursorVisitor::VisitUsingTypeLoc(UsingTypeLoc TL) { + return Visit(TL.getUnderlyingLoc()); +} + bool CursorVisitor::VisitAttributedTypeLoc(AttributedTypeLoc TL) { return Visit(TL.getModifiedLoc()); } diff --git a/clang/unittests/Tooling/StencilTest.cpp b/clang/unittests/Tooling/StencilTest.cpp --- a/clang/unittests/Tooling/StencilTest.cpp +++ b/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);