diff --git a/llvm/cmake/modules/TableGen.cmake b/llvm/cmake/modules/TableGen.cmake --- a/llvm/cmake/modules/TableGen.cmake +++ b/llvm/cmake/modules/TableGen.cmake @@ -80,6 +80,10 @@ 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 --- a/llvm/include/llvm/TableGen/Record.h +++ b/llvm/include/llvm/TableGen/Record.h @@ -1414,6 +1414,7 @@ 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 @@ /// 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 @@ } 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 --- a/llvm/lib/TableGen/Main.cpp +++ b/llvm/lib/TableGen/Main.cpp @@ -55,6 +55,10 @@ 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 @@ // 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 --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -2660,6 +2660,16 @@ } } +// 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.h b/llvm/lib/TableGen/TGParser.h --- a/llvm/lib/TableGen/TGParser.h +++ b/llvm/lib/TableGen/TGParser.h @@ -160,10 +160,13 @@ // 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/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -874,8 +874,9 @@ 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 @@ 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 @@ PopLocalScope(MulticlassScope); } + if (!NoWarnOnUnusedTemplateArgs) + CurMultiClass->Rec.checkUnusedTemplateArgs(); + CurMultiClass = nullptr; return false; } diff --git a/llvm/test/TableGen/2010-03-24-PrematureDefaults.td b/llvm/test/TableGen/2010-03-24-PrematureDefaults.td --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- /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