diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -5628,6 +5628,19 @@ +
Matches constinit variable declarations. + +Given: + constinit int foo = 42; + constinit const char* bar = "baz"; + int baz = 42; + [[clang::require_constant_initialization]] int xyz = 42; +varDecl(isConstinit()) + matches the declaration of `foo` and `bar`, but not `baz` and `xyz`. +
Matches if a declaration has a body attached. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -323,6 +323,8 @@ underlying type. - Added the ``isConsteval`` matcher to match ``consteval`` function declarations as well as `if consteval` and `if ! consteval` statements. +- Added the ``isConstinit`` matcher to match ``constinit`` variable + declarations. clang-format ------------ diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -5211,6 +5211,23 @@ return Node.isConstexpr(); } +/// Matches constinit variable declarations. +/// +/// Given: +/// \code +/// constinit int foo = 42; +/// constinit const char* bar = "bar"; +/// int baz = 42; +/// [[clang::require_constant_initialization]] int xyz = 42; +/// \endcode +/// varDecl(isConstinit()) +/// matches the declaration of `foo` and `bar`, but not `baz` and `xyz`. +AST_MATCHER(VarDecl, isConstinit) { + if (const auto *CIA = Node.getAttr()) + return CIA->isConstinit(); + return false; +} + /// Matches selection statements with initializer. /// /// Given: diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -406,6 +406,7 @@ REGISTER_MATCHER(isConstQualified); REGISTER_MATCHER(isConsteval); REGISTER_MATCHER(isConstexpr); + REGISTER_MATCHER(isConstinit); REGISTER_MATCHER(isCopyAssignmentOperator); REGISTER_MATCHER(isCopyConstructor); REGISTER_MATCHER(isDefaultConstructor); diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -1841,6 +1841,25 @@ notMatches("void baz() { if (1 > 0) {} }", ifStmt(isConstexpr()))); } +TEST_P(ASTMatchersTest, IsConstinit) { + if (!GetParam().isCXX20OrLater()) + return; + + EXPECT_TRUE(matches("constinit int foo = 1;", + varDecl(hasName("foo"), isConstinit()))); + EXPECT_TRUE(matches("extern constinit int foo;", + varDecl(hasName("foo"), isConstinit()))); + EXPECT_TRUE(matches("constinit const char* foo = \"bar\";", + varDecl(hasName("foo"), isConstinit()))); + EXPECT_TRUE( + notMatches("[[clang::require_constant_initialization]] int foo = 1;", + varDecl(hasName("foo"), isConstinit()))); + EXPECT_TRUE(notMatches("constexpr int foo = 1;", + varDecl(hasName("foo"), isConstinit()))); + EXPECT_TRUE(notMatches("static inline int foo = 1;", + varDecl(hasName("foo"), isConstinit()))); +} + TEST_P(ASTMatchersTest, HasInitStatement_MatchesSelectionInitializers) { EXPECT_TRUE(notMatches("void baz() { if (1 > 0) {} }", ifStmt(hasInitStatement(anything()))));