Reland "[AST] Add UsingType: a sugar type for types found via UsingDecl"
This reverts commit cc56c66f27
.
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.
This commit is contained in:
parent
cc56c66f27
commit
af27466c50
|
@ -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) {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -70,6 +70,13 @@ public:
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -364,6 +364,10 @@ public:
|
|||
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(),
|
||||
|
|
|
@ -74,6 +74,11 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VisitUsingType(UsingType *UT) {
|
||||
add(UT->getFoundDecl());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitTypedefType(TypedefType *TT) {
|
||||
add(TT->getDecl());
|
||||
return true;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1372,7 +1372,7 @@ TEST(LocateSymbol, Alias) {
|
|||
|
||||
R"cpp(
|
||||
namespace ns { class [[Foo]] {}; }
|
||||
using ns::Foo;
|
||||
using ns::[[Foo]];
|
||||
F^oo f;
|
||||
)cpp",
|
||||
|
||||
|
|
|
@ -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
|
||||
------------
|
||||
|
|
|
@ -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 @@ public:
|
|||
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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -311,6 +311,7 @@ public:
|
|||
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);
|
||||
|
|
|
@ -129,6 +129,7 @@ class TemplateArgumentLoc;
|
|||
class TemplateTypeParmDecl;
|
||||
class TypedefNameDecl;
|
||||
class UnresolvedUsingTypenameDecl;
|
||||
class UsingShadowDecl;
|
||||
|
||||
using CanQualType = CanQual<Type>;
|
||||
|
||||
|
@ -4368,6 +4369,27 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -665,6 +665,16 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// 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,
|
||||
|
|
|
@ -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() }];
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -1090,6 +1090,12 @@ private:
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 @@ Corrected:
|
|||
: 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 @@ Corrected:
|
|||
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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -933,6 +933,11 @@ public:
|
|||
/// 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>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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, "",
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue