Skip to content

Commit 97ea0ab

Browse files
authored
[TableGen] Do not exit in template argument check (#121636)
The signature of `CheckTemplateArgValues` implements error handling via the `bool` return type, yet always returned false. The single possible error case instead used `PrintFatalError,` which exits the program afterward. This behavior is undesirable: It prevents any further errors from being printed and makes TableGen less usable as a library as it crashes the entire process (e.g. `tblgen-lsp-server`). This PR therefore fixes the issue by using `Error` instead and returning true if an error occurred. All callers already perform proper error handling. As `llvm-tblgen` exits on error, a test was also added to the LSP to ensure it exits normally despite the error.
1 parent ce831a2 commit 97ea0ab

File tree

4 files changed

+56
-21
lines changed

4 files changed

+56
-21
lines changed

llvm/lib/TableGen/TGParser.cpp

+24-17
Original file line numberDiff line numberDiff line change
@@ -776,13 +776,14 @@ ParseSubClassReference(Record *CurRec, bool isDefm) {
776776
return Result;
777777
}
778778

779-
if (ParseTemplateArgValueList(Result.TemplateArgs, CurRec, Result.Rec)) {
779+
SmallVector<SMLoc> ArgLocs;
780+
if (ParseTemplateArgValueList(Result.TemplateArgs, ArgLocs, CurRec,
781+
Result.Rec)) {
780782
Result.Rec = nullptr; // Error parsing value list.
781783
return Result;
782784
}
783785

784-
if (CheckTemplateArgValues(Result.TemplateArgs, Result.RefRange.Start,
785-
Result.Rec)) {
786+
if (CheckTemplateArgValues(Result.TemplateArgs, ArgLocs, Result.Rec)) {
786787
Result.Rec = nullptr; // Error checking value list.
787788
return Result;
788789
}
@@ -812,7 +813,8 @@ ParseSubMultiClassReference(MultiClass *CurMC) {
812813
return Result;
813814
}
814815

815-
if (ParseTemplateArgValueList(Result.TemplateArgs, &CurMC->Rec,
816+
SmallVector<SMLoc> ArgLocs;
817+
if (ParseTemplateArgValueList(Result.TemplateArgs, ArgLocs, &CurMC->Rec,
816818
&Result.MC->Rec)) {
817819
Result.MC = nullptr; // Error parsing value list.
818820
return Result;
@@ -2722,11 +2724,12 @@ const Init *TGParser::ParseSimpleValue(Record *CurRec, const RecTy *ItemType,
27222724
}
27232725

27242726
SmallVector<const ArgumentInit *, 8> Args;
2727+
SmallVector<SMLoc> ArgLocs;
27252728
Lex.Lex(); // consume the <
2726-
if (ParseTemplateArgValueList(Args, CurRec, Class))
2729+
if (ParseTemplateArgValueList(Args, ArgLocs, CurRec, Class))
27272730
return nullptr; // Error parsing value list.
27282731

2729-
if (CheckTemplateArgValues(Args, NameLoc.Start, Class))
2732+
if (CheckTemplateArgValues(Args, ArgLocs, Class))
27302733
return nullptr; // Error checking template argument values.
27312734

27322735
if (resolveArguments(Class, Args, NameLoc.Start))
@@ -3201,8 +3204,8 @@ void TGParser::ParseValueList(SmallVectorImpl<const Init *> &Result,
32013204
// PostionalArgValueList ::= [Value {',' Value}*]
32023205
// NamedArgValueList ::= [NameValue '=' Value {',' NameValue '=' Value}*]
32033206
bool TGParser::ParseTemplateArgValueList(
3204-
SmallVectorImpl<const ArgumentInit *> &Result, Record *CurRec,
3205-
const Record *ArgsRec) {
3207+
SmallVectorImpl<const ArgumentInit *> &Result,
3208+
SmallVectorImpl<SMLoc> &ArgLocs, Record *CurRec, const Record *ArgsRec) {
32063209
assert(Result.empty() && "Result vector is not empty");
32073210
ArrayRef<const Init *> TArgs = ArgsRec->getTemplateArgs();
32083211

@@ -3217,7 +3220,7 @@ bool TGParser::ParseTemplateArgValueList(
32173220
return true;
32183221
}
32193222

3220-
SMLoc ValueLoc = Lex.getLoc();
3223+
SMLoc ValueLoc = ArgLocs.emplace_back(Lex.getLoc());
32213224
// If we are parsing named argument, we don't need to know the argument name
32223225
// and argument type will be resolved after we know the name.
32233226
const Init *Value = ParseValue(
@@ -4417,11 +4420,15 @@ bool TGParser::ParseFile() {
44174420
// If necessary, replace an argument with a cast to the required type.
44184421
// The argument count has already been checked.
44194422
bool TGParser::CheckTemplateArgValues(
4420-
SmallVectorImpl<const ArgumentInit *> &Values, SMLoc Loc,
4423+
SmallVectorImpl<const ArgumentInit *> &Values, ArrayRef<SMLoc> ValuesLocs,
44214424
const Record *ArgsRec) {
4425+
assert(Values.size() == ValuesLocs.size() &&
4426+
"expected as many values as locations");
4427+
44224428
ArrayRef<const Init *> TArgs = ArgsRec->getTemplateArgs();
44234429

4424-
for (const ArgumentInit *&Value : Values) {
4430+
bool HasError = false;
4431+
for (auto [Value, Loc] : llvm::zip_equal(Values, ValuesLocs)) {
44254432
const Init *ArgName = nullptr;
44264433
if (Value->isPositional())
44274434
ArgName = TArgs[Value->getIndex()];
@@ -4439,16 +4446,16 @@ bool TGParser::CheckTemplateArgValues(
44394446
"result of template arg value cast has wrong type");
44404447
Value = Value->cloneWithValue(CastValue);
44414448
} else {
4442-
PrintFatalError(Loc, "Value specified for template argument '" +
4443-
Arg->getNameInitAsString() + "' is of type " +
4444-
ArgValue->getType()->getAsString() +
4445-
"; expected type " + ArgType->getAsString() +
4446-
": " + ArgValue->getAsString());
4449+
HasError |= Error(
4450+
Loc, "Value specified for template argument '" +
4451+
Arg->getNameInitAsString() + "' is of type " +
4452+
ArgValue->getType()->getAsString() + "; expected type " +
4453+
ArgType->getAsString() + ": " + ArgValue->getAsString());
44474454
}
44484455
}
44494456
}
44504457

4451-
return false;
4458+
return HasError;
44524459
}
44534460

44544461
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

llvm/lib/TableGen/TGParser.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ class TGParser {
296296
void ParseValueList(SmallVectorImpl<const Init *> &Result, Record *CurRec,
297297
const RecTy *ItemType = nullptr);
298298
bool ParseTemplateArgValueList(SmallVectorImpl<const ArgumentInit *> &Result,
299+
SmallVectorImpl<SMLoc> &ArgLocs,
299300
Record *CurRec, const Record *ArgsRec);
300301
void ParseDagArgList(
301302
SmallVectorImpl<std::pair<const Init *, const StringInit *>> &Result,
@@ -321,7 +322,8 @@ class TGParser {
321322
bool ApplyLetStack(Record *CurRec);
322323
bool ApplyLetStack(RecordsEntry &Entry);
323324
bool CheckTemplateArgValues(SmallVectorImpl<const ArgumentInit *> &Values,
324-
SMLoc Loc, const Record *ArgsRec);
325+
ArrayRef<SMLoc> ValuesLocs,
326+
const Record *ArgsRec);
325327
};
326328

327329
} // end namespace llvm

llvm/test/TableGen/template-args.td

+14-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// RUN: not llvm-tblgen -DERROR8 %s 2>&1 | FileCheck --check-prefix=ERROR8 %s
1010
// RUN: not llvm-tblgen -DERROR9 %s 2>&1 | FileCheck --check-prefix=ERROR9 %s
1111
// RUN: not llvm-tblgen -DERROR10 %s 2>&1 | FileCheck --check-prefix=ERROR10 %s
12+
// RUN: not llvm-tblgen -DERROR11 %s 2>&1 | FileCheck --check-prefix=ERROR11 %s
1213

1314
// This file tests that all required arguments are specified and template
1415
// arguments are type-checked and cast if necessary.
@@ -158,19 +159,29 @@ defm MissingComma : TwoArgs<2 "two">;
158159
#ifdef ERROR8
159160
def error8: Class1;
160161
// ERROR8: value not specified for template argument 'Class1:nm'
161-
// ERROR8: 18:21: note: declared in 'Class1'
162+
// ERROR8: 19:21: note: declared in 'Class1'
162163
#endif
163164

164165
#ifdef ERROR9
165166
defm error9: MC1;
166167
// ERROR9: value not specified for template argument 'MC1::nm'
167-
// ERROR9: 99:23: note: declared in 'MC1'
168+
// ERROR9: 100:23: note: declared in 'MC1'
168169
#endif
169170

170171
#ifdef ERROR10
171172
def error10 {
172173
int value = Class2<>.Code;
173174
}
174175
// ERROR10: value not specified for template argument 'Class2:cd'
175-
// ERROR10: 37:22: note: declared in 'Class2'
176+
// ERROR10: 38:22: note: declared in 'Class2'
177+
#endif
178+
179+
#ifdef ERROR11
180+
181+
class Foo<int i, int j>;
182+
183+
def error11 : Foo<"", "">;
184+
// ERROR11: [[#@LINE-1]]:19: error: Value specified for template argument 'Foo:i' is of type string; expected type int: ""
185+
// ERROR11: [[#@LINE-2]]:23: error: Value specified for template argument 'Foo:j' is of type string; expected type int: ""
186+
176187
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: tblgen-lsp-server -lit-test < %s | FileCheck -strict-whitespace %s
2+
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"tablegen","capabilities":{},"trace":"off"}}
3+
// -----
4+
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{
5+
"uri":"test:///foo.td",
6+
"languageId":"tablegen",
7+
"version":1,
8+
"text":"class Foo<int i>;\ndef : Foo<\"\">;"
9+
}}}
10+
// CHECK: "method": "textDocument/publishDiagnostics",
11+
// CHECK: "message": "Value specified for template argument 'Foo:i' is of type string; expected type int: \"\"",
12+
// -----
13+
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
14+
// -----
15+
{"jsonrpc":"2.0","method":"exit"}

0 commit comments

Comments
 (0)