Skip to content

Commit 04540fa

Browse files
authored
[TableGen] Print record location when record asserts fail (llvm#111029)
When record assertions fail, print an error message with the record's location, so it's easier to see where the record that caused the assert to fail was instantiated. This is useful when the assert condition in a class depends on a template parameter, so we need to know the context of the definition to determine why the assert failed. Also enhanced the assert.td test to check for these context messages, and also add checks for some assert failures that were missing in the test.
1 parent 1811e87 commit 04540fa

File tree

4 files changed

+46
-20
lines changed

4 files changed

+46
-20
lines changed

llvm/include/llvm/TableGen/Error.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ void PrintError(const RecordVal *RecVal, const Twine &Msg);
4848
[[noreturn]] void PrintFatalError(const RecordVal *RecVal, const Twine &Msg);
4949
[[noreturn]] void PrintFatalError(function_ref<void(raw_ostream &OS)> PrintMsg);
5050

51-
void CheckAssert(SMLoc Loc, Init *Condition, Init *Message);
51+
// Returns true if the assert failed.
52+
bool CheckAssert(SMLoc Loc, Init *Condition, Init *Message);
5253
void dumpMessage(SMLoc Loc, Init *Message);
5354

5455
extern SourceMgr SrcMgr;

llvm/lib/TableGen/Error.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,18 +160,22 @@ void PrintFatalError(const RecordVal *RecVal, const Twine &Msg) {
160160

161161
// Check an assertion: Obtain the condition value and be sure it is true.
162162
// If not, print a nonfatal error along with the message.
163-
void CheckAssert(SMLoc Loc, Init *Condition, Init *Message) {
163+
bool CheckAssert(SMLoc Loc, Init *Condition, Init *Message) {
164164
auto *CondValue = dyn_cast_or_null<IntInit>(Condition->convertInitializerTo(
165165
IntRecTy::get(Condition->getRecordKeeper())));
166-
if (!CondValue)
166+
if (!CondValue) {
167167
PrintError(Loc, "assert condition must of type bit, bits, or int.");
168-
else if (!CondValue->getValue()) {
168+
return true;
169+
}
170+
if (!CondValue->getValue()) {
169171
PrintError(Loc, "assertion failed");
170172
if (auto *MessageInit = dyn_cast<StringInit>(Message))
171173
PrintNote(MessageInit->getValue());
172174
else
173175
PrintNote("(assert message is not a string)");
176+
return true;
174177
}
178+
return false;
175179
}
176180

177181
// Dump a message to stderr.

llvm/lib/TableGen/Record.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3182,11 +3182,19 @@ void Record::checkRecordAssertions() {
31823182
RecordResolver R(*this);
31833183
R.setFinal(true);
31843184

3185+
bool AnyFailed = false;
31853186
for (const auto &Assertion : getAssertions()) {
31863187
Init *Condition = Assertion.Condition->resolveReferences(R);
31873188
Init *Message = Assertion.Message->resolveReferences(R);
3188-
CheckAssert(Assertion.Loc, Condition, Message);
3189+
AnyFailed |= CheckAssert(Assertion.Loc, Condition, Message);
31893190
}
3191+
3192+
if (!AnyFailed)
3193+
return;
3194+
3195+
// If any of the record assertions failed, print some context that will
3196+
// help see where the record that caused these assert failures is defined.
3197+
PrintError(this, "assertion failed in this record");
31903198
}
31913199

31923200
void Record::emitRecordDumps() {

llvm/test/TableGen/assert.td

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s
1+
// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s -DFILE=%s
22

3+
// -----------------------------------------------------------------------------
34
// Test the assert statement at top level.
5+
// -----------------------------------------------------------------------------
46

57
// CHECK: assertion failed
68
// CHECK-NOT: note: primary name is too short
@@ -48,33 +50,35 @@ foreach i = 1...3 in {
4850
def bar_ # i;
4951
}
5052

53+
// -----------------------------------------------------------------------------
5154
// Test the assert statement in a record definition.
55+
// -----------------------------------------------------------------------------
5256

53-
// CHECK: assertion failed
57+
// CHECK: [[FILE]]:[[@LINE+8]]:10: error: assertion failed
5458
// CHECK-NOT: primary first name is not "Grace"
55-
// CHECK: primary first name is not "Grack"
56-
// CHECK: assertion failed
57-
// CHECK: foo field should be
58-
59+
// CHECK: note: primary first name is not "Grack"
60+
// CHECK: [[FILE]]:[[@LINE+7]]:10: error: assertion failed
61+
// CHECK: note: foo field should be
62+
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: assertion failed in this record
5963
def Rec10 {
6064
assert !eq(!substr(Name, 0, 5), "Grace"), "primary first name is not \"Grace\"";
6165
assert !eq(!substr(Name, 0, 5), "Grack"), "primary first name is not \"Grack\"";
6266
string foo = "Foo";
6367
assert !eq(foo, "foo"), "foo field should be \"Foo\"";
6468
}
6569

66-
// CHECK: assertion failed
70+
// CHECK: [[FILE]]:[[@LINE+5]]:10: error: assertion failed
6771
// CHECK: note: magic field is incorrect: 42
68-
72+
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: assertion failed in this record
6973
def Rec11 {
7074
int magic = 13;
7175
assert !eq(magic, 13), "magic field is incorrect: " # magic;
7276
let magic = 42;
7377
}
7478

75-
// CHECK: assertion failed
79+
// CHECK: [[FILE]]:[[@LINE+6]]:10: error: assertion failed
7680
// CHECK: note: var field has wrong value
77-
81+
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: assertion failed in this record
7882
def Rec12 {
7983
defvar prefix = "foo_";
8084
string var = prefix # "snork";
@@ -83,25 +87,27 @@ def Rec12 {
8387

8488
// CHECK: assertion failed
8589
// CHECK: note: kind field has wrong value
86-
8790
class Kind {
8891
int kind = 7;
8992
}
9093

94+
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: assertion failed in this record
9195
def Rec13 : Kind {
9296
let kind = 8;
9397
assert !eq(kind, 7), "kind field has wrong value: " # kind;
9498
}
9599

96100
// CHECK: assertion failed
97101
// CHECK: note: double_result should be
98-
102+
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: assertion failed in this record
99103
def Rec14 : Cube<3> {
100104
int double_result = !mul(result, 2);
101105
assert !eq(double_result, 53), "double_result should be 54";
102106
}
103107

108+
// -----------------------------------------------------------------------------
104109
// Test the assert statement in a class definition.
110+
// -----------------------------------------------------------------------------
105111

106112
class PersonName<string name> {
107113
assert !le(!size(name), 32), "person name is too long: " # name;
@@ -118,32 +124,39 @@ def Rec20 : Person<"Donald Knuth", 60>;
118124

119125
// CHECK: assertion failed
120126
// CHECK: note: person name is too long
121-
127+
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: assertion failed in this record
122128
def Rec21 : Person<"Donald Uh Oh This Name Is Too Long Knuth", 50>;
123129

124130
// CHECK: assertion failed
125131
// CHECK: note: person age is invalid
126-
132+
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: assertion failed in this record
127133
def Rec22 : Person<"Donald Knuth", 150>;
128134

129135
// Test the assert statement in an anonymous class invocation.
130-
131136
def Rec30 {
132137
string Name = Person<"Margaret Heafield Hamilton", 25>.Name;
133138
int Age = Person<"Margaret Heafield Hamilton", 25>.Age;
134139
}
135140

141+
// CHECK: assertion failed
142+
// CHECK: note: person name is too long
143+
// CHECK: [[FILE]]:[[@LINE+2]]:17: error: assertion failed in this record
136144
def Rec31 {
137145
string Name = Person<"Margaret Heafield And More Middle Names Hamilton", 25>.Name;
138146
int Age = Person<"Margaret Heafield Hamilton", 25>.Age;
139147
}
140148

149+
// CHECK: assertion failed
150+
// CHECK: note: person age is invalid: 0
151+
// CHECK: [[FILE]]:[[@LINE+3]]:13: error: assertion failed in this record
141152
def Rec32 {
142153
string Name = Person<"Margaret Heafield Hamilton", 25>.Name;
143154
int Age = Person<"Margaret Heafield Hamilton", 0>.Age;
144155
}
145156

157+
// -----------------------------------------------------------------------------
146158
// Test the assert statement in a multiclass.
159+
// -----------------------------------------------------------------------------
147160

148161
// CHECK: assertion failed
149162
// CHECK: note: MC1 id string is too long

0 commit comments

Comments
 (0)