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<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 = std::make_unique<BitstreamRemarkParser>(Buf); 322 323 if (ExternalFilePrependPath) 324 Parser->ExternalFilePrependPath = std::string(*ExternalFilePrependPath); 325 326 return std::move(Parser); 327 } 328 329 Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() { 330 if (ParserHelper.atEndOfStream()) 331 return make_error<EndOfFileError>(); 332 333 if (!ReadyToParseRemarks) { 334 if (Error E = parseMeta()) 335 return std::move(E); 336 ReadyToParseRemarks = true; 337 } 338 339 return parseRemark(); 340 } 341 342 Error BitstreamRemarkParser::parseMeta() { 343 // Advance and to the meta block. 344 if (Error E = advanceToMetaBlock(ParserHelper)) 345 return E; 346 347 BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream, 348 ParserHelper.BlockInfo); 349 if (Error E = MetaHelper.parse()) 350 return E; 351 352 if (Error E = processCommonMeta(MetaHelper)) 353 return E; 354 355 switch (ContainerType) { 356 case BitstreamRemarkContainerType::Standalone: 357 return processStandaloneMeta(MetaHelper); 358 case BitstreamRemarkContainerType::SeparateRemarksFile: 359 return processSeparateRemarksFileMeta(MetaHelper); 360 case BitstreamRemarkContainerType::SeparateRemarksMeta: 361 return processSeparateRemarksMetaMeta(MetaHelper); 362 } 363 llvm_unreachable("Unknown BitstreamRemarkContainerType enum"); 364 } 365 366 Error BitstreamRemarkParser::processCommonMeta( 367 BitstreamMetaParserHelper &Helper) { 368 if (std::optional<uint64_t> Version = Helper.ContainerVersion) 369 ContainerVersion = *Version; 370 else 371 return createStringError( 372 std::make_error_code(std::errc::illegal_byte_sequence), 373 "Error while parsing BLOCK_META: missing container version."); 374 375 if (std::optional<uint8_t> Type = Helper.ContainerType) { 376 // Always >= BitstreamRemarkContainerType::First since it's unsigned. 377 if (*Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last)) 378 return createStringError( 379 std::make_error_code(std::errc::illegal_byte_sequence), 380 "Error while parsing BLOCK_META: invalid container type."); 381 382 ContainerType = static_cast<BitstreamRemarkContainerType>(*Type); 383 } else 384 return createStringError( 385 std::make_error_code(std::errc::illegal_byte_sequence), 386 "Error while parsing BLOCK_META: missing container type."); 387 388 return Error::success(); 389 } 390 391 static Error processStrTab(BitstreamRemarkParser &P, 392 std::optional<StringRef> StrTabBuf) { 393 if (!StrTabBuf) 394 return createStringError( 395 std::make_error_code(std::errc::illegal_byte_sequence), 396 "Error while parsing BLOCK_META: missing string table."); 397 // Parse and assign the string table. 398 P.StrTab.emplace(*StrTabBuf); 399 return Error::success(); 400 } 401 402 static Error processRemarkVersion(BitstreamRemarkParser &P, 403 std::optional<uint64_t> RemarkVersion) { 404 if (!RemarkVersion) 405 return createStringError( 406 std::make_error_code(std::errc::illegal_byte_sequence), 407 "Error while parsing BLOCK_META: missing remark version."); 408 P.RemarkVersion = *RemarkVersion; 409 return Error::success(); 410 } 411 412 Error BitstreamRemarkParser::processExternalFilePath( 413 std::optional<StringRef> ExternalFilePath) { 414 if (!ExternalFilePath) 415 return createStringError( 416 std::make_error_code(std::errc::illegal_byte_sequence), 417 "Error while parsing BLOCK_META: missing external file path."); 418 419 SmallString<80> FullPath(ExternalFilePrependPath); 420 sys::path::append(FullPath, *ExternalFilePath); 421 422 // External file: open the external file, parse it, check if its metadata 423 // matches the one from the separate metadata, then replace the current parser 424 // with the one parsing the remarks. 425 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = 426 MemoryBuffer::getFile(FullPath); 427 if (std::error_code EC = BufferOrErr.getError()) 428 return createFileError(FullPath, EC); 429 430 TmpRemarkBuffer = std::move(*BufferOrErr); 431 432 // Don't try to parse the file if it's empty. 433 if (TmpRemarkBuffer->getBufferSize() == 0) 434 return make_error<EndOfFileError>(); 435 436 // Create a separate parser used for parsing the separate file. 437 ParserHelper = BitstreamParserHelper(TmpRemarkBuffer->getBuffer()); 438 // Advance and check until we can parse the meta block. 439 if (Error E = advanceToMetaBlock(ParserHelper)) 440 return E; 441 // Parse the meta from the separate file. 442 // Note: here we overwrite the BlockInfo with the one from the file. This will 443 // be used to parse the rest of the file. 444 BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream, 445 ParserHelper.BlockInfo); 446 if (Error E = SeparateMetaHelper.parse()) 447 return E; 448 449 uint64_t PreviousContainerVersion = ContainerVersion; 450 if (Error E = processCommonMeta(SeparateMetaHelper)) 451 return E; 452 453 if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile) 454 return createStringError( 455 std::make_error_code(std::errc::illegal_byte_sequence), 456 "Error while parsing external file's BLOCK_META: wrong container " 457 "type."); 458 459 if (PreviousContainerVersion != ContainerVersion) 460 return createStringError( 461 std::make_error_code(std::errc::illegal_byte_sequence), 462 "Error while parsing external file's BLOCK_META: mismatching versions: " 463 "original meta: %lu, external file meta: %lu.", 464 PreviousContainerVersion, ContainerVersion); 465 466 // Process the meta from the separate file. 467 return processSeparateRemarksFileMeta(SeparateMetaHelper); 468 } 469 470 Error BitstreamRemarkParser::processStandaloneMeta( 471 BitstreamMetaParserHelper &Helper) { 472 if (Error E = processStrTab(*this, Helper.StrTabBuf)) 473 return E; 474 return processRemarkVersion(*this, Helper.RemarkVersion); 475 } 476 477 Error BitstreamRemarkParser::processSeparateRemarksFileMeta( 478 BitstreamMetaParserHelper &Helper) { 479 return processRemarkVersion(*this, Helper.RemarkVersion); 480 } 481 482 Error BitstreamRemarkParser::processSeparateRemarksMetaMeta( 483 BitstreamMetaParserHelper &Helper) { 484 if (Error E = processStrTab(*this, Helper.StrTabBuf)) 485 return E; 486 return processExternalFilePath(Helper.ExternalFilePath); 487 } 488 489 Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::parseRemark() { 490 BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream); 491 if (Error E = RemarkHelper.parse()) 492 return std::move(E); 493 494 return processRemark(RemarkHelper); 495 } 496 497 Expected<std::unique_ptr<Remark>> 498 BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) { 499 std::unique_ptr<Remark> Result = std::make_unique<Remark>(); 500 Remark &R = *Result; 501 502 if (StrTab == std::nullopt) 503 return createStringError( 504 std::make_error_code(std::errc::invalid_argument), 505 "Error while parsing BLOCK_REMARK: missing string table."); 506 507 if (!Helper.Type) 508 return createStringError( 509 std::make_error_code(std::errc::illegal_byte_sequence), 510 "Error while parsing BLOCK_REMARK: missing remark type."); 511 512 // Always >= Type::First since it's unsigned. 513 if (*Helper.Type > static_cast<uint8_t>(Type::Last)) 514 return createStringError( 515 std::make_error_code(std::errc::illegal_byte_sequence), 516 "Error while parsing BLOCK_REMARK: unknown remark type."); 517 518 R.RemarkType = static_cast<Type>(*Helper.Type); 519 520 if (!Helper.RemarkNameIdx) 521 return createStringError( 522 std::make_error_code(std::errc::illegal_byte_sequence), 523 "Error while parsing BLOCK_REMARK: missing remark name."); 524 525 if (Expected<StringRef> RemarkName = (*StrTab)[*Helper.RemarkNameIdx]) 526 R.RemarkName = *RemarkName; 527 else 528 return RemarkName.takeError(); 529 530 if (!Helper.PassNameIdx) 531 return createStringError( 532 std::make_error_code(std::errc::illegal_byte_sequence), 533 "Error while parsing BLOCK_REMARK: missing remark pass."); 534 535 if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx]) 536 R.PassName = *PassName; 537 else 538 return PassName.takeError(); 539 540 if (!Helper.FunctionNameIdx) 541 return createStringError( 542 std::make_error_code(std::errc::illegal_byte_sequence), 543 "Error while parsing BLOCK_REMARK: missing remark function name."); 544 if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx]) 545 R.FunctionName = *FunctionName; 546 else 547 return FunctionName.takeError(); 548 549 if (Helper.SourceFileNameIdx && Helper.SourceLine && Helper.SourceColumn) { 550 Expected<StringRef> SourceFileName = (*StrTab)[*Helper.SourceFileNameIdx]; 551 if (!SourceFileName) 552 return SourceFileName.takeError(); 553 R.Loc.emplace(); 554 R.Loc->SourceFilePath = *SourceFileName; 555 R.Loc->SourceLine = *Helper.SourceLine; 556 R.Loc->SourceColumn = *Helper.SourceColumn; 557 } 558 559 if (Helper.Hotness) 560 R.Hotness = *Helper.Hotness; 561 562 if (!Helper.Args) 563 return std::move(Result); 564 565 for (const BitstreamRemarkParserHelper::Argument &Arg : *Helper.Args) { 566 if (!Arg.KeyIdx) 567 return createStringError( 568 std::make_error_code(std::errc::illegal_byte_sequence), 569 "Error while parsing BLOCK_REMARK: missing key in remark argument."); 570 if (!Arg.ValueIdx) 571 return createStringError( 572 std::make_error_code(std::errc::illegal_byte_sequence), 573 "Error while parsing BLOCK_REMARK: missing value in remark " 574 "argument."); 575 576 // We have at least a key and a value, create an entry. 577 R.Args.emplace_back(); 578 579 if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx]) 580 R.Args.back().Key = *Key; 581 else 582 return Key.takeError(); 583 584 if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx]) 585 R.Args.back().Val = *Value; 586 else 587 return Value.takeError(); 588 589 if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) { 590 if (Expected<StringRef> SourceFileName = 591 (*StrTab)[*Arg.SourceFileNameIdx]) { 592 R.Args.back().Loc.emplace(); 593 R.Args.back().Loc->SourceFilePath = *SourceFileName; 594 R.Args.back().Loc->SourceLine = *Arg.SourceLine; 595 R.Args.back().Loc->SourceColumn = *Arg.SourceColumn; 596 } else 597 return SourceFileName.takeError(); 598 } 599 } 600 601 return std::move(Result); 602 } 603