diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -5805,14 +5805,15 @@ Matcher<Expr>ignoringElidableConstructorCallast_matchers::Matcher<Expr> InnerMatcher
Matches expressions that match InnerMatcher that are possibly wrapped in an
-elidable constructor.
+elidable constructor and other corresponding bookkeeping nodes.
 
-In C++17 copy elidable constructors are no longer being
-generated in the AST as it is not permitted by the standard. They are
-however part of the AST in C++14 and earlier. Therefore, to write a matcher
-that works in all language modes, the matcher has to skip elidable
-constructor AST nodes if they appear in the AST. This matcher can be used to
-skip those elidable constructors.
+In C++17 copy elidable constructors are no longer being generated in the AST
+as it is not permitted by the standard. They are, however, part of the AST
+in C++14 and earlier. So, a matcher must elide these differences to work in
+all language modes. This matcher supports such elision by skipping elidable
+constructor-call AST nodes, `ExprWithCleanups` nodes wrapping elidable
+constructor-calls and various implicit nodes inside the constructor calls,
+all of which will not appear in the C++17 AST.
 
 Given
 
@@ -5822,10 +5823,8 @@
   H D = G();
 }
 
-``varDecl(hasInitializer(any(
-      ignoringElidableConstructorCall(callExpr()),
-      exprWithCleanups(ignoringElidableConstructorCall(callExpr()))))``
-matches ``H D = G()``
+``varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))``
+matches ``H D = G()`` in C++11 through C++17 (and beyond).
 
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 @@ -6533,14 +6533,15 @@ } /// Matches expressions that match InnerMatcher that are possibly wrapped in an -/// elidable constructor. +/// elidable constructor and other corresponding bookkeeping nodes. /// -/// In C++17 copy elidable constructors are no longer being -/// generated in the AST as it is not permitted by the standard. They are -/// however part of the AST in C++14 and earlier. Therefore, to write a matcher -/// that works in all language modes, the matcher has to skip elidable -/// constructor AST nodes if they appear in the AST. This matcher can be used to -/// skip those elidable constructors. +/// In C++17, elidable copy constructors are no longer being generated in the +/// AST as it is not permitted by the standard. They are, however, part of the +/// AST in C++14 and earlier. So, a matcher must abstract over these differences +/// to work in all language modes. This matcher skips elidable constructor-call +/// AST nodes, `ExprWithCleanups` nodes wrapping elidable constructor-calls and +/// various implicit nodes inside the constructor calls, all of which will not +/// appear in the C++17 AST. /// /// Given /// @@ -6552,13 +6553,20 @@ /// } /// \endcode /// -/// ``varDecl(hasInitializer(any( -/// ignoringElidableConstructorCall(callExpr()), -/// exprWithCleanups(ignoringElidableConstructorCall(callExpr()))))`` -/// matches ``H D = G()`` +/// ``varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))`` +/// matches ``H D = G()`` in C++11 through C++17 (and beyond). AST_MATCHER_P(Expr, ignoringElidableConstructorCall, ast_matchers::internal::Matcher, InnerMatcher) { - if (const auto *CtorExpr = dyn_cast(&Node)) { + // E tracks the node that we are examining. + const Expr *E = &Node; + // If present, remove an outer `ExprWithCleanups` corresponding to the + // underlying `CXXConstructExpr`. This check won't cover all cases of added + // `ExprWithCleanups` corresponding to `CXXConstructExpr` nodes (because the + // EWC is placed on the outermost node of the expression, which this may not + // be), but, it still improves the coverage of this matcher. + if (const auto *CleanupsExpr = dyn_cast(&Node)) + E = CleanupsExpr->getSubExpr(); + if (const auto *CtorExpr = dyn_cast(E)) { if (CtorExpr->isElidable()) { if (const auto *MaterializeTemp = dyn_cast(CtorExpr->getArg(0))) { 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 @@ -671,6 +671,23 @@ LanguageMode::Cxx11OrLater)); } +TEST(Matcher, IgnoresElidableInVarInit) { + auto matcher = + varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr()))); + EXPECT_TRUE(matches("struct H {};" + "H G();" + "void f(H D = G()) {" + " return;" + "}", + matcher, LanguageMode::Cxx11OrLater)); + EXPECT_TRUE(matches("struct H {};" + "H G();" + "void f() {" + " H D = G();" + "}", + matcher, LanguageMode::Cxx11OrLater)); +} + TEST(Matcher, BindTheSameNameInAlternatives) { StatementMatcher matcher = anyOf( binaryOperator(hasOperatorName("+"),