@@ -54,27 +54,16 @@ static StringRef getTypeKeyword(Type type) {
54
54
// / Prints a structure type. Keeps track of known struct names to handle self-
55
55
// / or mutually-referring structs without falling into infinite recursion.
56
56
static void printStructType (AsmPrinter &printer, LLVMStructType type) {
57
- // This keeps track of the names of identified structure types that are
58
- // currently being printed. Since such types can refer themselves, this
59
- // tracking is necessary to stop the recursion: the current function may be
60
- // called recursively from AsmPrinter::printType after the appropriate
61
- // dispatch. We maintain the invariant of this storage being modified
62
- // exclusively in this function, and at most one name being added per call.
63
- // TODO: consider having such functionality inside AsmPrinter.
64
- thread_local SetVector<StringRef> knownStructNames;
65
- unsigned stackSize = knownStructNames.size ();
66
- (void )stackSize;
67
- auto guard = llvm::make_scope_exit ([&]() {
68
- assert (knownStructNames.size () == stackSize &&
69
- " malformed identified stack when printing recursive structs" );
70
- });
57
+ FailureOr<AsmPrinter::CyclicPrintReset> cyclicPrint;
71
58
72
59
printer << " <" ;
73
60
if (type.isIdentified ()) {
61
+ cyclicPrint = printer.tryStartCyclicPrint (type);
62
+
74
63
printer << ' "' << type.getName () << ' "' ;
75
64
// If we are printing a reference to one of the enclosing structs, just
76
65
// print the name and stop to avoid infinitely long output.
77
- if (knownStructNames. count (type. getName () )) {
66
+ if (failed (cyclicPrint )) {
78
67
printer << ' >' ;
79
68
return ;
80
69
}
@@ -91,12 +80,8 @@ static void printStructType(AsmPrinter &printer, LLVMStructType type) {
91
80
92
81
// Put the current type on stack to avoid infinite recursion.
93
82
printer << ' (' ;
94
- if (type.isIdentified ())
95
- knownStructNames.insert (type.getName ());
96
83
llvm::interleaveComma (type.getBody (), printer.getStream (),
97
84
[&](Type subtype) { dispatchPrint (printer, subtype); });
98
- if (type.isIdentified ())
99
- knownStructNames.pop_back ();
100
85
printer << ' )' ;
101
86
printer << ' >' ;
102
87
}
@@ -198,21 +183,6 @@ static LLVMStructType trySetStructBody(LLVMStructType type,
198
183
// / | `struct<` string-literal `>`
199
184
// / | `struct<` string-literal `, opaque>`
200
185
static LLVMStructType parseStructType (AsmParser &parser) {
201
- // This keeps track of the names of identified structure types that are
202
- // currently being parsed. Since such types can refer themselves, this
203
- // tracking is necessary to stop the recursion: the current function may be
204
- // called recursively from AsmParser::parseType after the appropriate
205
- // dispatch. We maintain the invariant of this storage being modified
206
- // exclusively in this function, and at most one name being added per call.
207
- // TODO: consider having such functionality inside AsmParser.
208
- thread_local SetVector<StringRef> knownStructNames;
209
- unsigned stackSize = knownStructNames.size ();
210
- (void )stackSize;
211
- auto guard = llvm::make_scope_exit ([&]() {
212
- assert (knownStructNames.size () == stackSize &&
213
- " malformed identified stack when parsing recursive structs" );
214
- });
215
-
216
186
Location loc = parser.getEncodedSourceLoc (parser.getCurrentLocation ());
217
187
218
188
if (failed (parser.parseLess ()))
@@ -224,11 +194,17 @@ static LLVMStructType parseStructType(AsmParser &parser) {
224
194
std::string name;
225
195
bool isIdentified = succeeded (parser.parseOptionalString (&name));
226
196
if (isIdentified) {
227
- if (knownStructNames.count (name)) {
228
- if (failed (parser.parseGreater ()))
229
- return LLVMStructType ();
230
- return LLVMStructType::getIdentifiedChecked (
197
+ SMLoc greaterLoc = parser.getCurrentLocation ();
198
+ if (succeeded (parser.parseOptionalGreater ())) {
199
+ auto type = LLVMStructType::getIdentifiedChecked (
231
200
[loc] { return emitError (loc); }, loc.getContext (), name);
201
+ if (succeeded (parser.tryStartCyclicParse (type)))
202
+ return parser.emitError (
203
+ greaterLoc,
204
+ " struct without a body only allowed in a recursive struct" ),
205
+ LLVMStructType ();
206
+
207
+ return type;
232
208
}
233
209
if (failed (parser.parseComma ()))
234
210
return LLVMStructType ();
@@ -251,6 +227,18 @@ static LLVMStructType parseStructType(AsmParser &parser) {
251
227
return type;
252
228
}
253
229
230
+ FailureOr<AsmParser::CyclicParseReset> cyclicParse;
231
+ if (isIdentified) {
232
+ cyclicParse =
233
+ parser.tryStartCyclicParse (LLVMStructType::getIdentifiedChecked (
234
+ [loc] { return emitError (loc); }, loc.getContext (), name));
235
+ if (failed (cyclicParse)) {
236
+ parser.emitError (kwLoc,
237
+ " identifier already used for an enclosing struct" );
238
+ return nullptr ;
239
+ }
240
+ }
241
+
254
242
// Check for packedness.
255
243
bool isPacked = succeeded (parser.parseOptionalKeyword (" packed" ));
256
244
if (failed (parser.parseLParen ()))
@@ -273,14 +261,10 @@ static LLVMStructType parseStructType(AsmParser &parser) {
273
261
SmallVector<Type, 4 > subtypes;
274
262
SMLoc subtypesLoc = parser.getCurrentLocation ();
275
263
do {
276
- if (isIdentified)
277
- knownStructNames.insert (name);
278
264
Type type;
279
265
if (dispatchParse (parser, type))
280
266
return LLVMStructType ();
281
267
subtypes.push_back (type);
282
- if (isIdentified)
283
- knownStructNames.pop_back ();
284
268
} while (succeeded (parser.parseOptionalComma ()));
285
269
286
270
if (parser.parseRParen () || parser.parseGreater ())
0 commit comments