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 @@ +Matcher<StmtExpr>hasFinalExprMatcher<Expr> InnerMatcher +
Matches the result value expression of a GNU statement expression.
+
+Given
+  ({int *Ptr; *Ptr;});
+hasFinalExpr(unaryOperator())
+  matches '({int *Ptr; *Ptr;})'
+with unaryOperator()
+  matching '*Ptr'
+
+ + Matcher<Stmt>alignOfExprMatcher<UnaryExprOrTypeTraitExpr> InnerMatcher
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 {"