]> granicus.if.org Git - clang/commitdiff
Make CastExpr::getSubExprAsWritten look through implicit temporary under CK_Construct...
authorStephan Bergmann <sbergman@redhat.com>
Tue, 27 Jun 2017 08:19:09 +0000 (08:19 +0000)
committerStephan Bergmann <sbergman@redhat.com>
Tue, 27 Jun 2017 08:19:09 +0000 (08:19 +0000)
With

    struct S1 {};
    struct S2 { operator S1(); };
    S1 f(S2 s) { return static_cast<S1>(s); }

the static_cast expr is

    CXXStaticCastExpr 0x... 'struct S1' static_cast<struct S1> <ConstructorConversion>
    `-CXXConstructExpr 0x... 'struct S1' 'void (struct S1 &&) noexcept' elidable

    `-MaterializeTemporaryExpr 0x... 'struct S1' xvalue
      `-ImplicitCastExpr 0x... 'struct S1' <UserDefinedConversion>
        `-CXXMemberCallExpr 0x... 'struct S1'
          `-MemberExpr 0x... '<bound member function type>' .operator S1 0x...
            `-DeclRefExpr 0x... 'struct S2' lvalue ParmVar 0x... 's' 'struct S2'

getSubExprAsWritten used to return the MaterializeTemporaryExpr (of type S1)
under the CXXConstructExpr, instead of unwinding further to the DeclRefExpr (of
type S2) at the bottom.

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@306377 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/Expr.cpp
unittests/Tooling/CMakeLists.txt
unittests/Tooling/CastExprTest.cpp [new file with mode: 0644]

index c21cd3f65bd40dc1990ac86e60e29ea0a3574860..afc7fa8ea0949c0b192d7fc19d56145cb4a0976a 100644 (file)
@@ -1641,25 +1641,32 @@ const char *CastExpr::getCastKindName() const {
   llvm_unreachable("Unhandled cast kind!");
 }
 
+namespace {
+  Expr *skipImplicitTemporary(Expr *expr) {
+    // Skip through reference binding to temporary.
+    if (MaterializeTemporaryExpr *Materialize
+                                  = dyn_cast<MaterializeTemporaryExpr>(expr))
+      expr = Materialize->GetTemporaryExpr();
+
+    // Skip any temporary bindings; they're implicit.
+    if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(expr))
+      expr = Binder->getSubExpr();
+
+    return expr;
+  }
+}
+
 Expr *CastExpr::getSubExprAsWritten() {
   Expr *SubExpr = nullptr;
   CastExpr *E = this;
   do {
-    SubExpr = E->getSubExpr();
+    SubExpr = skipImplicitTemporary(E->getSubExpr());
 
-    // Skip through reference binding to temporary.
-    if (MaterializeTemporaryExpr *Materialize 
-                                  = dyn_cast<MaterializeTemporaryExpr>(SubExpr))
-      SubExpr = Materialize->GetTemporaryExpr();
-        
-    // Skip any temporary bindings; they're implicit.
-    if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr))
-      SubExpr = Binder->getSubExpr();
-    
     // Conversions by constructor and conversion functions have a
     // subexpression describing the call; strip it off.
     if (E->getCastKind() == CK_ConstructorConversion)
-      SubExpr = cast<CXXConstructExpr>(SubExpr)->getArg(0);
+      SubExpr =
+        skipImplicitTemporary(cast<CXXConstructExpr>(SubExpr)->getArg(0));
     else if (E->getCastKind() == CK_UserDefinedConversion) {
       assert((isa<CXXMemberCallExpr>(SubExpr) ||
               isa<BlockExpr>(SubExpr)) &&
index b5af99bdfd6da11d0829c2964efd497fdc7fac4c..8ed35480cb88da03ad640ab017ac31e4aa87ffc3 100644 (file)
@@ -11,6 +11,7 @@ if (MSVC)
 endif()
 
 add_clang_unittest(ToolingTests
+  CastExprTest.cpp
   CommentHandlerTest.cpp
   CompilationDatabaseTest.cpp
   FixItTest.cpp
diff --git a/unittests/Tooling/CastExprTest.cpp b/unittests/Tooling/CastExprTest.cpp
new file mode 100644 (file)
index 0000000..5310c21
--- /dev/null
@@ -0,0 +1,38 @@
+//===- unittest/Tooling/CastExprTest.cpp ----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestVisitor.h"
+
+using namespace clang;
+
+namespace {
+
+struct CastExprVisitor : TestVisitor<CastExprVisitor> {
+  std::function<void(ExplicitCastExpr *)> OnExplicitCast;
+
+  bool VisitExplicitCastExpr(ExplicitCastExpr *Expr) {
+    if (OnExplicitCast)
+      OnExplicitCast(Expr);
+    return true;
+  }
+};
+
+TEST(CastExprTest, GetSubExprAsWrittenThroughMaterializedTemporary) {
+    CastExprVisitor Visitor;
+    Visitor.OnExplicitCast = [](ExplicitCastExpr *Expr) {
+      auto Sub = Expr->getSubExprAsWritten();
+      EXPECT_TRUE(isa<DeclRefExpr>(Sub))
+        << "Expected DeclRefExpr, but saw " << Sub->getStmtClassName();
+    };
+    Visitor.runOver("struct S1 {};\n"
+                    "struct S2 { operator S1(); };\n"
+                    "S1 f(S2 s) { return static_cast<S1>(s); }\n");
+}
+
+}