jcking1034 created this revision. jcking1034 added reviewers: ymandel, tdl-g, sbenza. jcking1034 requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This provides better support for TypeLocs to allow TypeLoc-related Matchers to feature stricter typing and to avoid relying on the dynamic casting of TypeLocs in matchers. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D110586 Files: clang/include/clang/AST/ASTTypeTraits.h clang/lib/AST/ASTTypeTraits.cpp
Index: clang/lib/AST/ASTTypeTraits.cpp =================================================================== --- clang/lib/AST/ASTTypeTraits.cpp +++ clang/lib/AST/ASTTypeTraits.cpp @@ -18,6 +18,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OpenMPClause.h" +#include "clang/AST/TypeLoc.h" using namespace clang; @@ -28,6 +29,8 @@ {NKI_None, "TemplateName"}, {NKI_None, "NestedNameSpecifierLoc"}, {NKI_None, "QualType"}, +#define TYPELOC(CLASS, PARENT) {NKI_##PARENT, #CLASS "TypeLoc"}, +#include "clang/AST/TypeLocNodes.def" {NKI_None, "TypeLoc"}, {NKI_None, "CXXBaseSpecifier"}, {NKI_None, "CXXCtorInitializer"}, @@ -127,6 +130,17 @@ llvm_unreachable("invalid type kind"); } + ASTNodeKind ASTNodeKind::getFromNode(const TypeLoc &T) { + switch (T.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: \ + return ASTNodeKind(NKI_##CLASS##TypeLoc); +#include "clang/AST/TypeLocNodes.def" + } + llvm_unreachable("invalid typeloc kind"); + } + ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) { switch (C.getClauseKind()) { #define GEN_CLANG_CLAUSE_CLASS Index: clang/include/clang/AST/ASTTypeTraits.h =================================================================== --- clang/include/clang/AST/ASTTypeTraits.h +++ clang/include/clang/AST/ASTTypeTraits.h @@ -53,8 +53,7 @@ ASTNodeKind() : KindId(NKI_None) {} /// Construct an identifier for T. - template <class T> - static ASTNodeKind getFromNodeKind() { + template <class T> static ASTNodeKind getFromNodeKind() { return ASTNodeKind(KindToKindId<T>::Id); } @@ -63,6 +62,7 @@ static ASTNodeKind getFromNode(const Decl &D); static ASTNodeKind getFromNode(const Stmt &S); static ASTNodeKind getFromNode(const Type &T); + static ASTNodeKind getFromNode(const TypeLoc &T); static ASTNodeKind getFromNode(const OMPClause &C); static ASTNodeKind getFromNode(const Attr &A); /// \} @@ -133,6 +133,8 @@ NKI_TemplateName, NKI_NestedNameSpecifierLoc, NKI_QualType, +#define TYPELOC(CLASS, PARENT) NKI_##CLASS##TypeLoc, +#include "clang/AST/TypeLocNodes.def" NKI_TypeLoc, NKI_LastKindWithoutPointerIdentity = NKI_TypeLoc, NKI_CXXBaseSpecifier, @@ -172,8 +174,7 @@ template <class T> struct KindToKindId { static const NodeKindId Id = NKI_None; }; - template <class T> - struct KindToKindId<const T> : KindToKindId<T> {}; + template <class T> struct KindToKindId<const T> : KindToKindId<T> {}; /// Per kind info. struct KindInfo { @@ -198,6 +199,8 @@ KIND_TO_KIND_ID(NestedNameSpecifier) KIND_TO_KIND_ID(NestedNameSpecifierLoc) KIND_TO_KIND_ID(QualType) +#define TYPELOC(CLASS, PARENT) KIND_TO_KIND_ID(CLASS##TypeLoc) +#include "clang/AST/TypeLocNodes.def" KIND_TO_KIND_ID(TypeLoc) KIND_TO_KIND_ID(Decl) KIND_TO_KIND_ID(Stmt) @@ -238,8 +241,7 @@ class DynTypedNode { public: /// Creates a \c DynTypedNode from \c Node. - template <typename T> - static DynTypedNode create(const T &Node) { + template <typename T> static DynTypedNode create(const T &Node) { return BaseConverter<T>::create(Node); } @@ -262,8 +264,7 @@ /// Retrieve the stored node as type \c T. /// /// Similar to \c get(), but asserts that the type is what we are expecting. - template <typename T> - const T &getUnchecked() const { + template <typename T> const T &getUnchecked() const { return BaseConverter<T>::getUnchecked(NodeKind, &Storage); } @@ -304,7 +305,7 @@ return getUnchecked<QualType>().getAsOpaquePtr() < Other.getUnchecked<QualType>().getAsOpaquePtr(); - if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind)) { + if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(NodeKind)) { auto TLA = getUnchecked<TypeLoc>(); auto TLB = Other.getUnchecked<TypeLoc>(); return std::make_pair(TLA.getType().getAsOpaquePtr(), @@ -336,7 +337,7 @@ if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind)) return getUnchecked<QualType>() == Other.getUnchecked<QualType>(); - if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind)) + if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(NodeKind)) return getUnchecked<TypeLoc>() == Other.getUnchecked<TypeLoc>(); if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(NodeKind)) @@ -365,7 +366,7 @@ } static unsigned getHashValue(const DynTypedNode &Val) { // FIXME: Add hashing support for the remaining types. - if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(Val.NodeKind)) { + if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(Val.NodeKind)) { auto TL = Val.getUnchecked<TypeLoc>(); return llvm::hash_combine(TL.getType().getAsOpaquePtr(), TL.getOpaqueData()); @@ -455,6 +456,29 @@ } }; + /// Converter that stores nodes by value. It must be possible to dynamically + /// cast the stored node within a type hierarchy without breaking (especially + /// through slicing). + template <typename T, typename BaseT, + typename = std::enable_if_t<(sizeof(T) == sizeof(BaseT))>> + struct DynCastValueConverter { + static const T *get(ASTNodeKind NodeKind, const void *Storage) { + if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)) + return &getUnchecked(NodeKind, Storage); + return nullptr; + } + static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) { + assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)); + return *static_cast<const T *>(reinterpret_cast<const BaseT *>(Storage)); + } + static DynTypedNode create(const BaseT &Node) { + DynTypedNode Result; + Result.NodeKind = ASTNodeKind::getFromNode(Node); + new (&Result.Storage) BaseT(Node); + return Result; + } + }; + ASTNodeKind NodeKind; /// Stores the data of the node. @@ -497,37 +521,37 @@ : public DynCastPtrConverter<T, Attr> {}; template <> -struct DynTypedNode::BaseConverter< - NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {}; +struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> + : public PtrConverter<NestedNameSpecifier> {}; template <> -struct DynTypedNode::BaseConverter< - CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {}; +struct DynTypedNode::BaseConverter<CXXCtorInitializer, void> + : public PtrConverter<CXXCtorInitializer> {}; template <> -struct DynTypedNode::BaseConverter< - TemplateArgument, void> : public ValueConverter<TemplateArgument> {}; +struct DynTypedNode::BaseConverter<TemplateArgument, void> + : public ValueConverter<TemplateArgument> {}; template <> struct DynTypedNode::BaseConverter<TemplateArgumentLoc, void> : public ValueConverter<TemplateArgumentLoc> {}; template <> -struct DynTypedNode::BaseConverter< - TemplateName, void> : public ValueConverter<TemplateName> {}; +struct DynTypedNode::BaseConverter<TemplateName, void> + : public ValueConverter<TemplateName> {}; template <> -struct DynTypedNode::BaseConverter< - NestedNameSpecifierLoc, - void> : public ValueConverter<NestedNameSpecifierLoc> {}; +struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> + : public ValueConverter<NestedNameSpecifierLoc> {}; template <> -struct DynTypedNode::BaseConverter<QualType, - void> : public ValueConverter<QualType> {}; +struct DynTypedNode::BaseConverter<QualType, void> + : public ValueConverter<QualType> {}; -template <> +template <typename T> struct DynTypedNode::BaseConverter< - TypeLoc, void> : public ValueConverter<TypeLoc> {}; + T, std::enable_if_t<std::is_base_of<TypeLoc, T>::value>> + : public DynCastValueConverter<T, TypeLoc> {}; template <> struct DynTypedNode::BaseConverter<CXXBaseSpecifier, void> @@ -553,6 +577,6 @@ template <> struct DenseMapInfo<clang::DynTypedNode> : clang::DynTypedNode::DenseMapInfo {}; -} // end namespace llvm +} // end namespace llvm #endif
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits