From d968b173d33be1a5819e9f5f9a8b4258775a65ed Mon Sep 17 00:00:00 2001 From: Cullen Rhodes Date: Wed, 3 Nov 2021 08:04:28 +0000 Subject: [PATCH] [TableGen] Emit a warning for unused template args Add a warning to TableGen for unused template arguments in classes and multiclasses, for example: multiclass Foo { def bar; } $ llvm-tblgen foo.td foo.td:1:20: warning: unused template argument: Foo::x multiclass Foo { ^ A flag '--no-warn-on-unused-template-args' is added to disable the warning. The warning is disabled for LLVM and sub-projects if 'LLVM_ENABLE_WARNINGS=OFF'. Reviewed By: RKSimon Differential Revision: https://reviews.llvm.org/D109359 --- llvm/cmake/modules/TableGen.cmake | 4 ++++ llvm/include/llvm/TableGen/Record.h | 7 ++++++ llvm/lib/TableGen/Main.cpp | 6 +++++- llvm/lib/TableGen/Record.cpp | 10 +++++++++ llvm/lib/TableGen/TGParser.cpp | 13 +++++++++-- llvm/lib/TableGen/TGParser.h | 9 +++++--- llvm/test/TableGen/2010-03-24-PrematureDefaults.td | 2 +- llvm/test/TableGen/TemplateArgRename.td | 2 +- llvm/test/TableGen/cond-subclass.td | 2 +- llvm/test/TableGen/defmclass.td | 2 +- llvm/test/TableGen/if.td | 2 +- llvm/test/TableGen/isa.td | 2 +- llvm/test/TableGen/pr8330.td | 2 +- llvm/test/TableGen/warn-unused-template-arg.td | 25 ++++++++++++++++++++++ 14 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 llvm/test/TableGen/warn-unused-template-arg.td diff --git a/llvm/cmake/modules/TableGen.cmake b/llvm/cmake/modules/TableGen.cmake index 5e9e267..442b000 100644 --- a/llvm/cmake/modules/TableGen.cmake +++ b/llvm/cmake/modules/TableGen.cmake @@ -80,6 +80,10 @@ function(tablegen project ofn) set(tblgen_change_flag "--write-if-changed") endif() + if (NOT LLVM_ENABLE_WARNINGS) + list(APPEND LLVM_TABLEGEN_FLAGS "-no-warn-on-unused-template-args") + endif() + # We need both _TABLEGEN_TARGET and _TABLEGEN_EXE in the DEPENDS list # (both the target and the file) to have .inc files rebuilt on # a tablegen change, as cmake does not propagate file-level dependencies diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h index 713d937..2cf6ef1 100644 --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -1414,6 +1414,7 @@ private: SMLoc Loc; // Source location of definition of name. PointerIntPair TyAndKind; Init *Value; + bool IsUsed = false; public: RecordVal(Init *N, RecTy *T, FieldKind K); @@ -1458,6 +1459,11 @@ public: /// Set the value and source location of the field. bool setValue(Init *V, SMLoc NewLoc); + /// Whether this value is used. Useful for reporting warnings, for example + /// when a template argument is unused. + void setUsed(bool Used) { IsUsed = Used; } + bool isUsed() const { return IsUsed; } + void dump() const; /// Print the value to an output stream, possibly with a semicolon. @@ -1632,6 +1638,7 @@ public: } void checkRecordAssertions(); + void checkUnusedTemplateArgs(); bool isSubClassOf(const Record *R) const { for (const auto &SCPair : SuperClasses) diff --git a/llvm/lib/TableGen/Main.cpp b/llvm/lib/TableGen/Main.cpp index 0b102464..762255b 100644 --- a/llvm/lib/TableGen/Main.cpp +++ b/llvm/lib/TableGen/Main.cpp @@ -55,6 +55,10 @@ WriteIfChanged("write-if-changed", cl::desc("Only write output if it changed")); static cl::opt TimePhases("time-phases", cl::desc("Time phases of parser and backend")); +static cl::opt NoWarnOnUnusedTemplateArgs( + "no-warn-on-unused-template-args", + cl::desc("Disable unused template argument warnings.")); + static int reportError(const char *ProgName, Twine Msg) { errs() << ProgName << ": " << Msg; errs().flush(); @@ -107,7 +111,7 @@ int llvm::TableGenMain(const char *argv0, TableGenMainFn *MainFn) { // it later. SrcMgr.setIncludeDirs(IncludeDirs); - TGParser Parser(SrcMgr, MacroNames, Records); + TGParser Parser(SrcMgr, MacroNames, Records, NoWarnOnUnusedTemplateArgs); if (Parser.ParseFile()) return 1; diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp index aee8b85..a81014e 100644 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -2660,6 +2660,16 @@ void Record::checkRecordAssertions() { } } +// Report a warning if the record has unused template arguments. +void Record::checkUnusedTemplateArgs() { + for (const Init *TA : getTemplateArgs()) { + const RecordVal *Arg = getValue(TA); + if (!Arg->isUsed()) + PrintWarning(Arg->getLoc(), + "unused template argument: " + Twine(Arg->getName())); + } +} + #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void RecordKeeper::dump() const { errs() << *this; } #endif diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp index ed79630..6ccca4d 100644 --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -874,8 +874,9 @@ Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc, Record *TemplateRec = CurMultiClass ? &CurMultiClass->Rec : CurRec; if (TemplateRec->isTemplateArg(TemplateArgName)) { - const RecordVal *RV = TemplateRec->getValue(TemplateArgName); + RecordVal *RV = TemplateRec->getValue(TemplateArgName); assert(RV && "Template arg doesn't exist??"); + RV->setUsed(true); return VarInit::get(TemplateArgName, RV->getType()); } else if (Name->getValue() == "NAME") { return VarInit::get(TemplateArgName, StringRecTy::get()); @@ -3346,7 +3347,12 @@ bool TGParser::ParseClass() { if (ParseTemplateArgList(CurRec)) return true; - return ParseObjectBody(CurRec); + if (ParseObjectBody(CurRec)) + return true; + + if (!NoWarnOnUnusedTemplateArgs) + CurRec->checkUnusedTemplateArgs(); + return false; } /// ParseLetList - Parse a non-empty list of assignment expressions into a list @@ -3541,6 +3547,9 @@ bool TGParser::ParseMultiClass() { PopLocalScope(MulticlassScope); } + if (!NoWarnOnUnusedTemplateArgs) + CurMultiClass->Rec.checkUnusedTemplateArgs(); + CurMultiClass = nullptr; return false; } diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h index 6e3c518..00883c85 100644 --- a/llvm/lib/TableGen/TGParser.h +++ b/llvm/lib/TableGen/TGParser.h @@ -160,10 +160,13 @@ class TGParser { // exist. }; + bool NoWarnOnUnusedTemplateArgs = false; + public: - TGParser(SourceMgr &SM, ArrayRef Macros, - RecordKeeper &records) - : Lex(SM, Macros), CurMultiClass(nullptr), Records(records) {} + TGParser(SourceMgr &SM, ArrayRef Macros, RecordKeeper &records, + const bool NoWarnOnUnusedTemplateArgs = false) + : Lex(SM, Macros), CurMultiClass(nullptr), Records(records), + NoWarnOnUnusedTemplateArgs(NoWarnOnUnusedTemplateArgs) {} /// ParseFile - Main entrypoint for parsing a tblgen file. These parser /// routines return true on error, or false on success. diff --git a/llvm/test/TableGen/2010-03-24-PrematureDefaults.td b/llvm/test/TableGen/2010-03-24-PrematureDefaults.td index 24f6c93..ace979c 100644 --- a/llvm/test/TableGen/2010-03-24-PrematureDefaults.td +++ b/llvm/test/TableGen/2010-03-24-PrematureDefaults.td @@ -1,4 +1,4 @@ -// RUN: llvm-tblgen %s | FileCheck %s +// RUN: llvm-tblgen --no-warn-on-unused-template-args %s | FileCheck %s // XFAIL: vg_leak class A x = 1> { diff --git a/llvm/test/TableGen/TemplateArgRename.td b/llvm/test/TableGen/TemplateArgRename.td index 654b86d..c5c24ce 100644 --- a/llvm/test/TableGen/TemplateArgRename.td +++ b/llvm/test/TableGen/TemplateArgRename.td @@ -1,4 +1,4 @@ -// RUN: llvm-tblgen %s +// RUN: llvm-tblgen --no-warn-on-unused-template-args %s // XFAIL: vg_leak // Make sure there is no collision between XX and XX. diff --git a/llvm/test/TableGen/cond-subclass.td b/llvm/test/TableGen/cond-subclass.td index 9f6f6e2..5f31bf1 100644 --- a/llvm/test/TableGen/cond-subclass.td +++ b/llvm/test/TableGen/cond-subclass.td @@ -1,6 +1,6 @@ // Check that !cond with operands of different subtypes can // initialize a supertype variable. -// RUN: llvm-tblgen %s | FileCheck %s +// RUN: llvm-tblgen --no-warn-on-unused-template-args %s | FileCheck %s // XFAIL: vg_leak class E {} diff --git a/llvm/test/TableGen/defmclass.td b/llvm/test/TableGen/defmclass.td index 80f03b3..2a62184 100644 --- a/llvm/test/TableGen/defmclass.td +++ b/llvm/test/TableGen/defmclass.td @@ -1,4 +1,4 @@ -// RUN: llvm-tblgen %s | FileCheck %s +// RUN: llvm-tblgen --no-warn-on-unused-template-args %s | FileCheck %s // XFAIL: vg_leak class XD { bits<4> Prefix = 11; } diff --git a/llvm/test/TableGen/if.td b/llvm/test/TableGen/if.td index b2ba89c..cd8a8e7 100644 --- a/llvm/test/TableGen/if.td +++ b/llvm/test/TableGen/if.td @@ -1,4 +1,4 @@ -// RUN: llvm-tblgen %s | FileCheck %s +// RUN: llvm-tblgen --no-warn-on-unused-template-args %s | FileCheck %s // XFAIL: vg_leak // Support for an `!if' operator as part of a `let' statement. diff --git a/llvm/test/TableGen/isa.td b/llvm/test/TableGen/isa.td index cfaacb0..e4095fb 100644 --- a/llvm/test/TableGen/isa.td +++ b/llvm/test/TableGen/isa.td @@ -1,4 +1,4 @@ -// RUN: llvm-tblgen %s | FileCheck %s +// RUN: llvm-tblgen --no-warn-on-unused-template-args %s | FileCheck %s // XFAIL: vg_leak // CHECK: --- Defs --- diff --git a/llvm/test/TableGen/pr8330.td b/llvm/test/TableGen/pr8330.td index 7779b63..ceabbc5 100644 --- a/llvm/test/TableGen/pr8330.td +++ b/llvm/test/TableGen/pr8330.td @@ -1,4 +1,4 @@ -// RUN: llvm-tblgen %s | FileCheck %s +// RUN: llvm-tblgen --no-warn-on-unused-template-args %s | FileCheck %s // XFAIL: vg_leak class Or4 Val> { diff --git a/llvm/test/TableGen/warn-unused-template-arg.td b/llvm/test/TableGen/warn-unused-template-arg.td new file mode 100644 index 0000000..5f76e82 --- /dev/null +++ b/llvm/test/TableGen/warn-unused-template-arg.td @@ -0,0 +1,25 @@ +// RUN: llvm-tblgen %s 2>&1 | FileCheck %s +// RUN: llvm-tblgen --no-warn-on-unused-template-args %s 2>&1 | FileCheck %s --check-prefix=CHECK-DISABLED + +class UnusedClassArg {} + +// CHECK: warning: unused template argument: UnusedClassArg:foo +// CHECK-NEXT: class UnusedClassArg {} +// CHECK-NEXT: ^ + +multiclass UnusedMultiClassArg { + def bar; +} + +defm : UnusedMultiClassArg<1>; + +// CHECK: warning: unused template argument: UnusedMultiClassArg::foo +// CHECK-NEXT: multiclass UnusedMultiClassArg { +// CHECK-NEXT: ^ + +class NoWarning { + int a = b; +} + +// CHECK-NOT: warning: unused template argument: NoWarning:b +// CHECK-DISABLED-NOT: warning -- 2.7.4