[Lldb-commits] [lldb] af27466 - Reland "[AST] Add UsingType: a sugar type for types found via UsingDecl"
Sam McCall via lldb-commits
lldb-commits at lists.llvm.org
Mon Dec 20 09:04:15 PST 2021
Author: Sam McCall
Date: 2021-12-20T18:03:15+01:00
New Revision: af27466c50398e3f04372850370eab8dc8abbb92
URL: https://github.com/llvm/llvm-project/commit/af27466c50398e3f04372850370eab8dc8abbb92
DIFF: https://github.com/llvm/llvm-project/commit/af27466c50398e3f04372850370eab8dc8abbb92.diff
LOG: Reland "[AST] Add UsingType: a sugar type for types found via UsingDecl"
This reverts commit cc56c66f27e131b914082d3bd21180646e842e9a.
Fixed a bad assertion, the target of a UsingShadowDecl must not have
*local* qualifiers, but it can be a typedef whose underlying type is qualified.
Added:
clang/test/AST/ast-dump-using.cpp
Modified:
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/TextNodeDumper.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/ASTImporter.cpp
clang/lib/AST/ASTStructuralEquivalence.cpp
clang/lib/AST/ItaniumMangle.cpp
clang/lib/AST/QualTypeNames.cpp
clang/lib/AST/TextNodeDumper.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/tools/libclang/CIndex.cpp
clang/unittests/AST/ASTImporterTest.cpp
lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp b/clang-tools-extra/clang-tidy/google/UpgradeGoogletestCaseCheck.cpp
index d943b7a1a270..4c6d898d4cf7 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 04dff8dfefe0..9265504a7651 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<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())
diff --git a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp
index d8d9e28d598d..d5c9fa7de811 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<UnqualNameVisitor> {
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;
}
diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index 70e1d423f542..8b363efc9919 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 043fb8c3c6a5..9e51f5430be8 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 5c82332c9baf..12bcc9440f2d 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 d567e0d77b39..f85035a6c2a1 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 2993b20f7634..44485fcd7e26 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<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 ``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 ebe8fc8faf91..63f2c948c79b 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -248,6 +248,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
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 @@ class ASTContext : public RefCountedBase<ASTContext> {
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 a087cb406b29..9282b24eb68c 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 3801c180c795..8bcee8790e7b 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<Derived>::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<UsingShadowDecl>(Child))
+ TRY_TO(TraverseDecl(Child));
+ }
}
return true;
}
diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h
index 0eb0031de11f..41bbf2ec593a 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 8abaae56194c..a69c0ae67d0a 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<Type>;
@@ -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 223c1b607972..7a036836e8c4 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -665,6 +665,16 @@ class BuiltinTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
}
};
+/// 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,
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 19325d0c1fb2..8cbb67589b94 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -362,6 +362,19 @@ let Class = UnresolvedUsingType in {
}]>;
}
+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 0b86b4a9ba03..55cce324b436 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<Decl>,
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<UsingShadowDecl>, 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<DeclRefExpr>, Matcher<UsingType>
+AST_POLYMORPHIC_MATCHER_P(throughUsingDecl,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr,
+ UsingType),
+ internal::Matcher<UsingShadowDecl>, Inner) {
const NamedDecl *FoundDecl = Node.getFoundDecl();
if (const UsingShadowDecl *UsingDecl = dyn_cast<UsingShadowDecl>(FoundDecl))
- return InnerMatcher.matches(*UsingDecl, Finder, Builder);
+ return Inner.matches(*UsingDecl, Finder, Builder);
return false;
}
@@ -6843,7 +6852,7 @@ extern const AstTypeMatcher<DecltypeType> 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<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 +7193,18 @@ AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>,
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.
///
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index a77611001fb1..ab7a445dbcd4 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1090,6 +1090,12 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
if (const auto *S = dyn_cast<ElaboratedType>(&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<UsingType>(&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 3152b2a2cb16..b65e8ab521c0 100644
--- a/clang/include/clang/Basic/TypeNodes.td
+++ b/clang/include/clang/Basic/TypeNodes.td
@@ -75,6 +75,7 @@ def DependentSizedMatrixType : TypeNode<MatrixType>, AlwaysDependent;
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;
diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def
index 745d0bab5925..85571ea290f7 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 22020119b9f5..58bd7b6a4a8c 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<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());
@@ -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<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);
diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index 2e512195fd15..724ede272fbf 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<UsingType>(Ty)) {
+ QT = UT->desugar();
+ continue;
+ }
// ... or a paren type ...
if (const ParenType *PT = dyn_cast<ParenType>(Ty)) {
QT = PT->desugar();
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 13490f1cf89d..7f78da10e0b3 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<UsingShadowDecl *> FoundOrErr = import(T->getFoundDecl());
+ if (!FoundOrErr)
+ return FoundOrErr.takeError();
+ Expected<QualType> 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 9883f6fd69ba..0813a5204a5e 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<UsingType>(T1)->getFoundDecl(),
+ cast<UsingType>(T2)->getFoundDecl()))
+ return false;
+ break;
+
case Type::Typedef:
if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
cast<TypedefType>(T2)->getDecl()))
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index c39daa3ce8df..7afc1250a36f 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<UsingType>(Ty)->desugar(),
+ Prefix);
case Type::Elaborated:
return mangleUnresolvedTypeOrSimpleId(
cast<ElaboratedType>(Ty)->getNamedType(), Prefix);
diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp
index 673821078345..561757b1ba64 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<UsingType>(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 b21e806e307c..67c934847c7f 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 e5a39f88d8c0..c771fe264b0c 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<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 {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 4044518609ab..2a33a69f288d 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 7680eb38283e..815058f32de4 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1059,6 +1059,7 @@ const AstTypeMatcher<UnaryTransformType> unaryTransformType;
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;
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 878547923d27..4f3efdb0a663 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 89ec9f1b7e8f..6e189a61dd20 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<ElaboratedType>(T)->getNamedType();
break;
+ case Type::Using:
+ T = cast<UsingType>(T)->getUnderlyingType();
+ break;
case Type::Paren:
T = cast<ParenType>(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 4c488bcd552f..702495df9db6 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 c4826b5a6e8f..8cecf6c6ab4f 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<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 @@ 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 2af71661b782..3c58f1d19c04 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<UsingShadowDecl>(*Res);
+ }
}
}
@@ -465,6 +468,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::Found:
IIDecl = Result.getFoundDecl();
+ FoundUsingShadow = dyn_cast<UsingShadowDecl>(*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<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 @@ 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<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 @@ 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<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 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
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
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 82e881476d35..d32b3f217aa0 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<DecltypeType>(Ty)->desugar();
break;
+ case Type::Using:
+ T = cast<UsingType>(Ty)->desugar();
+ break;
case Type::Auto:
case Type::DeducedTemplateSpecialization:
T = cast<DeducedType>(Ty)->getDeducedType();
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 31f4c475d345..39b659753dfa 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<Derived>::TransformFunctionNoProtoType(
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 @@ TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB,
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 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(SourceLocation Loc,
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 @@ QualType TreeTransform<Derived>::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<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>
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 08f93465ea4d..d16697b48ca9 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 f3bccf99acc1..3e4153b3b612 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 000000000000..5c98556d84dd
--- /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 b66cf577f1f1..c59c5709b6fa 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 9e8bee9c10b3..04da7988fc30 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<Decl> 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<Decl> Verifier;
testImport("template <typename T> void declToImport() { };", Lang_CXX03, "",
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 9b6327754f6c..0df95594eea2 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<clang::Type::TypeClass> 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;
More information about the lldb-commits
mailing list