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