diff --git a/clang/include/clang/AST/ASTTypeTraits.h b/clang/include/clang/AST/ASTTypeTraits.h --- a/clang/include/clang/AST/ASTTypeTraits.h +++ b/clang/include/clang/AST/ASTTypeTraits.h @@ -53,8 +53,7 @@ ASTNodeKind() : KindId(NKI_None) {} /// Construct an identifier for T. - template - static ASTNodeKind getFromNodeKind() { + template static ASTNodeKind getFromNodeKind() { return ASTNodeKind(KindToKindId::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 struct KindToKindId { static const NodeKindId Id = NKI_None; }; - template - struct KindToKindId : KindToKindId {}; + template struct KindToKindId : KindToKindId {}; /// 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 - static DynTypedNode create(const T &Node) { + template static DynTypedNode create(const T &Node) { return BaseConverter::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 - const T &getUnchecked() const { + template const T &getUnchecked() const { return BaseConverter::getUnchecked(NodeKind, &Storage); } @@ -304,7 +305,7 @@ return getUnchecked().getAsOpaquePtr() < Other.getUnchecked().getAsOpaquePtr(); - if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) { + if (ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)) { auto TLA = getUnchecked(); auto TLB = Other.getUnchecked(); return std::make_pair(TLA.getType().getAsOpaquePtr(), @@ -336,7 +337,7 @@ if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) return getUnchecked() == Other.getUnchecked(); - if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) + if (ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)) return getUnchecked() == Other.getUnchecked(); if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) @@ -365,7 +366,7 @@ } static unsigned getHashValue(const DynTypedNode &Val) { // FIXME: Add hashing support for the remaining types. - if (ASTNodeKind::getFromNodeKind().isSame(Val.NodeKind)) { + if (ASTNodeKind::getFromNodeKind().isBaseOf(Val.NodeKind)) { auto TL = Val.getUnchecked(); 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 > + struct DynCastValueConverter { + static const T *get(ASTNodeKind NodeKind, const void *Storage) { + if (ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)) + return &getUnchecked(NodeKind, Storage); + return nullptr; + } + static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) { + assert(ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)); + return *static_cast(reinterpret_cast(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 {}; template <> -struct DynTypedNode::BaseConverter< - NestedNameSpecifier, void> : public PtrConverter {}; +struct DynTypedNode::BaseConverter + : public PtrConverter {}; template <> -struct DynTypedNode::BaseConverter< - CXXCtorInitializer, void> : public PtrConverter {}; +struct DynTypedNode::BaseConverter + : public PtrConverter {}; template <> -struct DynTypedNode::BaseConverter< - TemplateArgument, void> : public ValueConverter {}; +struct DynTypedNode::BaseConverter + : public ValueConverter {}; template <> struct DynTypedNode::BaseConverter : public ValueConverter {}; template <> -struct DynTypedNode::BaseConverter< - TemplateName, void> : public ValueConverter {}; +struct DynTypedNode::BaseConverter + : public ValueConverter {}; template <> -struct DynTypedNode::BaseConverter< - NestedNameSpecifierLoc, - void> : public ValueConverter {}; +struct DynTypedNode::BaseConverter + : public ValueConverter {}; template <> -struct DynTypedNode::BaseConverter : public ValueConverter {}; +struct DynTypedNode::BaseConverter + : public ValueConverter {}; -template <> +template struct DynTypedNode::BaseConverter< - TypeLoc, void> : public ValueConverter {}; + T, std::enable_if_t::value>> + : public DynCastValueConverter {}; template <> struct DynTypedNode::BaseConverter @@ -553,6 +577,6 @@ template <> struct DenseMapInfo : clang::DynTypedNode::DenseMapInfo {}; -} // end namespace llvm +} // end namespace llvm #endif diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/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