[clang] Support `constexpr` for some `ASTNodeKind` member functions
authorEric Li <li.zhe.hua@gmail.com>
Wed, 12 Oct 2022 20:28:59 +0000 (16:28 -0400)
committerEric Li <li.zhe.hua@gmail.com>
Thu, 13 Oct 2022 17:00:48 +0000 (13:00 -0400)
Add `constexpr` support for:

  * The `getFromNodeKind` factory function
  * `isSame`
  * `isNone`
  * `hasPointerIdentity`

This enables these functions to be used in SFINAE context for AST node
types.

Differential Revision: https://reviews.llvm.org/D135816

clang/include/clang/AST/ASTTypeTraits.h
clang/unittests/AST/ASTTypeTraitsTest.cpp

index cd6b514..8713221 100644 (file)
@@ -51,11 +51,10 @@ enum TraversalKind {
 class ASTNodeKind {
 public:
   /// Empty identifier. It matches nothing.
-  ASTNodeKind() : KindId(NKI_None) {}
+  constexpr ASTNodeKind() : KindId(NKI_None) {}
 
   /// Construct an identifier for T.
-  template <class T>
-  static ASTNodeKind getFromNodeKind() {
+  template <class T> static constexpr ASTNodeKind getFromNodeKind() {
     return ASTNodeKind(KindToKindId<T>::Id);
   }
 
@@ -71,12 +70,12 @@ public:
   /// \}
 
   /// Returns \c true if \c this and \c Other represent the same kind.
-  bool isSame(ASTNodeKind Other) const {
+  constexpr bool isSame(ASTNodeKind Other) const {
     return KindId != NKI_None && KindId == Other.KindId;
   }
 
   /// Returns \c true only for the default \c ASTNodeKind()
-  bool isNone() const { return KindId == NKI_None; }
+  constexpr bool isNone() const { return KindId == NKI_None; }
 
   /// Returns \c true if \c this is a base kind of (or same as) \c Other.
   /// \param Distance If non-null, used to return the distance between \c this
@@ -87,7 +86,7 @@ public:
   StringRef asStringRef() const;
 
   /// Strict weak ordering for ASTNodeKind.
-  bool operator<(const ASTNodeKind &Other) const {
+  constexpr bool operator<(const ASTNodeKind &Other) const {
     return KindId < Other.KindId;
   }
 
@@ -121,7 +120,7 @@ public:
 
   /// Check if the given ASTNodeKind identifies a type that offers pointer
   /// identity. This is useful for the fast path in DynTypedNode.
-  bool hasPointerIdentity() const {
+  constexpr bool hasPointerIdentity() const {
     return KindId > NKI_LastKindWithoutPointerIdentity;
   }
 
@@ -165,7 +164,7 @@ private:
   };
 
   /// Use getFromNodeKind<T>() to construct the kind.
-  ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
+  constexpr ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
 
   /// Returns \c true if \c Base is a base kind of (or same as) \c
   ///   Derived.
index 9fcb006..dcea32d 100644 (file)
@@ -117,6 +117,47 @@ TEST(ASTNodeKind, UnknownKind) {
   EXPECT_FALSE(DNT<Foo>().isSame(DNT<Foo>()));
 }
 
+template <typename T>
+constexpr bool HasPointerIdentity =
+    ASTNodeKind::getFromNodeKind<T>().hasPointerIdentity();
+
+TEST(ASTNodeKind, ConstexprHasPointerIdentity) {
+  EXPECT_TRUE(HasPointerIdentity<Decl>);
+  EXPECT_TRUE(HasPointerIdentity<Stmt>);
+  EXPECT_FALSE(HasPointerIdentity<TypeLoc>);
+  EXPECT_FALSE(HasPointerIdentity<QualType>);
+  EXPECT_FALSE(HasPointerIdentity<Foo>);
+
+  constexpr bool DefaultConstructedHasPointerIdentity =
+      ASTNodeKind().hasPointerIdentity();
+  EXPECT_FALSE(DefaultConstructedHasPointerIdentity);
+}
+
+template <typename T, typename U>
+constexpr bool NodeKindIsSame =
+    ASTNodeKind::getFromNodeKind<T>().isSame(ASTNodeKind::getFromNodeKind<U>());
+
+TEST(ASTNodeKind, ConstexprIsSame) {
+  EXPECT_TRUE((NodeKindIsSame<Decl, Decl>));
+  EXPECT_FALSE((NodeKindIsSame<Decl, VarDecl>));
+  EXPECT_FALSE((NodeKindIsSame<Foo, Foo>));
+
+  constexpr bool DefaultConstructedIsSameToDefaultConstructed =
+      ASTNodeKind().isSame(ASTNodeKind());
+  EXPECT_FALSE(DefaultConstructedIsSameToDefaultConstructed);
+}
+
+template <typename T>
+constexpr bool NodeKindIsNone = ASTNodeKind::getFromNodeKind<T>().isNone();
+
+TEST(ASTNodeKind, ConstexprIsNone) {
+  EXPECT_FALSE(NodeKindIsNone<Decl>);
+  EXPECT_TRUE(NodeKindIsNone<Foo>);
+
+  constexpr bool DefaultConstructedIsNone = ASTNodeKind().isNone();
+  EXPECT_TRUE(DefaultConstructedIsNone);
+}
+
 TEST(ASTNodeKind, Name) {
   EXPECT_EQ("<None>", ASTNodeKind().asStringRef());
 #define VERIFY_NAME(Node) EXPECT_EQ(#Node, DNT<Node>().asStringRef());