Fix Stmt::ignoreImplicit
authorStephen Kelly <steveire@gmail.com>
Tue, 14 Aug 2018 21:33:28 +0000 (21:33 +0000)
committerStephen Kelly <steveire@gmail.com>
Tue, 14 Aug 2018 21:33:28 +0000 (21:33 +0000)
Summary:
A CXXBindTemporaryExpr can appear inside an ImplicitCastExpr, and was
not ignored previously.

Fixes the case reported in PR37327.

Reviewers: rsmith, dblaikie, klimek

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D50666

llvm-svn: 339730

clang/lib/AST/Stmt.cpp
clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

index 5fce633..6ed71fd 100644 (file)
@@ -113,17 +113,23 @@ void Stmt::EnableStatistics() {
 Stmt *Stmt::IgnoreImplicit() {
   Stmt *s = this;
 
-  if (auto *ewc = dyn_cast<ExprWithCleanups>(s))
-    s = ewc->getSubExpr();
+  Stmt *lasts = nullptr;
 
-  if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s))
-    s = mte->GetTemporaryExpr();
+  while (s != lasts) {
+    lasts = s;
 
-  if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s))
-    s = bte->getSubExpr();
+    if (auto *ewc = dyn_cast<ExprWithCleanups>(s))
+      s = ewc->getSubExpr();
 
-  while (auto *ice = dyn_cast<ImplicitCastExpr>(s))
-    s = ice->getSubExpr();
+    if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s))
+      s = mte->GetTemporaryExpr();
+
+    if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s))
+      s = bte->getSubExpr();
+
+    if (auto *ice = dyn_cast<ImplicitCastExpr>(s))
+      s = ice->getSubExpr();
+  }
 
   return s;
 }
index 443b058..52ab544 100644 (file)
@@ -1321,6 +1321,45 @@ TEST(IgnoringImplicit, MatchesImplicit) {
                       varDecl(has(ignoringImplicit(cxxConstructExpr())))));
 }
 
+TEST(IgnoringImplicit, MatchesNestedImplicit) {
+  EXPECT_TRUE(matches(R"(
+
+struct OtherType;
+
+struct SomeType
+{
+    SomeType() {}
+    SomeType(const OtherType&) {}
+    SomeType& operator=(OtherType const&) { return *this; }
+};
+
+struct OtherType
+{
+    OtherType() {}
+    ~OtherType() {}
+};
+
+OtherType something()
+{
+    return {};
+}
+
+int main()
+{
+    SomeType i = something();
+}
+)"
+  , varDecl(
+      hasName("i"),
+      hasInitializer(exprWithCleanups(has(
+        cxxConstructExpr(has(expr(ignoringImplicit(cxxConstructExpr(
+          has(expr(ignoringImplicit(callExpr())))
+          )))))
+        )))
+      )
+  ));
+}
+
 TEST(IgnoringImplicit, DoesNotMatchIncorrectly) {
   EXPECT_TRUE(
       notMatches("class C {}; C a = C();", varDecl(has(cxxConstructExpr()))));