r363262 - Added AST matcher for ignoring elidable constructors
Dmitri Gribenko via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 13 06:48:24 PDT 2019
Author: gribozavr
Date: Thu Jun 13 06:48:24 2019
New Revision: 363262
URL: http://llvm.org/viewvc/llvm-project?rev=363262&view=rev
Log:
Added AST matcher for ignoring elidable constructors
Summary: Added AST matcher for ignoring elidable move constructors
Reviewers: hokein, gribozavr
Reviewed By: hokein, gribozavr
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63149
Patch by Johan Vikström.
Modified:
cfe/trunk/docs/LibASTMatchersReference.html
cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h
Modified: cfe/trunk/docs/LibASTMatchersReference.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LibASTMatchersReference.html?rev=363262&r1=363261&r2=363262&view=diff
==============================================================================
--- cfe/trunk/docs/LibASTMatchersReference.html (original)
+++ cfe/trunk/docs/LibASTMatchersReference.html Thu Jun 13 06:48:24 2019
@@ -5728,6 +5728,32 @@ Example matches x (matcher = expr(hasTyp
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('ignoringElidableConstructorCall0')"><a name="ignoringElidableConstructorCall0Anchor">ignoringElidableConstructorCall</a></td><td>ast_matchers::Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="ignoringElidableConstructorCall0"><pre>Matches expressions that match InnerMatcher that are possibly wrapped in an
+elidable constructor.
+
+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.
+
+Given
+
+struct H {};
+H G();
+void f() {
+ H D = G();
+}
+
+``varDecl(hasInitializer(any(
+ ignoringElidableConstructorCall(callExpr()),
+ exprWithCleanups(ignoringElidableConstructorCall(callExpr()))))``
+matches ``H D = G()``
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('ignoringImpCasts0')"><a name="ignoringImpCasts0Anchor">ignoringImpCasts</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="ignoringImpCasts0"><pre>Matches expressions that match InnerMatcher after any implicit casts
are stripped off.
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=363262&r1=363261&r2=363262&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Thu Jun 13 06:48:24 2019
@@ -6452,6 +6452,44 @@ AST_MATCHER(FunctionDecl, hasTrailingRet
return false;
}
+/// Matches expressions that match InnerMatcher that are possibly wrapped in an
+/// elidable constructor.
+///
+/// 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.
+///
+/// Given
+///
+/// \code
+/// struct H {};
+/// H G();
+/// void f() {
+/// H D = G();
+/// }
+/// \endcode
+///
+/// ``varDecl(hasInitializer(any(
+/// ignoringElidableConstructorCall(callExpr()),
+/// exprWithCleanups(ignoringElidableConstructorCall(callExpr()))))``
+/// matches ``H D = G()``
+AST_MATCHER_P(Expr, ignoringElidableConstructorCall,
+ ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
+ if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(&Node)) {
+ if (CtorExpr->isElidable()) {
+ if (const auto *MaterializeTemp =
+ dyn_cast<MaterializeTemporaryExpr>(CtorExpr->getArg(0))) {
+ return InnerMatcher.matches(*MaterializeTemp->GetTemporaryExpr(),
+ Finder, Builder);
+ }
+ }
+ }
+ return InnerMatcher.matches(Node, Finder, Builder);
+}
+
//----------------------------------------------------------------------------//
// OpenMP handling.
//----------------------------------------------------------------------------//
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=363262&r1=363261&r2=363262&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Thu Jun 13 06:48:24 2019
@@ -320,6 +320,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasUnqualifiedDesugaredType);
REGISTER_MATCHER(hasValueType);
REGISTER_MATCHER(ifStmt);
+ REGISTER_MATCHER(ignoringElidableConstructorCall);
REGISTER_MATCHER(ignoringImpCasts);
REGISTER_MATCHER(ignoringImplicit);
REGISTER_MATCHER(ignoringParenCasts);
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp?rev=363262&r1=363261&r2=363262&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Thu Jun 13 06:48:24 2019
@@ -566,6 +566,74 @@ TEST(Matcher, BindMatchedNodes) {
llvm::make_unique<VerifyIdIsBoundTo<CXXMemberCallExpr>>("x")));
}
+TEST(Matcher, IgnoresElidableConstructors) {
+ EXPECT_TRUE(
+ matches("struct H {};"
+ "template<typename T> H B(T A);"
+ "void f() {"
+ " H D1;"
+ " D1 = B(B(1));"
+ "}",
+ cxxOperatorCallExpr(hasArgument(
+ 1, callExpr(hasArgument(
+ 0, ignoringElidableConstructorCall(callExpr()))))),
+ LanguageMode::Cxx11OrLater));
+ EXPECT_TRUE(
+ matches("struct H {};"
+ "template<typename T> H B(T A);"
+ "void f() {"
+ " H D1;"
+ " D1 = B(1);"
+ "}",
+ cxxOperatorCallExpr(hasArgument(
+ 1, callExpr(hasArgument(0, ignoringElidableConstructorCall(
+ integerLiteral()))))),
+ LanguageMode::Cxx11OrLater));
+ EXPECT_TRUE(matches(
+ "struct H {};"
+ "H G();"
+ "void f() {"
+ " H D = G();"
+ "}",
+ varDecl(hasInitializer(anyOf(
+ ignoringElidableConstructorCall(callExpr()),
+ exprWithCleanups(has(ignoringElidableConstructorCall(callExpr())))))),
+ LanguageMode::Cxx11OrLater));
+}
+
+TEST(Matcher, IgnoresElidableInReturn) {
+ auto matcher = expr(ignoringElidableConstructorCall(declRefExpr()));
+ EXPECT_TRUE(matches("struct H {};"
+ "H f() {"
+ " H g;"
+ " return g;"
+ "}",
+ matcher, LanguageMode::Cxx11OrLater));
+ EXPECT_TRUE(notMatches("struct H {};"
+ "H f() {"
+ " return H();"
+ "}",
+ matcher, LanguageMode::Cxx11OrLater));
+}
+
+TEST(Matcher, IgnoreElidableConstructorDoesNotMatchConstructors) {
+ EXPECT_TRUE(matches("struct H {};"
+ "void f() {"
+ " H D;"
+ "}",
+ varDecl(hasInitializer(
+ ignoringElidableConstructorCall(cxxConstructExpr()))),
+ LanguageMode::Cxx11OrLater));
+}
+
+TEST(Matcher, IgnoresElidableDoesNotPreventMatches) {
+ EXPECT_TRUE(matches("void f() {"
+ " int D = 10;"
+ "}",
+ expr(ignoringElidableConstructorCall(integerLiteral())),
+ LanguageMode::Cxx11OrLater));
+}
+
TEST(Matcher, BindTheSameNameInAlternatives) {
StatementMatcher matcher = anyOf(
binaryOperator(hasOperatorName("+"),
@@ -914,10 +982,10 @@ TEST(isConstexpr, MatchesConstexprDeclar
varDecl(hasName("foo"), isConstexpr())));
EXPECT_TRUE(matches("constexpr int bar();",
functionDecl(hasName("bar"), isConstexpr())));
- EXPECT_TRUE(matchesConditionally("void baz() { if constexpr(1 > 0) {} }",
- ifStmt(isConstexpr()), true, "-std=c++17"));
- EXPECT_TRUE(matchesConditionally("void baz() { if (1 > 0) {} }",
- ifStmt(isConstexpr()), false, "-std=c++17"));
+ EXPECT_TRUE(matches("void baz() { if constexpr(1 > 0) {} }",
+ ifStmt(isConstexpr()), LanguageMode::Cxx17OrLater));
+ EXPECT_TRUE(notMatches("void baz() { if (1 > 0) {} }", ifStmt(isConstexpr()),
+ LanguageMode::Cxx17OrLater));
}
TEST(TemplateArgumentCountIs, Matches) {
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h?rev=363262&r1=363261&r2=363262&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h Thu Jun 13 06:48:24 2019
@@ -57,6 +57,17 @@ private:
const std::unique_ptr<BoundNodesCallback> FindResultReviewer;
};
+enum class LanguageMode {
+ Cxx11,
+ Cxx14,
+ Cxx17,
+ Cxx2a,
+ Cxx11OrLater,
+ Cxx14OrLater,
+ Cxx17OrLater,
+ Cxx2aOrLater
+};
+
template <typename T>
testing::AssertionResult matchesConditionally(
const std::string &Code, const T &AMatcher, bool ExpectMatch,
@@ -116,14 +127,71 @@ testing::AssertionResult matchesConditio
}
template <typename T>
-testing::AssertionResult matches(const std::string &Code, const T &AMatcher) {
- return matchesConditionally(Code, AMatcher, true, "-std=c++11");
+testing::AssertionResult
+matchesConditionally(const std::string &Code, const T &AMatcher,
+ bool ExpectMatch, const LanguageMode &Mode) {
+ std::vector<LanguageMode> LangModes;
+ switch (Mode) {
+ case LanguageMode::Cxx11:
+ case LanguageMode::Cxx14:
+ case LanguageMode::Cxx17:
+ case LanguageMode::Cxx2a:
+ LangModes = {Mode};
+ break;
+ case LanguageMode::Cxx11OrLater:
+ LangModes = {LanguageMode::Cxx11, LanguageMode::Cxx14, LanguageMode::Cxx17,
+ LanguageMode::Cxx2a};
+ break;
+ case LanguageMode::Cxx14OrLater:
+ LangModes = {LanguageMode::Cxx14, LanguageMode::Cxx17, LanguageMode::Cxx2a};
+ break;
+ case LanguageMode::Cxx17OrLater:
+ LangModes = {LanguageMode::Cxx17, LanguageMode::Cxx2a};
+ break;
+ case LanguageMode::Cxx2aOrLater:
+ LangModes = {LanguageMode::Cxx2a};
+ }
+
+ for (auto Mode : LangModes) {
+ std::string LangModeArg;
+ switch (Mode) {
+ case LanguageMode::Cxx11:
+ LangModeArg = "-std=c++11";
+ break;
+ case LanguageMode::Cxx14:
+ LangModeArg = "-std=c++14";
+ break;
+ case LanguageMode::Cxx17:
+ LangModeArg = "-std=c++17";
+ break;
+ case LanguageMode::Cxx2a:
+ LangModeArg = "-std=c++2a";
+ break;
+ default:
+ llvm_unreachable("Invalid language mode");
+ }
+
+ auto Result =
+ matchesConditionally(Code, AMatcher, ExpectMatch, LangModeArg);
+ if (!Result)
+ return Result;
+ }
+
+ return testing::AssertionSuccess();
+}
+
+template <typename T>
+testing::AssertionResult
+matches(const std::string &Code, const T &AMatcher,
+ const LanguageMode &Mode = LanguageMode::Cxx11) {
+ return matchesConditionally(Code, AMatcher, true, Mode);
}
template <typename T>
-testing::AssertionResult notMatches(const std::string &Code,
- const T &AMatcher) {
- return matchesConditionally(Code, AMatcher, false, "-std=c++11");
+testing::AssertionResult
+notMatches(const std::string &Code, const T &AMatcher,
+ const LanguageMode &Mode = LanguageMode::Cxx11) {
+ return matchesConditionally(Code, AMatcher, false, Mode);
}
template <typename T>
More information about the cfe-commits
mailing list