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
SMLoc Loc; // Source location of definition of name.
PointerIntPair<RecTy *, 2, FieldKind> TyAndKind;
Init *Value;
+ bool IsUsed = false;
public:
RecordVal(Init *N, RecTy *T, FieldKind K);
/// 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.
}
void checkRecordAssertions();
+ void checkUnusedTemplateArgs();
bool isSubClassOf(const Record *R) const {
for (const auto &SCPair : SuperClasses)
static cl::opt<bool>
TimePhases("time-phases", cl::desc("Time phases of parser and backend"));
+static cl::opt<bool> 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();
// it later.
SrcMgr.setIncludeDirs(IncludeDirs);
- TGParser Parser(SrcMgr, MacroNames, Records);
+ TGParser Parser(SrcMgr, MacroNames, Records, NoWarnOnUnusedTemplateArgs);
if (Parser.ParseFile())
return 1;
}
}
+// 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
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());
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
PopLocalScope(MulticlassScope);
}
+ if (!NoWarnOnUnusedTemplateArgs)
+ CurMultiClass->Rec.checkUnusedTemplateArgs();
+
CurMultiClass = nullptr;
return false;
}
// exist.
};
+ bool NoWarnOnUnusedTemplateArgs = false;
+
public:
- TGParser(SourceMgr &SM, ArrayRef<std::string> Macros,
- RecordKeeper &records)
- : Lex(SM, Macros), CurMultiClass(nullptr), Records(records) {}
+ TGParser(SourceMgr &SM, ArrayRef<std::string> 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.
-// RUN: llvm-tblgen %s | FileCheck %s
+// RUN: llvm-tblgen --no-warn-on-unused-template-args %s | FileCheck %s
// XFAIL: vg_leak
class A<int k, bits<2> x = 1> {
-// 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.
// 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<int dummy> {}
-// 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; }
-// 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.
-// RUN: llvm-tblgen %s | FileCheck %s
+// RUN: llvm-tblgen --no-warn-on-unused-template-args %s | FileCheck %s
// XFAIL: vg_leak
// CHECK: --- Defs ---
-// RUN: llvm-tblgen %s | FileCheck %s
+// RUN: llvm-tblgen --no-warn-on-unused-template-args %s | FileCheck %s
// XFAIL: vg_leak
class Or4<bits<8> Val> {
--- /dev/null
+// 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<int foo> {}
+
+// CHECK: warning: unused template argument: UnusedClassArg:foo
+// CHECK-NEXT: class UnusedClassArg<int foo> {}
+// CHECK-NEXT: ^
+
+multiclass UnusedMultiClassArg<int foo> {
+ def bar;
+}
+
+defm : UnusedMultiClassArg<1>;
+
+// CHECK: warning: unused template argument: UnusedMultiClassArg::foo
+// CHECK-NEXT: multiclass UnusedMultiClassArg<int foo> {
+// CHECK-NEXT: ^
+
+class NoWarning<int b> {
+ int a = b;
+}
+
+// CHECK-NOT: warning: unused template argument: NoWarning:b
+// CHECK-DISABLED-NOT: warning