Skip to content

Commit

Permalink
[TableGen] Do not exit in template argument check (llvm#121636)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
zero9178 authored Jan 6, 2025
1 parent ce831a2 commit 97ea0ab
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 21 deletions.
41 changes: 24 additions & 17 deletions llvm/lib/TableGen/TGParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,13 +776,14 @@ ParseSubClassReference(Record *CurRec, bool isDefm) {
return Result;
}

if (ParseTemplateArgValueList(Result.TemplateArgs, CurRec, Result.Rec)) {
SmallVector<SMLoc> ArgLocs;
if (ParseTemplateArgValueList(Result.TemplateArgs, ArgLocs, CurRec,
Result.Rec)) {
Result.Rec = nullptr; // Error parsing value list.
return Result;
}

if (CheckTemplateArgValues(Result.TemplateArgs, Result.RefRange.Start,
Result.Rec)) {
if (CheckTemplateArgValues(Result.TemplateArgs, ArgLocs, Result.Rec)) {
Result.Rec = nullptr; // Error checking value list.
return Result;
}
Expand Down Expand Up @@ -812,7 +813,8 @@ ParseSubMultiClassReference(MultiClass *CurMC) {
return Result;
}

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

SmallVector<const ArgumentInit *, 8> Args;
SmallVector<SMLoc> ArgLocs;
Lex.Lex(); // consume the <
if (ParseTemplateArgValueList(Args, CurRec, Class))
if (ParseTemplateArgValueList(Args, ArgLocs, CurRec, Class))
return nullptr; // Error parsing value list.

if (CheckTemplateArgValues(Args, NameLoc.Start, Class))
if (CheckTemplateArgValues(Args, ArgLocs, Class))
return nullptr; // Error checking template argument values.

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

Expand All @@ -3217,7 +3220,7 @@ bool TGParser::ParseTemplateArgValueList(
return true;
}

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

ArrayRef<const Init *> TArgs = ArgsRec->getTemplateArgs();

for (const ArgumentInit *&Value : Values) {
bool HasError = false;
for (auto [Value, Loc] : llvm::zip_equal(Values, ValuesLocs)) {
const Init *ArgName = nullptr;
if (Value->isPositional())
ArgName = TArgs[Value->getIndex()];
Expand All @@ -4439,16 +4446,16 @@ bool TGParser::CheckTemplateArgValues(
"result of template arg value cast has wrong type");
Value = Value->cloneWithValue(CastValue);
} else {
PrintFatalError(Loc, "Value specified for template argument '" +
Arg->getNameInitAsString() + "' is of type " +
ArgValue->getType()->getAsString() +
"; expected type " + ArgType->getAsString() +
": " + ArgValue->getAsString());
HasError |= Error(
Loc, "Value specified for template argument '" +
Arg->getNameInitAsString() + "' is of type " +
ArgValue->getType()->getAsString() + "; expected type " +
ArgType->getAsString() + ": " + ArgValue->getAsString());
}
}
}

return false;
return HasError;
}

#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/TableGen/TGParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ class TGParser {
void ParseValueList(SmallVectorImpl<const Init *> &Result, Record *CurRec,
const RecTy *ItemType = nullptr);
bool ParseTemplateArgValueList(SmallVectorImpl<const ArgumentInit *> &Result,
SmallVectorImpl<SMLoc> &ArgLocs,
Record *CurRec, const Record *ArgsRec);
void ParseDagArgList(
SmallVectorImpl<std::pair<const Init *, const StringInit *>> &Result,
Expand All @@ -321,7 +322,8 @@ class TGParser {
bool ApplyLetStack(Record *CurRec);
bool ApplyLetStack(RecordsEntry &Entry);
bool CheckTemplateArgValues(SmallVectorImpl<const ArgumentInit *> &Values,
SMLoc Loc, const Record *ArgsRec);
ArrayRef<SMLoc> ValuesLocs,
const Record *ArgsRec);
};

} // end namespace llvm
Expand Down
17 changes: 14 additions & 3 deletions llvm/test/TableGen/template-args.td
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// RUN: not llvm-tblgen -DERROR8 %s 2>&1 | FileCheck --check-prefix=ERROR8 %s
// RUN: not llvm-tblgen -DERROR9 %s 2>&1 | FileCheck --check-prefix=ERROR9 %s
// RUN: not llvm-tblgen -DERROR10 %s 2>&1 | FileCheck --check-prefix=ERROR10 %s
// RUN: not llvm-tblgen -DERROR11 %s 2>&1 | FileCheck --check-prefix=ERROR11 %s

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

#ifdef ERROR9
defm error9: MC1;
// ERROR9: value not specified for template argument 'MC1::nm'
// ERROR9: 99:23: note: declared in 'MC1'
// ERROR9: 100:23: note: declared in 'MC1'
#endif

#ifdef ERROR10
def error10 {
int value = Class2<>.Code;
}
// ERROR10: value not specified for template argument 'Class2:cd'
// ERROR10: 37:22: note: declared in 'Class2'
// ERROR10: 38:22: note: declared in 'Class2'
#endif

#ifdef ERROR11

class Foo<int i, int j>;

def error11 : Foo<"", "">;
// ERROR11: [[#@LINE-1]]:19: error: Value specified for template argument 'Foo:i' is of type string; expected type int: ""
// ERROR11: [[#@LINE-2]]:23: error: Value specified for template argument 'Foo:j' is of type string; expected type int: ""

#endif
15 changes: 15 additions & 0 deletions mlir/test/tblgen-lsp-server/templ-arg-check.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: tblgen-lsp-server -lit-test < %s | FileCheck -strict-whitespace %s
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"tablegen","capabilities":{},"trace":"off"}}
// -----
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{
"uri":"test:///foo.td",
"languageId":"tablegen",
"version":1,
"text":"class Foo<int i>;\ndef : Foo<\"\">;"
}}}
// CHECK: "method": "textDocument/publishDiagnostics",
// CHECK: "message": "Value specified for template argument 'Foo:i' is of type string; expected type int: \"\"",
// -----
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
// -----
{"jsonrpc":"2.0","method":"exit"}

0 comments on commit 97ea0ab

Please sign in to comment.