aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Stierand <kai.stierand@swplusplus.de>2023-07-25 10:36:53 +0200
committerCorentin Jabot <corentinjabot@gmail.com>2023-07-25 10:53:14 +0200
commit86da763ab6ed19c58349d3f6f62d4bb52becab2c (patch)
tree2cf7e8005ade248aa6485360b82bc43b0807af48
parentca9a3354d04b15366088d7831b40f891e3d77b95 (diff)
downloadllvm-86da763ab6ed19c58349d3f6f62d4bb52becab2c.zip
llvm-86da763ab6ed19c58349d3f6f62d4bb52becab2c.tar.gz
llvm-86da763ab6ed19c58349d3f6f62d4bb52becab2c.tar.bz2
[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
-rw-r--r--clang/tools/libclang/CIndex.cpp2
-rw-r--r--clang/unittests/libclang/LibclangTest.cpp74
-rw-r--r--clang/unittests/libclang/TestUtils.h16
3 files changed, 85 insertions, 7 deletions
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 120ad4e..1bdc0bf 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 f85a72b..b1f6534 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 c78351d..013aad1 100644
--- a/clang/unittests/libclang/TestUtils.h
+++ b/clang/unittests/libclang/TestUtils.h
@@ -87,14 +87,18 @@ public:
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);