Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Remarks/BitstreamRemarkParser.cpp
35262 views
1
//===- BitstreamRemarkParser.cpp ------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file provides utility methods used by clients that want to use the
10
// parser for remark diagnostics in LLVM.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "llvm/Remarks/BitstreamRemarkParser.h"
15
#include "BitstreamRemarkParser.h"
16
#include "llvm/Remarks/Remark.h"
17
#include "llvm/Support/MemoryBuffer.h"
18
#include "llvm/Support/Path.h"
19
#include <optional>
20
21
using namespace llvm;
22
using namespace llvm::remarks;
23
24
static Error unknownRecord(const char *BlockName, unsigned RecordID) {
25
return createStringError(
26
std::make_error_code(std::errc::illegal_byte_sequence),
27
"Error while parsing %s: unknown record entry (%lu).", BlockName,
28
RecordID);
29
}
30
31
static Error malformedRecord(const char *BlockName, const char *RecordName) {
32
return createStringError(
33
std::make_error_code(std::errc::illegal_byte_sequence),
34
"Error while parsing %s: malformed record entry (%s).", BlockName,
35
RecordName);
36
}
37
38
BitstreamMetaParserHelper::BitstreamMetaParserHelper(
39
BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo)
40
: Stream(Stream), BlockInfo(BlockInfo) {}
41
42
/// Parse a record and fill in the fields in the parser.
43
static Error parseRecord(BitstreamMetaParserHelper &Parser, unsigned Code) {
44
BitstreamCursor &Stream = Parser.Stream;
45
// Note: 2 is used here because it's the max number of fields we have per
46
// record.
47
SmallVector<uint64_t, 2> Record;
48
StringRef Blob;
49
Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob);
50
if (!RecordID)
51
return RecordID.takeError();
52
53
switch (*RecordID) {
54
case RECORD_META_CONTAINER_INFO: {
55
if (Record.size() != 2)
56
return malformedRecord("BLOCK_META", "RECORD_META_CONTAINER_INFO");
57
Parser.ContainerVersion = Record[0];
58
Parser.ContainerType = Record[1];
59
break;
60
}
61
case RECORD_META_REMARK_VERSION: {
62
if (Record.size() != 1)
63
return malformedRecord("BLOCK_META", "RECORD_META_REMARK_VERSION");
64
Parser.RemarkVersion = Record[0];
65
break;
66
}
67
case RECORD_META_STRTAB: {
68
if (Record.size() != 0)
69
return malformedRecord("BLOCK_META", "RECORD_META_STRTAB");
70
Parser.StrTabBuf = Blob;
71
break;
72
}
73
case RECORD_META_EXTERNAL_FILE: {
74
if (Record.size() != 0)
75
return malformedRecord("BLOCK_META", "RECORD_META_EXTERNAL_FILE");
76
Parser.ExternalFilePath = Blob;
77
break;
78
}
79
default:
80
return unknownRecord("BLOCK_META", *RecordID);
81
}
82
return Error::success();
83
}
84
85
BitstreamRemarkParserHelper::BitstreamRemarkParserHelper(
86
BitstreamCursor &Stream)
87
: Stream(Stream) {}
88
89
/// Parse a record and fill in the fields in the parser.
90
static Error parseRecord(BitstreamRemarkParserHelper &Parser, unsigned Code) {
91
BitstreamCursor &Stream = Parser.Stream;
92
// Note: 5 is used here because it's the max number of fields we have per
93
// record.
94
SmallVector<uint64_t, 5> Record;
95
StringRef Blob;
96
Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob);
97
if (!RecordID)
98
return RecordID.takeError();
99
100
switch (*RecordID) {
101
case RECORD_REMARK_HEADER: {
102
if (Record.size() != 4)
103
return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HEADER");
104
Parser.Type = Record[0];
105
Parser.RemarkNameIdx = Record[1];
106
Parser.PassNameIdx = Record[2];
107
Parser.FunctionNameIdx = Record[3];
108
break;
109
}
110
case RECORD_REMARK_DEBUG_LOC: {
111
if (Record.size() != 3)
112
return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_DEBUG_LOC");
113
Parser.SourceFileNameIdx = Record[0];
114
Parser.SourceLine = Record[1];
115
Parser.SourceColumn = Record[2];
116
break;
117
}
118
case RECORD_REMARK_HOTNESS: {
119
if (Record.size() != 1)
120
return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HOTNESS");
121
Parser.Hotness = Record[0];
122
break;
123
}
124
case RECORD_REMARK_ARG_WITH_DEBUGLOC: {
125
if (Record.size() != 5)
126
return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_ARG_WITH_DEBUGLOC");
127
// Create a temporary argument. Use that as a valid memory location for this
128
// argument entry.
129
Parser.TmpArgs.emplace_back();
130
Parser.TmpArgs.back().KeyIdx = Record[0];
131
Parser.TmpArgs.back().ValueIdx = Record[1];
132
Parser.TmpArgs.back().SourceFileNameIdx = Record[2];
133
Parser.TmpArgs.back().SourceLine = Record[3];
134
Parser.TmpArgs.back().SourceColumn = Record[4];
135
Parser.Args =
136
ArrayRef<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs);
137
break;
138
}
139
case RECORD_REMARK_ARG_WITHOUT_DEBUGLOC: {
140
if (Record.size() != 2)
141
return malformedRecord("BLOCK_REMARK",
142
"RECORD_REMARK_ARG_WITHOUT_DEBUGLOC");
143
// Create a temporary argument. Use that as a valid memory location for this
144
// argument entry.
145
Parser.TmpArgs.emplace_back();
146
Parser.TmpArgs.back().KeyIdx = Record[0];
147
Parser.TmpArgs.back().ValueIdx = Record[1];
148
Parser.Args =
149
ArrayRef<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs);
150
break;
151
}
152
default:
153
return unknownRecord("BLOCK_REMARK", *RecordID);
154
}
155
return Error::success();
156
}
157
158
template <typename T>
159
static Error parseBlock(T &ParserHelper, unsigned BlockID,
160
const char *BlockName) {
161
BitstreamCursor &Stream = ParserHelper.Stream;
162
Expected<BitstreamEntry> Next = Stream.advance();
163
if (!Next)
164
return Next.takeError();
165
if (Next->Kind != BitstreamEntry::SubBlock || Next->ID != BlockID)
166
return createStringError(
167
std::make_error_code(std::errc::illegal_byte_sequence),
168
"Error while parsing %s: expecting [ENTER_SUBBLOCK, %s, ...].",
169
BlockName, BlockName);
170
if (Stream.EnterSubBlock(BlockID))
171
return createStringError(
172
std::make_error_code(std::errc::illegal_byte_sequence),
173
"Error while entering %s.", BlockName);
174
175
// Stop when there is nothing to read anymore or when we encounter an
176
// END_BLOCK.
177
while (!Stream.AtEndOfStream()) {
178
Next = Stream.advance();
179
if (!Next)
180
return Next.takeError();
181
switch (Next->Kind) {
182
case BitstreamEntry::EndBlock:
183
return Error::success();
184
case BitstreamEntry::Error:
185
case BitstreamEntry::SubBlock:
186
return createStringError(
187
std::make_error_code(std::errc::illegal_byte_sequence),
188
"Error while parsing %s: expecting records.", BlockName);
189
case BitstreamEntry::Record:
190
if (Error E = parseRecord(ParserHelper, Next->ID))
191
return E;
192
continue;
193
}
194
}
195
// If we're here, it means we didn't get an END_BLOCK yet, but we're at the
196
// end of the stream. In this case, error.
197
return createStringError(
198
std::make_error_code(std::errc::illegal_byte_sequence),
199
"Error while parsing %s: unterminated block.", BlockName);
200
}
201
202
Error BitstreamMetaParserHelper::parse() {
203
return parseBlock(*this, META_BLOCK_ID, "META_BLOCK");
204
}
205
206
Error BitstreamRemarkParserHelper::parse() {
207
return parseBlock(*this, REMARK_BLOCK_ID, "REMARK_BLOCK");
208
}
209
210
BitstreamParserHelper::BitstreamParserHelper(StringRef Buffer)
211
: Stream(Buffer) {}
212
213
Expected<std::array<char, 4>> BitstreamParserHelper::parseMagic() {
214
std::array<char, 4> Result;
215
for (unsigned i = 0; i < 4; ++i)
216
if (Expected<unsigned> R = Stream.Read(8))
217
Result[i] = *R;
218
else
219
return R.takeError();
220
return Result;
221
}
222
223
Error BitstreamParserHelper::parseBlockInfoBlock() {
224
Expected<BitstreamEntry> Next = Stream.advance();
225
if (!Next)
226
return Next.takeError();
227
if (Next->Kind != BitstreamEntry::SubBlock ||
228
Next->ID != llvm::bitc::BLOCKINFO_BLOCK_ID)
229
return createStringError(
230
std::make_error_code(std::errc::illegal_byte_sequence),
231
"Error while parsing BLOCKINFO_BLOCK: expecting [ENTER_SUBBLOCK, "
232
"BLOCKINFO_BLOCK, ...].");
233
234
Expected<std::optional<BitstreamBlockInfo>> MaybeBlockInfo =
235
Stream.ReadBlockInfoBlock();
236
if (!MaybeBlockInfo)
237
return MaybeBlockInfo.takeError();
238
239
if (!*MaybeBlockInfo)
240
return createStringError(
241
std::make_error_code(std::errc::illegal_byte_sequence),
242
"Error while parsing BLOCKINFO_BLOCK.");
243
244
BlockInfo = **MaybeBlockInfo;
245
246
Stream.setBlockInfo(&BlockInfo);
247
return Error::success();
248
}
249
250
static Expected<bool> isBlock(BitstreamCursor &Stream, unsigned BlockID) {
251
bool Result = false;
252
uint64_t PreviousBitNo = Stream.GetCurrentBitNo();
253
Expected<BitstreamEntry> Next = Stream.advance();
254
if (!Next)
255
return Next.takeError();
256
switch (Next->Kind) {
257
case BitstreamEntry::SubBlock:
258
// Check for the block id.
259
Result = Next->ID == BlockID;
260
break;
261
case BitstreamEntry::Error:
262
return createStringError(
263
std::make_error_code(std::errc::illegal_byte_sequence),
264
"Unexpected error while parsing bitstream.");
265
default:
266
Result = false;
267
break;
268
}
269
if (Error E = Stream.JumpToBit(PreviousBitNo))
270
return std::move(E);
271
return Result;
272
}
273
274
Expected<bool> BitstreamParserHelper::isMetaBlock() {
275
return isBlock(Stream, META_BLOCK_ID);
276
}
277
278
Expected<bool> BitstreamParserHelper::isRemarkBlock() {
279
return isBlock(Stream, META_BLOCK_ID);
280
}
281
282
static Error validateMagicNumber(StringRef MagicNumber) {
283
if (MagicNumber != remarks::ContainerMagic)
284
return createStringError(std::make_error_code(std::errc::invalid_argument),
285
"Unknown magic number: expecting %s, got %.4s.",
286
remarks::ContainerMagic.data(), MagicNumber.data());
287
return Error::success();
288
}
289
290
static Error advanceToMetaBlock(BitstreamParserHelper &Helper) {
291
Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic();
292
if (!MagicNumber)
293
return MagicNumber.takeError();
294
if (Error E = validateMagicNumber(
295
StringRef(MagicNumber->data(), MagicNumber->size())))
296
return E;
297
if (Error E = Helper.parseBlockInfoBlock())
298
return E;
299
Expected<bool> isMetaBlock = Helper.isMetaBlock();
300
if (!isMetaBlock)
301
return isMetaBlock.takeError();
302
if (!*isMetaBlock)
303
return createStringError(
304
std::make_error_code(std::errc::illegal_byte_sequence),
305
"Expecting META_BLOCK after the BLOCKINFO_BLOCK.");
306
return Error::success();
307
}
308
309
Expected<std::unique_ptr<BitstreamRemarkParser>>
310
remarks::createBitstreamParserFromMeta(
311
StringRef Buf, std::optional<ParsedStringTable> StrTab,
312
std::optional<StringRef> ExternalFilePrependPath) {
313
BitstreamParserHelper Helper(Buf);
314
Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic();
315
if (!MagicNumber)
316
return MagicNumber.takeError();
317
318
if (Error E = validateMagicNumber(
319
StringRef(MagicNumber->data(), MagicNumber->size())))
320
return std::move(E);
321
322
auto Parser =
323
StrTab ? std::make_unique<BitstreamRemarkParser>(Buf, std::move(*StrTab))
324
: std::make_unique<BitstreamRemarkParser>(Buf);
325
326
if (ExternalFilePrependPath)
327
Parser->ExternalFilePrependPath = std::string(*ExternalFilePrependPath);
328
329
return std::move(Parser);
330
}
331
332
Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() {
333
if (ParserHelper.atEndOfStream())
334
return make_error<EndOfFileError>();
335
336
if (!ReadyToParseRemarks) {
337
if (Error E = parseMeta())
338
return std::move(E);
339
ReadyToParseRemarks = true;
340
}
341
342
return parseRemark();
343
}
344
345
Error BitstreamRemarkParser::parseMeta() {
346
// Advance and to the meta block.
347
if (Error E = advanceToMetaBlock(ParserHelper))
348
return E;
349
350
BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream,
351
ParserHelper.BlockInfo);
352
if (Error E = MetaHelper.parse())
353
return E;
354
355
if (Error E = processCommonMeta(MetaHelper))
356
return E;
357
358
switch (ContainerType) {
359
case BitstreamRemarkContainerType::Standalone:
360
return processStandaloneMeta(MetaHelper);
361
case BitstreamRemarkContainerType::SeparateRemarksFile:
362
return processSeparateRemarksFileMeta(MetaHelper);
363
case BitstreamRemarkContainerType::SeparateRemarksMeta:
364
return processSeparateRemarksMetaMeta(MetaHelper);
365
}
366
llvm_unreachable("Unknown BitstreamRemarkContainerType enum");
367
}
368
369
Error BitstreamRemarkParser::processCommonMeta(
370
BitstreamMetaParserHelper &Helper) {
371
if (std::optional<uint64_t> Version = Helper.ContainerVersion)
372
ContainerVersion = *Version;
373
else
374
return createStringError(
375
std::make_error_code(std::errc::illegal_byte_sequence),
376
"Error while parsing BLOCK_META: missing container version.");
377
378
if (std::optional<uint8_t> Type = Helper.ContainerType) {
379
// Always >= BitstreamRemarkContainerType::First since it's unsigned.
380
if (*Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last))
381
return createStringError(
382
std::make_error_code(std::errc::illegal_byte_sequence),
383
"Error while parsing BLOCK_META: invalid container type.");
384
385
ContainerType = static_cast<BitstreamRemarkContainerType>(*Type);
386
} else
387
return createStringError(
388
std::make_error_code(std::errc::illegal_byte_sequence),
389
"Error while parsing BLOCK_META: missing container type.");
390
391
return Error::success();
392
}
393
394
static Error processStrTab(BitstreamRemarkParser &P,
395
std::optional<StringRef> StrTabBuf) {
396
if (!StrTabBuf)
397
return createStringError(
398
std::make_error_code(std::errc::illegal_byte_sequence),
399
"Error while parsing BLOCK_META: missing string table.");
400
// Parse and assign the string table.
401
P.StrTab.emplace(*StrTabBuf);
402
return Error::success();
403
}
404
405
static Error processRemarkVersion(BitstreamRemarkParser &P,
406
std::optional<uint64_t> RemarkVersion) {
407
if (!RemarkVersion)
408
return createStringError(
409
std::make_error_code(std::errc::illegal_byte_sequence),
410
"Error while parsing BLOCK_META: missing remark version.");
411
P.RemarkVersion = *RemarkVersion;
412
return Error::success();
413
}
414
415
Error BitstreamRemarkParser::processExternalFilePath(
416
std::optional<StringRef> ExternalFilePath) {
417
if (!ExternalFilePath)
418
return createStringError(
419
std::make_error_code(std::errc::illegal_byte_sequence),
420
"Error while parsing BLOCK_META: missing external file path.");
421
422
SmallString<80> FullPath(ExternalFilePrependPath);
423
sys::path::append(FullPath, *ExternalFilePath);
424
425
// External file: open the external file, parse it, check if its metadata
426
// matches the one from the separate metadata, then replace the current parser
427
// with the one parsing the remarks.
428
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
429
MemoryBuffer::getFile(FullPath);
430
if (std::error_code EC = BufferOrErr.getError())
431
return createFileError(FullPath, EC);
432
433
TmpRemarkBuffer = std::move(*BufferOrErr);
434
435
// Don't try to parse the file if it's empty.
436
if (TmpRemarkBuffer->getBufferSize() == 0)
437
return make_error<EndOfFileError>();
438
439
// Create a separate parser used for parsing the separate file.
440
ParserHelper = BitstreamParserHelper(TmpRemarkBuffer->getBuffer());
441
// Advance and check until we can parse the meta block.
442
if (Error E = advanceToMetaBlock(ParserHelper))
443
return E;
444
// Parse the meta from the separate file.
445
// Note: here we overwrite the BlockInfo with the one from the file. This will
446
// be used to parse the rest of the file.
447
BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream,
448
ParserHelper.BlockInfo);
449
if (Error E = SeparateMetaHelper.parse())
450
return E;
451
452
uint64_t PreviousContainerVersion = ContainerVersion;
453
if (Error E = processCommonMeta(SeparateMetaHelper))
454
return E;
455
456
if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile)
457
return createStringError(
458
std::make_error_code(std::errc::illegal_byte_sequence),
459
"Error while parsing external file's BLOCK_META: wrong container "
460
"type.");
461
462
if (PreviousContainerVersion != ContainerVersion)
463
return createStringError(
464
std::make_error_code(std::errc::illegal_byte_sequence),
465
"Error while parsing external file's BLOCK_META: mismatching versions: "
466
"original meta: %lu, external file meta: %lu.",
467
PreviousContainerVersion, ContainerVersion);
468
469
// Process the meta from the separate file.
470
return processSeparateRemarksFileMeta(SeparateMetaHelper);
471
}
472
473
Error BitstreamRemarkParser::processStandaloneMeta(
474
BitstreamMetaParserHelper &Helper) {
475
if (Error E = processStrTab(*this, Helper.StrTabBuf))
476
return E;
477
return processRemarkVersion(*this, Helper.RemarkVersion);
478
}
479
480
Error BitstreamRemarkParser::processSeparateRemarksFileMeta(
481
BitstreamMetaParserHelper &Helper) {
482
return processRemarkVersion(*this, Helper.RemarkVersion);
483
}
484
485
Error BitstreamRemarkParser::processSeparateRemarksMetaMeta(
486
BitstreamMetaParserHelper &Helper) {
487
if (Error E = processStrTab(*this, Helper.StrTabBuf))
488
return E;
489
return processExternalFilePath(Helper.ExternalFilePath);
490
}
491
492
Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::parseRemark() {
493
BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream);
494
if (Error E = RemarkHelper.parse())
495
return std::move(E);
496
497
return processRemark(RemarkHelper);
498
}
499
500
Expected<std::unique_ptr<Remark>>
501
BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) {
502
std::unique_ptr<Remark> Result = std::make_unique<Remark>();
503
Remark &R = *Result;
504
505
if (StrTab == std::nullopt)
506
return createStringError(
507
std::make_error_code(std::errc::invalid_argument),
508
"Error while parsing BLOCK_REMARK: missing string table.");
509
510
if (!Helper.Type)
511
return createStringError(
512
std::make_error_code(std::errc::illegal_byte_sequence),
513
"Error while parsing BLOCK_REMARK: missing remark type.");
514
515
// Always >= Type::First since it's unsigned.
516
if (*Helper.Type > static_cast<uint8_t>(Type::Last))
517
return createStringError(
518
std::make_error_code(std::errc::illegal_byte_sequence),
519
"Error while parsing BLOCK_REMARK: unknown remark type.");
520
521
R.RemarkType = static_cast<Type>(*Helper.Type);
522
523
if (!Helper.RemarkNameIdx)
524
return createStringError(
525
std::make_error_code(std::errc::illegal_byte_sequence),
526
"Error while parsing BLOCK_REMARK: missing remark name.");
527
528
if (Expected<StringRef> RemarkName = (*StrTab)[*Helper.RemarkNameIdx])
529
R.RemarkName = *RemarkName;
530
else
531
return RemarkName.takeError();
532
533
if (!Helper.PassNameIdx)
534
return createStringError(
535
std::make_error_code(std::errc::illegal_byte_sequence),
536
"Error while parsing BLOCK_REMARK: missing remark pass.");
537
538
if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx])
539
R.PassName = *PassName;
540
else
541
return PassName.takeError();
542
543
if (!Helper.FunctionNameIdx)
544
return createStringError(
545
std::make_error_code(std::errc::illegal_byte_sequence),
546
"Error while parsing BLOCK_REMARK: missing remark function name.");
547
if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx])
548
R.FunctionName = *FunctionName;
549
else
550
return FunctionName.takeError();
551
552
if (Helper.SourceFileNameIdx && Helper.SourceLine && Helper.SourceColumn) {
553
Expected<StringRef> SourceFileName = (*StrTab)[*Helper.SourceFileNameIdx];
554
if (!SourceFileName)
555
return SourceFileName.takeError();
556
R.Loc.emplace();
557
R.Loc->SourceFilePath = *SourceFileName;
558
R.Loc->SourceLine = *Helper.SourceLine;
559
R.Loc->SourceColumn = *Helper.SourceColumn;
560
}
561
562
if (Helper.Hotness)
563
R.Hotness = *Helper.Hotness;
564
565
if (!Helper.Args)
566
return std::move(Result);
567
568
for (const BitstreamRemarkParserHelper::Argument &Arg : *Helper.Args) {
569
if (!Arg.KeyIdx)
570
return createStringError(
571
std::make_error_code(std::errc::illegal_byte_sequence),
572
"Error while parsing BLOCK_REMARK: missing key in remark argument.");
573
if (!Arg.ValueIdx)
574
return createStringError(
575
std::make_error_code(std::errc::illegal_byte_sequence),
576
"Error while parsing BLOCK_REMARK: missing value in remark "
577
"argument.");
578
579
// We have at least a key and a value, create an entry.
580
R.Args.emplace_back();
581
582
if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx])
583
R.Args.back().Key = *Key;
584
else
585
return Key.takeError();
586
587
if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx])
588
R.Args.back().Val = *Value;
589
else
590
return Value.takeError();
591
592
if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) {
593
if (Expected<StringRef> SourceFileName =
594
(*StrTab)[*Arg.SourceFileNameIdx]) {
595
R.Args.back().Loc.emplace();
596
R.Args.back().Loc->SourceFilePath = *SourceFileName;
597
R.Args.back().Loc->SourceLine = *Arg.SourceLine;
598
R.Args.back().Loc->SourceColumn = *Arg.SourceColumn;
599
} else
600
return SourceFileName.takeError();
601
}
602
}
603
604
return std::move(Result);
605
}
606
607