[PATCH] D117391: [AST] Ignore implicit nodes in CastExpr::getConversionFunction

Kim Gräsman via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Sat Jan 15 02:17:51 PST 2022


kimgr created this revision.
kimgr requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Under -std=c++20 with use of consteval, the subexpression hierarchy sometimes
contains ConstantExpr nodes that getConversionFunction did not expect.

CastExpr::getConversionFunction is very rarely used, so this was difficult to
trigger in the compiler. It is possible to reproduce using -ast-dump=json, which
triggers an assertion for inputs with consteval implicit casts.

In AST-based tools, however, it surfaces quite easily if they try to inspect the
conversion function of a visited CastExpr.

Add two new testcases, both for implicit constructor conversions and
user-defined conversions with consteval.

Depends on D117390 <https://reviews.llvm.org/D117390>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D117391

Files:
  clang/lib/AST/Expr.cpp
  clang/unittests/Tooling/CastExprTest.cpp


Index: clang/unittests/Tooling/CastExprTest.cpp
===================================================================
--- clang/unittests/Tooling/CastExprTest.cpp
+++ clang/unittests/Tooling/CastExprTest.cpp
@@ -14,12 +14,19 @@
 
 struct CastExprVisitor : TestVisitor<CastExprVisitor> {
   std::function<void(ExplicitCastExpr *)> OnExplicitCast;
+  std::function<void(CastExpr *)> OnCast;
 
   bool VisitExplicitCastExpr(ExplicitCastExpr *Expr) {
     if (OnExplicitCast)
       OnExplicitCast(Expr);
     return true;
   }
+
+  bool VisitCastExpr(CastExpr *Expr) {
+    if (OnCast)
+      OnCast(Expr);
+    return true;
+  }
 };
 
 TEST(CastExprTest, GetSubExprAsWrittenThroughMaterializedTemporary) {
@@ -54,4 +61,57 @@
                   CastExprVisitor::Lang_CXX2a);
 }
 
+// Verify that getConversionFunction looks through a ConstantExpr for implicit
+// constructor conversions (https://github.com/llvm/llvm-project/issues/53044):
+//
+// `-ImplicitCastExpr 'S' <ConstructorConversion>
+// `-ConstantExpr 'S'
+//   |-value: Struct
+//   `-CXXConstructExpr 'S' 'void (const char *)'
+//     `-ImplicitCastExpr 'const char *' <ArrayToPointerDecay>
+//       `-StringLiteral 'const char [7]' lvalue "foobar"
+TEST(CastExprTest, GetCtorConversionFunctionThroughConstantExpr) {
+  CastExprVisitor Visitor;
+  Visitor.OnCast = [](CastExpr *Expr) {
+    if (Expr->getCastKind() == CK_ConstructorConversion) {
+      auto *Conv = Expr->getConversionFunction();
+      EXPECT_TRUE(isa<CXXConstructorDecl>(Conv))
+          << "Expected CXXConstructorDecl, but saw " << Conv->getDeclKindName();
+    }
+  };
+  Visitor.runOver("struct X { consteval X(const char *) {} };\n"
+                  "void f() { X x = \"foobar\"; }\n",
+                  CastExprVisitor::Lang_CXX2a);
+}
+
+// Verify that getConversionFunction looks through a ConstantExpr for implicit
+// user-defined conversions.
+//
+// `-ImplicitCastExpr 'const char *' <UserDefinedConversion>
+//   `-ConstantExpr 'const char *'
+//     |-value: LValue
+//     `-CXXMemberCallExpr 'const char *'
+//       `-MemberExpr '<bound member function type>' .operator const char *
+//         `-DeclRefExpr 'const X' lvalue Var 'x' 'const X'
+TEST(CastExprTest, GetUserDefinedConversionFunctionThroughConstantExpr) {
+  CastExprVisitor Visitor;
+  Visitor.OnCast = [](CastExpr *Expr) {
+    if (Expr->getCastKind() == CK_UserDefinedConversion) {
+      auto *Conv = Expr->getConversionFunction();
+      EXPECT_TRUE(isa<CXXMethodDecl>(Conv))
+          << "Expected CXXMethodDecl, but saw " << Conv->getDeclKindName();
+    }
+  };
+  Visitor.runOver("struct X {\n"
+                  "  consteval operator const char *() const {\n"
+                  "    return nullptr;\n"
+                  "  }\n"
+                  "};\n"
+                  "const char *f() {\n"
+                  "  constexpr X x;\n";
+                  "  return x;\n"
+                  "}\n",
+                  CastExprVisitor::Lang_CXX2a);
+}
+
 } // namespace
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -1944,6 +1944,7 @@
 
   for (const CastExpr *E = this; E; E = dyn_cast<ImplicitCastExpr>(SubExpr)) {
     SubExpr = skipImplicitTemporary(E->getSubExpr());
+    SubExpr = SubExpr->IgnoreImplicit();
 
     if (E->getCastKind() == CK_ConstructorConversion)
       return cast<CXXConstructExpr>(SubExpr)->getConstructor();


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D117391.400265.patch
Type: text/x-patch
Size: 3470 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20220115/79ccf2fb/attachment-0001.bin>


More information about the cfe-commits mailing list