diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -7188,6 +7188,18 @@ +
Matches the result value expression of a GNU statement expression.
+
+Given
+ ({int *Ptr; *Ptr;});
+hasFinalExpr(unaryOperator())
+ matches '({int *Ptr; *Ptr;})'
+with unaryOperator()
+ matching '*Ptr'
+Same as unaryExprOrTypeTraitExpr, but only matching
alignof.
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
@@ -6729,6 +6729,24 @@
return false;
}
+/// Matches the result value expression of a GNU statement expression.
+///
+/// Given
+/// \code
+/// ({int *Ptr; *Ptr;});
+/// \endcode
+/// hasFinalExpr(unaryOperator())
+/// matches '({int *Ptr; *Ptr;})'
+/// with unaryOperator()
+/// matching '*Ptr'
+AST_MATCHER_P(StmtExpr, hasFinalExpr, internal::Matcher, InnerMatcher) {
+ if (const CompoundStmt *CS = Node.getSubStmt()) {
+ if (const auto *E = dyn_cast_or_null(CS->body_back()))
+ return InnerMatcher.matches(*E, Finder, Builder);
+ }
+ return false;
+}
+
/// Matches CUDA kernel call expression.
///
/// Example matches,
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -3006,6 +3006,13 @@
EXPECT_FALSE(matches("void F() { return; }", RetVal));
}
+TEST(StatementMatcher, hasFinalExpr) {
+ StatementMatcher RetVal = stmtExpr(hasFinalExpr(binaryOperator()));
+ EXPECT_TRUE(matches("void F() { ({int a, b; a + b;}); }", RetVal));
+ EXPECT_FALSE(matches("void F() { ({int a; a;}); }", RetVal));
+ EXPECT_FALSE(matches("void F() { ({int a;}); }", RetVal));
+}
+
TEST(StatementMatcher, ForFunction) {
const auto CppString1 =
"struct PosVec {"