Skip to content

Commit 86da763

Browse files
kiloalphaindiacor3ntin
authored andcommitted
[Clang] Fix crash in CIndex, when visiting a static_assert without message
After implementation of "[Clang] Implement P2741R3 - user-generated static_assert messages" (47ccfd7) 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
1 parent ca9a335 commit 86da763

File tree

3 files changed

+85
-7
lines changed

3 files changed

+85
-7
lines changed

clang/tools/libclang/CIndex.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1294,7 +1294,7 @@ bool CursorVisitor::VisitUnresolvedUsingTypenameDecl(
12941294
bool CursorVisitor::VisitStaticAssertDecl(StaticAssertDecl *D) {
12951295
if (Visit(MakeCXCursor(D->getAssertExpr(), StmtParent, TU, RegionOfInterest)))
12961296
return true;
1297-
if (auto *Message = dyn_cast<StringLiteral>(D->getMessage()))
1297+
if (auto *Message = D->getMessage())
12981298
if (Visit(MakeCXCursor(Message, StmtParent, TU, RegionOfInterest)))
12991299
return true;
13001300
return false;

clang/unittests/libclang/LibclangTest.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,80 @@ TEST_F(LibclangParseTest, UnaryOperator) {
11721172
});
11731173
}
11741174

1175+
TEST_F(LibclangParseTest, VisitStaticAssertDecl_noMessage) {
1176+
const char testSource[] = R"cpp(static_assert(true))cpp";
1177+
std::string fileName = "main.cpp";
1178+
WriteFile(fileName, testSource);
1179+
const char *Args[] = {"-xc++"};
1180+
ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args, 1,
1181+
nullptr, 0, TUFlags);
1182+
1183+
std::optional<CXCursor> staticAssertCsr;
1184+
Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {
1185+
if (cursor.kind == CXCursor_StaticAssert) {
1186+
staticAssertCsr.emplace(cursor);
1187+
return CXChildVisit_Break;
1188+
}
1189+
return CXChildVisit_Recurse;
1190+
});
1191+
ASSERT_TRUE(staticAssertCsr.has_value());
1192+
Traverse(*staticAssertCsr, [](CXCursor cursor, CXCursor parent) {
1193+
EXPECT_EQ(cursor.kind, CXCursor_CXXBoolLiteralExpr);
1194+
return CXChildVisit_Break;
1195+
});
1196+
EXPECT_EQ(fromCXString(clang_getCursorSpelling(*staticAssertCsr)), "");
1197+
}
1198+
1199+
TEST_F(LibclangParseTest, VisitStaticAssertDecl_exprMessage) {
1200+
const char testSource[] = R"cpp(
1201+
template <unsigned s>
1202+
constexpr unsigned size(const char (&)[s])
1203+
{
1204+
return s - 1;
1205+
}
1206+
1207+
struct Message {
1208+
static constexpr char message[] = "Hello World!";
1209+
constexpr const char* data() const { return message;}
1210+
constexpr unsigned size() const
1211+
{
1212+
return ::size(message);
1213+
}
1214+
};
1215+
Message message;
1216+
static_assert(true, message);
1217+
)cpp";
1218+
std::string fileName = "main.cpp";
1219+
WriteFile(fileName, testSource);
1220+
const char *Args[] = {"-xc++", "-std=c++26"};
1221+
ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args,
1222+
std::size(Args), nullptr, 0, TUFlags);
1223+
ASSERT_EQ(clang_getNumDiagnostics(ClangTU), 0);
1224+
std::optional<CXCursor> staticAssertCsr;
1225+
Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {
1226+
if (cursor.kind == CXCursor_StaticAssert) {
1227+
staticAssertCsr.emplace(cursor);
1228+
}
1229+
return CXChildVisit_Continue;
1230+
});
1231+
ASSERT_TRUE(staticAssertCsr.has_value());
1232+
size_t argCnt = 0;
1233+
Traverse(*staticAssertCsr, [&argCnt](CXCursor cursor, CXCursor parent) {
1234+
switch (argCnt) {
1235+
case 0:
1236+
EXPECT_EQ(cursor.kind, CXCursor_CXXBoolLiteralExpr);
1237+
break;
1238+
case 1:
1239+
EXPECT_EQ(cursor.kind, CXCursor_DeclRefExpr);
1240+
break;
1241+
}
1242+
++argCnt;
1243+
return CXChildVisit_Continue;
1244+
});
1245+
ASSERT_EQ(argCnt, 2);
1246+
EXPECT_EQ(fromCXString(clang_getCursorSpelling(*staticAssertCsr)), "");
1247+
}
1248+
11751249
class LibclangRewriteTest : public LibclangParseTest {
11761250
public:
11771251
CXRewriter Rew = nullptr;

clang/unittests/libclang/TestUtils.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,18 @@ class LibclangParseTest : public ::testing::Test {
8787
it.first->second->size() // length
8888
});
8989
}
90-
template<typename F>
91-
void Traverse(const F &TraversalFunctor) {
92-
CXCursor TuCursor = clang_getTranslationUnitCursor(ClangTU);
90+
template <typename F>
91+
void Traverse(const CXCursor &cursor, const F &TraversalFunctor) {
9392
std::reference_wrapper<const F> FunctorRef = std::cref(TraversalFunctor);
94-
clang_visitChildren(TuCursor,
95-
&TraverseStateless<std::reference_wrapper<const F>>,
96-
&FunctorRef);
93+
clang_visitChildren(cursor,
94+
&TraverseStateless<std::reference_wrapper<const F>>,
95+
&FunctorRef);
9796
}
97+
98+
template <typename F> void Traverse(const F &TraversalFunctor) {
99+
Traverse(clang_getTranslationUnitCursor(ClangTU), TraversalFunctor);
100+
}
101+
98102
static std::string fromCXString(CXString cx_string) {
99103
std::string string{clang_getCString(cx_string)};
100104
clang_disposeString(cx_string);

0 commit comments

Comments
 (0)