[clang] 86da763 - [Clang] Fix crash in CIndex, when visiting a static_assert without message

Corentin Jabot via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 25 01:53:19 PDT 2023


Author: Kai Stierand
Date: 2023-07-25T10:53:14+02:00
New Revision: 86da763ab6ed19c58349d3f6f62d4bb52becab2c

URL: https://github.com/llvm/llvm-project/commit/86da763ab6ed19c58349d3f6f62d4bb52becab2c
DIFF: https://github.com/llvm/llvm-project/commit/86da763ab6ed19c58349d3f6f62d4bb52becab2c.diff

LOG: [Clang] Fix crash in CIndex, when visiting a static_assert without message

After implementation of "[Clang] Implement P2741R3 - user-generated static_assert messages"  (47ccfd7a89e2a9a747a7114db18db1376324799c) the c indexer crashes when handling a `static_assert` w/o any message.
This is caused by using `dyn_cast` to get the literal string, which isn't working on `nullptr`.

Reviewed By: cor3ntin

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

Added: 
    

Modified: 
    clang/tools/libclang/CIndex.cpp
    clang/unittests/libclang/LibclangTest.cpp
    clang/unittests/libclang/TestUtils.h

Removed: 
    


################################################################################
diff  --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 120ad4ea39e1a9..1bdc0bf742a8ce 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -1294,7 +1294,7 @@ bool CursorVisitor::VisitUnresolvedUsingTypenameDecl(
 bool CursorVisitor::VisitStaticAssertDecl(StaticAssertDecl *D) {
   if (Visit(MakeCXCursor(D->getAssertExpr(), StmtParent, TU, RegionOfInterest)))
     return true;
-  if (auto *Message = dyn_cast<StringLiteral>(D->getMessage()))
+  if (auto *Message = D->getMessage())
     if (Visit(MakeCXCursor(Message, StmtParent, TU, RegionOfInterest)))
       return true;
   return false;

diff  --git a/clang/unittests/libclang/LibclangTest.cpp b/clang/unittests/libclang/LibclangTest.cpp
index f85a72b1c2f702..b1f653441d0efe 100644
--- a/clang/unittests/libclang/LibclangTest.cpp
+++ b/clang/unittests/libclang/LibclangTest.cpp
@@ -1172,6 +1172,80 @@ TEST_F(LibclangParseTest, UnaryOperator) {
   });
 }
 
+TEST_F(LibclangParseTest, VisitStaticAssertDecl_noMessage) {
+  const char testSource[] = R"cpp(static_assert(true))cpp";
+  std::string fileName = "main.cpp";
+  WriteFile(fileName, testSource);
+  const char *Args[] = {"-xc++"};
+  ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args, 1,
+                                       nullptr, 0, TUFlags);
+
+  std::optional<CXCursor> staticAssertCsr;
+  Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {
+    if (cursor.kind == CXCursor_StaticAssert) {
+      staticAssertCsr.emplace(cursor);
+      return CXChildVisit_Break;
+    }
+    return CXChildVisit_Recurse;
+  });
+  ASSERT_TRUE(staticAssertCsr.has_value());
+  Traverse(*staticAssertCsr, [](CXCursor cursor, CXCursor parent) {
+    EXPECT_EQ(cursor.kind, CXCursor_CXXBoolLiteralExpr);
+    return CXChildVisit_Break;
+  });
+  EXPECT_EQ(fromCXString(clang_getCursorSpelling(*staticAssertCsr)), "");
+}
+
+TEST_F(LibclangParseTest, VisitStaticAssertDecl_exprMessage) {
+  const char testSource[] = R"cpp(
+template <unsigned s>
+constexpr unsigned size(const char (&)[s])
+{
+    return s - 1;
+}
+
+struct Message {
+    static constexpr char message[] = "Hello World!";
+    constexpr const char* data() const { return message;}
+    constexpr unsigned size() const
+    {
+        return ::size(message);
+    }
+};
+Message message;
+static_assert(true, message);
+)cpp";
+  std::string fileName = "main.cpp";
+  WriteFile(fileName, testSource);
+  const char *Args[] = {"-xc++", "-std=c++26"};
+  ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args,
+                                       std::size(Args), nullptr, 0, TUFlags);
+  ASSERT_EQ(clang_getNumDiagnostics(ClangTU), 0);
+  std::optional<CXCursor> staticAssertCsr;
+  Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {
+    if (cursor.kind == CXCursor_StaticAssert) {
+      staticAssertCsr.emplace(cursor);
+    }
+    return CXChildVisit_Continue;
+  });
+  ASSERT_TRUE(staticAssertCsr.has_value());
+  size_t argCnt = 0;
+  Traverse(*staticAssertCsr, [&argCnt](CXCursor cursor, CXCursor parent) {
+    switch (argCnt) {
+    case 0:
+      EXPECT_EQ(cursor.kind, CXCursor_CXXBoolLiteralExpr);
+      break;
+    case 1:
+      EXPECT_EQ(cursor.kind, CXCursor_DeclRefExpr);
+      break;
+    }
+    ++argCnt;
+    return CXChildVisit_Continue;
+  });
+  ASSERT_EQ(argCnt, 2);
+  EXPECT_EQ(fromCXString(clang_getCursorSpelling(*staticAssertCsr)), "");
+}
+
 class LibclangRewriteTest : public LibclangParseTest {
 public:
   CXRewriter Rew = nullptr;

diff  --git a/clang/unittests/libclang/TestUtils.h b/clang/unittests/libclang/TestUtils.h
index c78351d4afd200..013aad17358211 100644
--- a/clang/unittests/libclang/TestUtils.h
+++ b/clang/unittests/libclang/TestUtils.h
@@ -87,14 +87,18 @@ class LibclangParseTest : public ::testing::Test {
         it.first->second->size()    // length
     });
   }
-  template<typename F>
-  void Traverse(const F &TraversalFunctor) {
-    CXCursor TuCursor = clang_getTranslationUnitCursor(ClangTU);
+  template <typename F>
+  void Traverse(const CXCursor &cursor, const F &TraversalFunctor) {
     std::reference_wrapper<const F> FunctorRef = std::cref(TraversalFunctor);
-    clang_visitChildren(TuCursor,
-        &TraverseStateless<std::reference_wrapper<const F>>,
-        &FunctorRef);
+    clang_visitChildren(cursor,
+                        &TraverseStateless<std::reference_wrapper<const F>>,
+                        &FunctorRef);
   }
+
+  template <typename F> void Traverse(const F &TraversalFunctor) {
+    Traverse(clang_getTranslationUnitCursor(ClangTU), TraversalFunctor);
+  }
+
   static std::string fromCXString(CXString cx_string) {
     std::string string{clang_getCString(cx_string)};
     clang_disposeString(cx_string);


        


More information about the cfe-commits mailing list