733 lines · cpp
1//===-- lib/Parser/provenance.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang/Parser/provenance.h"10#include "flang/Common/idioms.h"11#include "llvm/Support/raw_ostream.h"12#include <algorithm>13#include <set>14#include <utility>15 16namespace Fortran::parser {17 18ProvenanceRangeToOffsetMappings::ProvenanceRangeToOffsetMappings() {}19ProvenanceRangeToOffsetMappings::~ProvenanceRangeToOffsetMappings() {}20 21void ProvenanceRangeToOffsetMappings::Put(22 ProvenanceRange range, std::size_t offset) {23 auto fromTo{map_.equal_range(range)};24 for (auto iter{fromTo.first}; iter != fromTo.second; ++iter) {25 if (range == iter->first) {26 iter->second = std::min(offset, iter->second);27 return;28 }29 }30 if (fromTo.second != map_.end()) {31 map_.emplace_hint(fromTo.second, range, offset);32 } else {33 map_.emplace(range, offset);34 }35}36 37std::optional<std::size_t> ProvenanceRangeToOffsetMappings::Map(38 ProvenanceRange range) const {39 auto fromTo{map_.equal_range(range)};40 std::optional<std::size_t> result;41 for (auto iter{fromTo.first}; iter != fromTo.second; ++iter) {42 ProvenanceRange that{iter->first};43 if (that.Contains(range)) {44 std::size_t offset{iter->second + that.MemberOffset(range.start())};45 if (!result || offset < *result) {46 result = offset;47 }48 }49 }50 return result;51}52 53bool ProvenanceRangeToOffsetMappings::WhollyPrecedes::operator()(54 ProvenanceRange before, ProvenanceRange after) const {55 return before.start() + before.size() <= after.start();56}57 58void OffsetToProvenanceMappings::clear() { provenanceMap_.clear(); }59 60void OffsetToProvenanceMappings::swap(OffsetToProvenanceMappings &that) {61 provenanceMap_.swap(that.provenanceMap_);62}63 64void OffsetToProvenanceMappings::shrink_to_fit() {65 provenanceMap_.shrink_to_fit();66}67 68std::size_t OffsetToProvenanceMappings::SizeInBytes() const {69 if (provenanceMap_.empty()) {70 return 0;71 } else {72 const ContiguousProvenanceMapping &last{provenanceMap_.back()};73 return last.start + last.range.size();74 }75}76 77void OffsetToProvenanceMappings::Put(ProvenanceRange range) {78 if (provenanceMap_.empty()) {79 provenanceMap_.push_back({0, range});80 } else {81 ContiguousProvenanceMapping &last{provenanceMap_.back()};82 if (!last.range.AnnexIfPredecessor(range)) {83 provenanceMap_.push_back({last.start + last.range.size(), range});84 }85 }86}87 88void OffsetToProvenanceMappings::Put(const OffsetToProvenanceMappings &that) {89 for (const auto &map : that.provenanceMap_) {90 Put(map.range);91 }92}93 94ProvenanceRange OffsetToProvenanceMappings::Map(std::size_t at) const {95 if (provenanceMap_.empty()) {96 CHECK(at == 0);97 return {};98 }99 std::size_t low{0}, count{provenanceMap_.size()};100 while (count > 1) {101 std::size_t mid{low + (count >> 1)};102 if (provenanceMap_[mid].start > at) {103 count = mid - low;104 } else {105 count -= mid - low;106 low = mid;107 }108 }109 std::size_t offset{at - provenanceMap_[low].start};110 return provenanceMap_[low].range.Suffix(offset);111}112 113void OffsetToProvenanceMappings::RemoveLastBytes(std::size_t bytes) {114 for (; bytes > 0; provenanceMap_.pop_back()) {115 CHECK(!provenanceMap_.empty());116 ContiguousProvenanceMapping &last{provenanceMap_.back()};117 std::size_t chunk{last.range.size()};118 if (bytes < chunk) {119 last.range = last.range.Prefix(chunk - bytes);120 break;121 }122 bytes -= chunk;123 }124}125 126ProvenanceRangeToOffsetMappings OffsetToProvenanceMappings::Invert(127 const AllSources &allSources) const {128 ProvenanceRangeToOffsetMappings result;129 for (const auto &contig : provenanceMap_) {130 ProvenanceRange range{contig.range};131 while (!range.empty()) {132 ProvenanceRange source{allSources.IntersectionWithSourceFiles(range)};133 if (source.empty()) {134 break;135 }136 result.Put(137 source, contig.start + contig.range.MemberOffset(source.start()));138 Provenance after{source.NextAfter()};139 if (range.Contains(after)) {140 range = range.Suffix(range.MemberOffset(after));141 } else {142 break;143 }144 }145 }146 return result;147}148 149AllSources::AllSources() : range_{1, 1} {150 // Start the origin_ array with a dummy entry that has a forced provenance,151 // so that provenance offset 0 remains reserved as an uninitialized152 // value.153 origin_.emplace_back(range_, std::string{'?'});154}155 156AllSources::~AllSources() {}157 158const char &AllSources::operator[](Provenance at) const {159 const Origin &origin{MapToOrigin(at)};160 return origin[origin.covers.MemberOffset(at)];161}162 163void AllSources::ClearSearchPath() { searchPath_.clear(); }164 165void AllSources::AppendSearchPathDirectory(std::string directory) {166 // gfortran and ifort append to current path, PGI prepends167 searchPath_.push_back(directory);168}169 170const SourceFile *AllSources::OpenPath(171 std::string path, llvm::raw_ostream &error) {172 std::unique_ptr<SourceFile> source{std::make_unique<SourceFile>(encoding_)};173 if (source->Open(path, error)) {174 return ownedSourceFiles_.emplace_back(std::move(source)).get();175 } else {176 return nullptr;177 }178}179 180const SourceFile *AllSources::Open(std::string path, llvm::raw_ostream &error,181 std::optional<std::string> &&prependPath) {182 std::unique_ptr<SourceFile> source{std::make_unique<SourceFile>(encoding_)};183 if (prependPath) {184 // Set to "." for the initial source file; set to the directory name185 // of the including file for #include "quoted-file" directives &186 // INCLUDE statements.187 searchPath_.emplace_front(std::move(*prependPath));188 }189 std::optional<std::string> found{LocateSourceFile(path, searchPath_)};190 if (prependPath) {191 searchPath_.pop_front();192 }193 if (found) {194 return OpenPath(*found, error);195 } else {196 error << "Source file '" << path << "' was not found";197 return nullptr;198 }199}200 201const SourceFile *AllSources::ReadStandardInput(llvm::raw_ostream &error) {202 std::unique_ptr<SourceFile> source{std::make_unique<SourceFile>(encoding_)};203 if (source->ReadStandardInput(error)) {204 return ownedSourceFiles_.emplace_back(std::move(source)).get();205 }206 return nullptr;207}208 209ProvenanceRange AllSources::AddIncludedFile(210 const SourceFile &source, ProvenanceRange from, bool isModule) {211 ProvenanceRange covers{range_.NextAfter(), source.bytes()};212 CHECK(range_.AnnexIfPredecessor(covers));213 CHECK(origin_.back().covers.ImmediatelyPrecedes(covers));214 origin_.emplace_back(covers, source, from, isModule);215 return covers;216}217 218ProvenanceRange AllSources::AddMacroCall(219 ProvenanceRange def, ProvenanceRange use, const std::string &expansion) {220 ProvenanceRange covers{range_.NextAfter(), expansion.size()};221 CHECK(range_.AnnexIfPredecessor(covers));222 CHECK(origin_.back().covers.ImmediatelyPrecedes(covers));223 origin_.emplace_back(covers, def, use, expansion);224 return covers;225}226 227ProvenanceRange AllSources::AddCompilerInsertion(std::string text) {228 ProvenanceRange covers{range_.NextAfter(), text.size()};229 CHECK(range_.AnnexIfPredecessor(covers));230 CHECK(origin_.back().covers.ImmediatelyPrecedes(covers));231 origin_.emplace_back(covers, text);232 return covers;233}234 235static void EmitPrefix(llvm::raw_ostream &o, llvm::raw_ostream::Colors color,236 const std::string &prefix, bool showColors) {237 if (prefix.empty()) {238 return;239 }240 if (showColors) {241 o.changeColor(color, true);242 }243 o << prefix;244 if (showColors) {245 o.resetColor();246 }247}248 249std::optional<ProvenanceRange> AllSources::GetInclusionInfo(250 const std::optional<ProvenanceRange> &range) const {251 if (!range || !IsValid(range->start()))252 return std::nullopt;253 const Origin &origin{MapToOrigin(range->start())};254 255 return common::visit(256 common::visitors{257 [&](const Inclusion &inc) -> std::optional<ProvenanceRange> {258 if (IsValid(origin.replaces) &&259 range_.Contains(origin.replaces.start()))260 return origin.replaces;261 return std::nullopt;262 },263 [&](const auto &) -> std::optional<ProvenanceRange> {264 return std::nullopt;265 },266 },267 origin.u);268}269 270void AllSources::EmitMessage(llvm::raw_ostream &o,271 const std::optional<ProvenanceRange> &range, const std::string &message,272 const std::string &prefix, llvm::raw_ostream::Colors color,273 bool echoSourceLine) const {274 if (!range) {275 EmitPrefix(o, color, prefix, this->getShowColors());276 o << message << '\n';277 return;278 }279 CHECK(IsValid(*range));280 const Origin &origin{MapToOrigin(range->start())};281 common::visit(282 common::visitors{283 [&](const Inclusion &inc) {284 std::size_t offset{origin.covers.MemberOffset(range->start())};285 SourcePosition pos{inc.source.GetSourcePosition(offset)};286 o << pos.path << ':' << pos.line << ':' << pos.column << ": ";287 EmitPrefix(o, color, prefix, this->getShowColors());288 o << message << '\n';289 if (echoSourceLine) {290 const char *text{inc.source.content().data() +291 inc.source.GetLineStartOffset(pos.trueLineNumber)};292 o << " ";293 for (const char *p{text}; *p != '\n'; ++p) {294 o << *p;295 }296 o << "\n ";297 for (int j{1}; j < pos.column; ++j) {298 char ch{text[j - 1]};299 o << (ch == '\t' ? '\t' : ' ');300 }301 o << '^';302 if (range->size() > 1) {303 auto last{range->start() + range->size() - 1};304 if (&MapToOrigin(last) == &origin) {305 auto endOffset{origin.covers.MemberOffset(last)};306 auto endPos{inc.source.GetSourcePosition(endOffset)};307 if (pos.line == endPos.line) {308 for (int j{pos.column}; j < endPos.column; ++j) {309 o << '^';310 }311 }312 }313 }314 o << '\n';315 }316 if (IsValid(origin.replaces)) {317 EmitMessage(o, origin.replaces,318 inc.isModule ? "used here"s : "included here"s, prefix, color,319 echoSourceLine);320 }321 },322 [&](const Macro &mac) {323 EmitMessage(324 o, origin.replaces, message, prefix, color, echoSourceLine);325 EmitMessage(o, mac.definition, "in a macro defined here", ""s,326 color, echoSourceLine);327 if (echoSourceLine) {328 o << "that expanded to:\n " << mac.expansion << "\n ";329 for (std::size_t j{0};330 origin.covers.OffsetMember(j) < range->start(); ++j) {331 o << (mac.expansion[j] == '\t' ? '\t' : ' ');332 }333 o << "^\n";334 }335 },336 [&](const CompilerInsertion &) {337 EmitPrefix(o, color, prefix, this->getShowColors());338 o << message << '\n';339 },340 },341 origin.u);342}343 344const SourceFile *AllSources::GetSourceFile(345 Provenance at, std::size_t *offset, bool topLevel) const {346 const Origin &origin{MapToOrigin(at)};347 return common::visit(common::visitors{348 [&](const Inclusion &inc) {349 if (topLevel && !origin.replaces.empty()) {350 return GetSourceFile(351 origin.replaces.start(), offset, topLevel);352 } else {353 if (offset) {354 *offset = origin.covers.MemberOffset(at);355 }356 return &inc.source;357 }358 },359 [&](const Macro &) {360 return GetSourceFile(361 origin.replaces.start(), offset);362 },363 [offset](const CompilerInsertion &) {364 if (offset) {365 *offset = 0;366 }367 return static_cast<const SourceFile *>(nullptr);368 },369 },370 origin.u);371}372 373const char *AllSources::GetSource(ProvenanceRange range) const {374 Provenance start{range.start()};375 const Origin &origin{MapToOrigin(start)};376 return origin.covers.Contains(range)377 ? &origin[origin.covers.MemberOffset(start)]378 : nullptr;379}380 381std::optional<SourcePosition> AllSources::GetSourcePosition(382 Provenance prov) const {383 const Origin &origin{MapToOrigin(prov)};384 return common::visit(385 common::visitors{386 [&](const Inclusion &inc) -> std::optional<SourcePosition> {387 std::size_t offset{origin.covers.MemberOffset(prov)};388 return inc.source.GetSourcePosition(offset);389 },390 [&](const Macro &) {391 return GetSourcePosition(origin.replaces.start());392 },393 [](const CompilerInsertion &) -> std::optional<SourcePosition> {394 return std::nullopt;395 },396 },397 origin.u);398}399 400std::optional<ProvenanceRange> AllSources::GetFirstFileProvenance() const {401 for (const auto &origin : origin_) {402 if (std::holds_alternative<Inclusion>(origin.u)) {403 return origin.covers;404 }405 }406 return std::nullopt;407}408 409std::string AllSources::GetPath(Provenance at, bool topLevel) const {410 std::size_t offset{0};411 const SourceFile *source{GetSourceFile(at, &offset, topLevel)};412 return source ? *source->GetSourcePosition(offset).path : ""s;413}414 415int AllSources::GetLineNumber(Provenance at) const {416 std::size_t offset{0};417 const SourceFile *source{GetSourceFile(at, &offset)};418 return source ? source->GetSourcePosition(offset).line : 0;419}420 421Provenance AllSources::CompilerInsertionProvenance(char ch) {422 auto iter{compilerInsertionProvenance_.find(ch)};423 if (iter != compilerInsertionProvenance_.end()) {424 return iter->second;425 }426 ProvenanceRange newCharRange{AddCompilerInsertion(std::string{ch})};427 Provenance newCharProvenance{newCharRange.start()};428 compilerInsertionProvenance_.insert(std::make_pair(ch, newCharProvenance));429 return newCharProvenance;430}431 432ProvenanceRange AllSources::IntersectionWithSourceFiles(433 ProvenanceRange range) const {434 if (range.empty()) {435 return {};436 } else {437 const Origin &origin{MapToOrigin(range.start())};438 if (std::holds_alternative<Inclusion>(origin.u)) {439 return range.Intersection(origin.covers);440 } else {441 auto skip{442 origin.covers.size() - origin.covers.MemberOffset(range.start())};443 return IntersectionWithSourceFiles(range.Suffix(skip));444 }445 }446}447 448AllSources::Origin::Origin(ProvenanceRange r, const SourceFile &source)449 : u{Inclusion{source}}, covers{r} {}450AllSources::Origin::Origin(ProvenanceRange r, const SourceFile &included,451 ProvenanceRange from, bool isModule)452 : u{Inclusion{included, isModule}}, covers{r}, replaces{from} {}453AllSources::Origin::Origin(ProvenanceRange r, ProvenanceRange def,454 ProvenanceRange use, const std::string &expansion)455 : u{Macro{def, expansion}}, covers{r}, replaces{use} {}456AllSources::Origin::Origin(ProvenanceRange r, const std::string &text)457 : u{CompilerInsertion{text}}, covers{r} {}458 459const char &AllSources::Origin::operator[](std::size_t n) const {460 return common::visit(461 common::visitors{462 [n](const Inclusion &inc) -> const char & {463 return inc.source.content()[n];464 },465 [n](const Macro &mac) -> const char & { return mac.expansion[n]; },466 [n](const CompilerInsertion &ins) -> const char & {467 return ins.text[n];468 },469 },470 u);471}472 473const AllSources::Origin &AllSources::MapToOrigin(Provenance at) const {474 CHECK(range_.Contains(at));475 std::size_t low{0}, count{origin_.size()};476 while (count > 1) {477 std::size_t mid{low + (count >> 1)};478 if (at < origin_[mid].covers.start()) {479 count = mid - low;480 } else {481 count -= mid - low;482 low = mid;483 }484 }485 CHECK(origin_[low].covers.Contains(at));486 return origin_[low];487}488 489Provenance AllSources::GetReplacedProvenance(Provenance provenance) const {490 const Origin &origin{MapToOrigin(provenance)};491 if (std::holds_alternative<Macro>(origin.u)) {492 return origin.replaces.start();493 }494 return provenance;495}496 497std::optional<ProvenanceRange> CookedSource::GetProvenanceRange(498 CharBlock cookedRange) const {499 if (!AsCharBlock().Contains(cookedRange)) {500 return std::nullopt;501 }502 ProvenanceRange first{provenanceMap_.Map(cookedRange.begin() - &data_[0])};503 if (cookedRange.size() <= first.size()) { // always true when empty504 return first.Prefix(cookedRange.size());505 }506 ProvenanceRange last{provenanceMap_.Map(cookedRange.end() - 1 - &data_[0])};507 if (first.start() <= last.start()) {508 return {ProvenanceRange{first.start(), last.start() - first.start() + 1}};509 } else {510 // cookedRange may start (resp. end) in a macro expansion while it does not511 // end (resp. start) in this macro expansion. Attempt to build a range512 // over the replaced source.513 Provenance firstStart{allSources_.GetReplacedProvenance(first.start())};514 Provenance lastStart{allSources_.GetReplacedProvenance(last.start())};515 if (firstStart <= lastStart) {516 return {ProvenanceRange{firstStart, lastStart - firstStart + 1}};517 } else {518 return std::nullopt;519 }520 }521}522 523std::optional<CharBlock> CookedSource::GetCharBlock(524 ProvenanceRange range) const {525 CHECK(!invertedMap_.empty() &&526 "CompileProvenanceRangeToOffsetMappings not called");527 if (auto to{invertedMap_.Map(range)}) {528 return CharBlock{data_.c_str() + *to, range.size()};529 } else {530 return std::nullopt;531 }532}533 534std::size_t CookedSource::BufferedBytes() const { return buffer_.bytes(); }535 536void CookedSource::Marshal(AllCookedSources &allCookedSources) {537 CHECK(provenanceMap_.SizeInBytes() == buffer_.bytes());538 provenanceMap_.Put(allCookedSources.allSources().AddCompilerInsertion(539 "(after end of source)"));540 data_ = buffer_.Marshal();541 buffer_.clear();542 for (std::size_t ffStart : possibleFixedFormContinuations_) {543 if (ffStart > 0 && ffStart + 1 < data_.size() &&544 data_[ffStart - 1] == '\n' && data_[ffStart] == ' ') {545 // This fixed form include line is the first source line in an546 // #include file (or after an empty one). Connect it with the previous547 // source line by deleting its terminal newline.548 data_[ffStart - 1] = ' ';549 }550 }551 possibleFixedFormContinuations_.clear();552 allCookedSources.Register(*this);553}554 555void CookedSource::CompileProvenanceRangeToOffsetMappings(556 AllSources &allSources) {557 if (invertedMap_.empty()) {558 invertedMap_ = provenanceMap_.Invert(allSources);559 }560}561 562static void DumpRange(llvm::raw_ostream &o, const ProvenanceRange &r) {563 o << "[" << r.start().offset() << ".." << r.Last().offset() << "] ("564 << r.size() << " bytes)";565}566 567llvm::raw_ostream &ProvenanceRangeToOffsetMappings::Dump(568 llvm::raw_ostream &o) const {569 for (const auto &m : map_) {570 o << "provenances ";571 DumpRange(o, m.first);572 o << " -> offsets [" << m.second << ".." << (m.second + m.first.size() - 1)573 << "]\n";574 }575 return o;576}577 578llvm::raw_ostream &OffsetToProvenanceMappings::Dump(579 llvm::raw_ostream &o) const {580 for (const ContiguousProvenanceMapping &m : provenanceMap_) {581 std::size_t n{m.range.size()};582 o << "offsets [" << m.start << ".." << (m.start + n - 1)583 << "] -> provenances ";584 DumpRange(o, m.range);585 o << '\n';586 }587 return o;588}589 590llvm::raw_ostream &AllSources::Dump(llvm::raw_ostream &o) const {591 o << "AllSources range_ ";592 DumpRange(o, range_);593 o << '\n';594 std::set<const SourceFile *> sources;595 for (const Origin &m : origin_) {596 o << " ";597 DumpRange(o, m.covers);598 o << " -> ";599 common::visit(common::visitors{600 [&](const Inclusion &inc) {601 if (inc.isModule) {602 o << "module ";603 }604 o << "file " << inc.source.path();605 sources.emplace(&inc.source);606 },607 [&](const Macro &mac) { o << "macro " << mac.expansion; },608 [&](const CompilerInsertion &ins) {609 o << "compiler '" << ins.text << '\'';610 if (ins.text.length() == 1) {611 int ch = ins.text[0];612 o << "(0x";613 o.write_hex(ch & 0xff) << ")";614 }615 },616 },617 m.u);618 if (IsValid(m.replaces)) {619 o << " replaces ";620 DumpRange(o, m.replaces);621 }622 o << '\n';623 }624 for (const SourceFile *sf : sources) {625 sf->Dump(o);626 }627 return o;628}629 630llvm::raw_ostream &CookedSource::Dump(llvm::raw_ostream &o) const {631 o << "CookedSource::provenanceMap_:\n";632 provenanceMap_.Dump(o);633 o << "CookedSource::invertedMap_:\n";634 invertedMap_.Dump(o);635 return o;636}637 638AllCookedSources::AllCookedSources(AllSources &s) : allSources_{s} {}639AllCookedSources::~AllCookedSources() {}640 641CookedSource &AllCookedSources::NewCookedSource() {642 return cooked_.emplace_back(allSources_);643}644 645const CookedSource *AllCookedSources::Find(CharBlock x) const {646 auto pair{index_.equal_range(x)};647 for (auto iter{pair.first}; iter != pair.second; ++iter) {648 if (iter->second.AsCharBlock().Contains(x)) {649 return &iter->second;650 }651 }652 return nullptr;653}654 655std::optional<ProvenanceRange> AllCookedSources::GetProvenanceRange(656 CharBlock cb) const {657 if (const CookedSource * c{Find(cb)}) {658 return c->GetProvenanceRange(cb);659 } else {660 return std::nullopt;661 }662}663 664std::optional<CharBlock> AllCookedSources::GetCharBlockFromLineAndColumns(665 int line, int startColumn, int endColumn) const {666 // 2nd column is exclusive, meaning it is target column + 1.667 CHECK(line > 0 && startColumn > 0 && endColumn > 0);668 CHECK(startColumn < endColumn);669 auto provenanceStart{allSources_.GetFirstFileProvenance().value().start()};670 if (auto sourceFile{allSources_.GetSourceFile(provenanceStart)}) {671 CHECK(line <= static_cast<int>(sourceFile->lines()));672 return GetCharBlock(ProvenanceRange(sourceFile->GetLineStartOffset(line) +673 provenanceStart.offset() + startColumn - 1,674 endColumn - startColumn));675 }676 return std::nullopt;677}678 679std::optional<std::pair<SourcePosition, SourcePosition>>680AllCookedSources::GetSourcePositionRange(CharBlock cookedRange) const {681 if (auto range{GetProvenanceRange(cookedRange)}) {682 if (auto firstOffset{allSources_.GetSourcePosition(range->start())}) {683 if (auto secondOffset{684 allSources_.GetSourcePosition(range->start() + range->size())}) {685 return std::pair{*firstOffset, *secondOffset};686 }687 }688 }689 return std::nullopt;690}691 692std::optional<CharBlock> AllCookedSources::GetCharBlock(693 ProvenanceRange range) const {694 for (const auto &c : cooked_) {695 if (auto result{c.GetCharBlock(range)}) {696 return result;697 }698 }699 return std::nullopt;700}701 702void AllCookedSources::Dump(llvm::raw_ostream &o) const {703 o << "AllSources:\n";704 allSources_.Dump(o);705 for (const auto &c : cooked_) {706 c.Dump(o);707 }708}709 710bool AllCookedSources::Precedes(CharBlock x, CharBlock y) const {711 if (const CookedSource * xSource{Find(x)}) {712 if (xSource->AsCharBlock().Contains(y)) {713 return x.begin() < y.begin();714 } else if (const CookedSource * ySource{Find(y)}) {715 return xSource->number() < ySource->number();716 } else {717 return true; // by fiat, all cooked source < anything outside718 }719 } else if (Find(y)) {720 return false;721 } else {722 // Both names are compiler-created (SaveTempName).723 return x < y;724 }725}726 727void AllCookedSources::Register(CookedSource &cooked) {728 index_.emplace(cooked.AsCharBlock(), cooked);729 cooked.set_number(static_cast<int>(index_.size()));730}731 732} // namespace Fortran::parser733