Skip to content

Commit f7617f7

Browse files
authored
[clang-format] Recognize TableGen paste operator on separate line (#133722)
Formatting this piece of code made the program crash. ``` class TypedVecListRegOperand<RegisterClass Reg, int lanes, string eltsize> : RegisterOperand<Reg, "printTypedVectorList<" # lanes # ", '" # eltsize # "'>">; ``` The line starting with the `#` was treated as a separate preprocessor directive line. Then the code dereferenced a null pointer when it tried to continue parsing the first line that did not end in a semicolon. Now the 2 problems are fixed.
1 parent ed85822 commit f7617f7

File tree

4 files changed

+40
-2
lines changed

4 files changed

+40
-2
lines changed

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,8 @@ class AnnotatingParser {
948948
HashTok->setType(TT_Unknown);
949949
if (!parseTableGenValue(ParseNameMode))
950950
return false;
951+
if (!CurrentToken)
952+
return true;
951953
}
952954
// In name mode, '{' is regarded as the end of the value.
953955
// See TGParser::ParseValue in TGParser.cpp

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4842,9 +4842,16 @@ void UnwrappedLineParser::readToken(int LevelDifference) {
48424842
PreviousWasComment = FormatTok->is(tok::comment);
48434843

48444844
while (!Line->InPPDirective && FormatTok->is(tok::hash) &&
4845-
(!Style.isVerilog() ||
4846-
Keywords.isVerilogPPDirective(*Tokens->peekNextToken())) &&
48474845
FirstNonCommentOnLine) {
4846+
// In Verilog, the backtick is used for macro invocations. In TableGen,
4847+
// the single hash is used for the paste operator.
4848+
const auto *Next = Tokens->peekNextToken();
4849+
if ((Style.isVerilog() && !Keywords.isVerilogPPDirective(*Next)) ||
4850+
(Style.isTableGen() &&
4851+
!Next->isOneOf(tok::kw_else, tok::pp_define, tok::pp_ifdef,
4852+
tok::pp_ifndef, tok::pp_endif))) {
4853+
break;
4854+
}
48484855
distributeComments(Comments, FormatTok);
48494856
Comments.clear();
48504857
// If there is an unfinished unwrapped line, we flush the preprocessor

clang/unittests/Format/FormatTestTableGen.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,13 @@ TEST_F(FormatTestTableGen, PasteOperator) {
218218
" string Z = [\"Traring\", \"Paste\", \"Traring\", \"Paste\",\n"
219219
" \"Traring\", \"Paste\"]#;\n"
220220
"}");
221+
222+
verifyFormat("def x#x {}", "def x\n"
223+
"#x {}");
224+
verifyFormat("def x#x {}", "def x\n"
225+
"#\n"
226+
"x {}");
227+
verifyFormat("def x#x");
221228
}
222229

223230
TEST_F(FormatTestTableGen, ClassDefinition) {

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2836,6 +2836,28 @@ TEST_F(TokenAnnotatorTest, UnderstandTableGenTokens) {
28362836
Tokens = Annotate("!cond");
28372837
EXPECT_TOKEN(Tokens[0], tok::identifier, TT_TableGenCondOperator);
28382838

2839+
// The paste operator should not be treated as a preprocessor directive even
2840+
// if it is on a separate line.
2841+
Tokens = Annotate("def x\n"
2842+
"#embed {}");
2843+
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
2844+
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_StartOfName);
2845+
EXPECT_EQ(Tokens[1]->Next, Tokens[2]);
2846+
Tokens = Annotate("def x\n"
2847+
"#define x\n"
2848+
"#embed {}");
2849+
ASSERT_EQ(Tokens.size(), 10u) << Tokens;
2850+
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_StartOfName);
2851+
EXPECT_EQ(Tokens[1]->Next, Tokens[5]);
2852+
Tokens = Annotate("def x\n"
2853+
"#ifdef x\n"
2854+
"#else\n"
2855+
"#endif\n"
2856+
"#embed {}");
2857+
ASSERT_EQ(Tokens.size(), 14u) << Tokens;
2858+
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_StartOfName);
2859+
EXPECT_EQ(Tokens[1]->Next, Tokens[9]);
2860+
28392861
auto AnnotateValue = [this, &Style](StringRef Code) {
28402862
// Values are annotated only in specific context.
28412863
auto Result = annotate(("def X { let V = " + Code + "; }").str(), Style);

0 commit comments

Comments
 (0)