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