diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp index e8679439c81d..60ae11b7f426 100644 --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -776,13 +776,14 @@ ParseSubClassReference(Record *CurRec, bool isDefm) { return Result; } - if (ParseTemplateArgValueList(Result.TemplateArgs, CurRec, Result.Rec)) { + SmallVector 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; } @@ -812,7 +813,8 @@ ParseSubMultiClassReference(MultiClass *CurMC) { return Result; } - if (ParseTemplateArgValueList(Result.TemplateArgs, &CurMC->Rec, + SmallVector ArgLocs; + if (ParseTemplateArgValueList(Result.TemplateArgs, ArgLocs, &CurMC->Rec, &Result.MC->Rec)) { Result.MC = nullptr; // Error parsing value list. return Result; @@ -2722,11 +2724,12 @@ const Init *TGParser::ParseSimpleValue(Record *CurRec, const RecTy *ItemType, } SmallVector Args; + SmallVector 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)) @@ -3201,8 +3204,8 @@ void TGParser::ParseValueList(SmallVectorImpl &Result, // PostionalArgValueList ::= [Value {',' Value}*] // NamedArgValueList ::= [NameValue '=' Value {',' NameValue '=' Value}*] bool TGParser::ParseTemplateArgValueList( - SmallVectorImpl &Result, Record *CurRec, - const Record *ArgsRec) { + SmallVectorImpl &Result, + SmallVectorImpl &ArgLocs, Record *CurRec, const Record *ArgsRec) { assert(Result.empty() && "Result vector is not empty"); ArrayRef TArgs = ArgsRec->getTemplateArgs(); @@ -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( @@ -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 &Values, SMLoc Loc, + SmallVectorImpl &Values, ArrayRef ValuesLocs, const Record *ArgsRec) { + assert(Values.size() == ValuesLocs.size() && + "expected as many values as locations"); + ArrayRef 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()]; @@ -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) diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h index cac1ba827f11..4509893eefc2 100644 --- a/llvm/lib/TableGen/TGParser.h +++ b/llvm/lib/TableGen/TGParser.h @@ -296,6 +296,7 @@ private: // Parser methods. void ParseValueList(SmallVectorImpl &Result, Record *CurRec, const RecTy *ItemType = nullptr); bool ParseTemplateArgValueList(SmallVectorImpl &Result, + SmallVectorImpl &ArgLocs, Record *CurRec, const Record *ArgsRec); void ParseDagArgList( SmallVectorImpl> &Result, @@ -321,7 +322,8 @@ private: // Parser methods. bool ApplyLetStack(Record *CurRec); bool ApplyLetStack(RecordsEntry &Entry); bool CheckTemplateArgValues(SmallVectorImpl &Values, - SMLoc Loc, const Record *ArgsRec); + ArrayRef ValuesLocs, + const Record *ArgsRec); }; } // end namespace llvm diff --git a/llvm/test/TableGen/template-args.td b/llvm/test/TableGen/template-args.td index f3eb02dd823e..1644b0a12dc3 100644 --- a/llvm/test/TableGen/template-args.td +++ b/llvm/test/TableGen/template-args.td @@ -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. @@ -158,13 +159,13 @@ 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 @@ -172,5 +173,15 @@ 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; + +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 diff --git a/mlir/test/tblgen-lsp-server/templ-arg-check.test b/mlir/test/tblgen-lsp-server/templ-arg-check.test new file mode 100644 index 000000000000..cda9b79a1f46 --- /dev/null +++ b/mlir/test/tblgen-lsp-server/templ-arg-check.test @@ -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;\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"}