Skip to content

Commit cac6777

Browse files
authored
[clang-format] Fix crashes when the macro expansion is empty (#119428)
An empty expansion should be valid, like `echo 'A()' | clang-format --style='{Macros: [A(x)=x]}'`. Fixes #119258.
1 parent 9072665 commit cac6777

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

clang/lib/Format/MacroExpander.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ MacroExpander::expand(FormatToken *ID,
233233
if (Result.size() > 1) {
234234
++Result[0]->MacroCtx->StartOfExpansion;
235235
++Result[Result.size() - 2]->MacroCtx->EndOfExpansion;
236+
} else {
237+
// If the macro expansion is empty, mark the start and end.
238+
Result[0]->MacroCtx->StartOfExpansion = 1;
239+
Result[0]->MacroCtx->EndOfExpansion = 1;
236240
}
237241
return Result;
238242
}

clang/unittests/Format/MacroCallReconstructorTest.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ class Expansion {
6565
}
6666
Unexpanded[ID] = std::move(UnexpandedLine);
6767

68-
auto Expanded = uneof(Macros.expand(ID, Args));
68+
auto Expanded = Macros.expand(ID, Args);
69+
if (Expanded.size() > 1)
70+
Expanded = uneof(Expanded);
6971
Tokens.append(Expanded.begin(), Expanded.end());
7072

7173
TokenList UnexpandedTokens;
@@ -217,6 +219,31 @@ TEST_F(MacroCallReconstructorTest, Identifier) {
217219
EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(line(U.consume("X"))));
218220
}
219221

222+
TEST_F(MacroCallReconstructorTest, EmptyDefinition) {
223+
auto Macros = createExpander({"X"});
224+
Expansion Exp(Lex, *Macros);
225+
TokenList Call = Exp.expand("X");
226+
227+
MacroCallReconstructor Unexp(0, Exp.getUnexpanded());
228+
Unexp.addLine(line(Exp.getTokens()));
229+
EXPECT_TRUE(Unexp.finished());
230+
Matcher U(Call, Lex);
231+
EXPECT_THAT(std::move(Unexp).takeResult(), matchesLine(line(U.consume("X"))));
232+
}
233+
234+
TEST_F(MacroCallReconstructorTest, EmptyExpansion) {
235+
auto Macros = createExpander({"A(x)=x"});
236+
Expansion Exp(Lex, *Macros);
237+
TokenList Call = Exp.expand("A", {""});
238+
239+
MacroCallReconstructor Unexp(0, Exp.getUnexpanded());
240+
Unexp.addLine(line(Exp.getTokens()));
241+
EXPECT_TRUE(Unexp.finished());
242+
Matcher U(Call, Lex);
243+
EXPECT_THAT(std::move(Unexp).takeResult(),
244+
matchesLine(line(U.consume("A()"))));
245+
}
246+
220247
TEST_F(MacroCallReconstructorTest, NestedLineWithinCall) {
221248
auto Macros = createExpander({"C(a)=class X { a; };"});
222249
Expansion Exp(Lex, *Macros);

0 commit comments

Comments
 (0)