[flang] Order Symbols by source provenance

In parser::AllCookedSources, implement a map from CharBlocks to
the CookedSource instances that they cover.  This permits a fast
Find() operation based on std::map::equal_range to map a CharBlock
to its enclosing CookedSource instance.

Add a creation order number to each CookedSource.  This allows
AllCookedSources to provide a Precedes(x,y) predicate that is a
true source stream ordering between two CharBlocks -- x is less
than y if it is in an earlier CookedSource, or in the same
CookedSource at an earlier position.

Add a reference to the singleton SemanticsContext to each Scope.

All of this allows operator< to be implemented on Symbols by
means of a true source ordering.  From a Symbol, we get to
its Scope, then to the SemanticsContext, and then use its
AllCookedSources reference to call Precedes().

Differential Revision: https://reviews.llvm.org/D98743

GitOrigin-RevId: 46ade6d0ef8fea94fbc28c75bb4bed4d928fd64b
diff --git a/include/flang/Parser/char-block.h b/include/flang/Parser/char-block.h
index 7c29c9a..0f5758f 100644
--- a/include/flang/Parser/char-block.h
+++ b/include/flang/Parser/char-block.h
@@ -138,6 +138,13 @@
   return right < left;
 }
 
+// An alternative comparator based on pointer values; use with care!
+struct CharBlockPointerComparator {
+  bool operator()(CharBlock x, CharBlock y) const {
+    return x.end() < y.begin();
+  }
+};
+
 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const CharBlock &x);
 
 } // namespace Fortran::parser
diff --git a/include/flang/Parser/provenance.h b/include/flang/Parser/provenance.h
index bce7980..56b78a2 100644
--- a/include/flang/Parser/provenance.h
+++ b/include/flang/Parser/provenance.h
@@ -47,6 +47,7 @@
 // necessary.)
 
 class AllSources;
+class AllCookedSources;
 
 class Provenance {
 public:
@@ -219,6 +220,9 @@
 // single instances of CookedSource.
 class CookedSource {
 public:
+  int number() const { return number_; }
+  void set_number(int n) { number_ = n; }
+
   CharBlock AsCharBlock() const { return CharBlock{data_}; }
   std::optional<ProvenanceRange> GetProvenanceRange(CharBlock) const;
   std::optional<CharBlock> GetCharBlock(ProvenanceRange) const;
@@ -242,11 +246,12 @@
   }
 
   std::size_t BufferedBytes() const;
-  void Marshal(AllSources &); // marshals text into one contiguous block
+  void Marshal(AllCookedSources &); // marshals text into one contiguous block
   void CompileProvenanceRangeToOffsetMappings(AllSources &);
   llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
 
 private:
+  int number_{0}; // for sorting purposes
   CharBuffer buffer_; // before Marshal()
   std::string data_; // all of it, prescanned and preprocessed
   OffsetToProvenanceMappings provenanceMap_;
@@ -263,15 +268,8 @@
 
   CookedSource &NewCookedSource();
 
-  template <typename A> // const char * or CharBlock
-  const CookedSource *Find(A x) const {
-    for (const auto &c : cooked_) {
-      if (c.AsCharBlock().Contains(x)) {
-        return &c;
-      }
-    }
-    return nullptr;
-  }
+  const CookedSource *Find(CharBlock) const;
+  const CookedSource *Find(const char *p) const { return Find(CharBlock{p}); }
 
   bool IsValid(ProvenanceRange r) const { return allSources_.IsValid(r); }
 
@@ -283,9 +281,30 @@
   std::optional<CharBlock> GetCharBlock(ProvenanceRange) const;
   void Dump(llvm::raw_ostream &) const;
 
+  // For sorting symbol names without being dependent on pointer values
+  bool Precedes(CharBlock, CharBlock) const;
+
+  // Once a CookedSource is complete, add it to index_ and assign its number_
+  void Register(CookedSource &);
+
 private:
   AllSources &allSources_;
   std::list<CookedSource> cooked_; // owns all CookedSource instances
+  int counter_{0};
+  std::map<CharBlock, const CookedSource &, CharBlockPointerComparator> index_;
 };
+
+// For use as a Comparator for maps, sets, sorting, &c.
+class CharBlockComparator {
+public:
+  explicit CharBlockComparator(const AllCookedSources &all) : all_{all} {}
+  bool operator()(CharBlock x, CharBlock y) const {
+    return all_.Precedes(x, y);
+  }
+
+private:
+  const AllCookedSources &all_;
+};
+
 } // namespace Fortran::parser
 #endif // FORTRAN_PARSER_PROVENANCE_H_
diff --git a/include/flang/Semantics/scope.h b/include/flang/Semantics/scope.h
index 81840bd..f1d5b0c 100644
--- a/include/flang/Semantics/scope.h
+++ b/include/flang/Semantics/scope.h
@@ -62,9 +62,10 @@
   using ImportKind = common::ImportKind;
 
   // Create the Global scope -- the root of the scope tree
-  Scope() : Scope{*this, Kind::Global, nullptr} {}
-  Scope(Scope &parent, Kind kind, Symbol *symbol)
-      : parent_{parent}, kind_{kind}, symbol_{symbol} {
+  explicit Scope(SemanticsContext &context)
+      : Scope{*this, Kind::Global, nullptr, context} {}
+  Scope(Scope &parent, Kind kind, Symbol *symbol, SemanticsContext &context)
+      : parent_{parent}, kind_{kind}, symbol_{symbol}, context_{context} {
     if (symbol) {
       symbol->set_scope(this);
     }
@@ -99,6 +100,7 @@
   }
   Symbol *symbol() { return symbol_; }
   const Symbol *symbol() const { return symbol_; }
+  SemanticsContext &context() const { return context_; }
 
   inline const Symbol *GetSymbol() const;
   const Scope *GetDerivedTypeParent() const;
@@ -107,6 +109,9 @@
   bool Contains(const Scope &) const;
   /// Make a scope nested in this one
   Scope &MakeScope(Kind kind, Symbol *symbol = nullptr);
+  SemanticsContext &GetMutableSemanticsContext() const {
+    return const_cast<SemanticsContext &>(context());
+  }
 
   using size_type = mapType::size_type;
   using iterator = mapType::iterator;
@@ -244,7 +249,7 @@
         symbol_->test(Symbol::Flag::ModFile);
   }
 
-  void InstantiateDerivedTypes(SemanticsContext &);
+  void InstantiateDerivedTypes();
 
   const Symbol *runtimeDerivedTypeDescription() const {
     return runtimeDerivedTypeDescription_;
@@ -273,8 +278,9 @@
   parser::Message::Reference instantiationContext_;
   bool hasSAVE_{false}; // scope has a bare SAVE statement
   const Symbol *runtimeDerivedTypeDescription_{nullptr};
+  SemanticsContext &context_;
   // When additional data members are added to Scope, remember to
-  // copy them, if appropriate, in InstantiateDerivedType().
+  // copy them, if appropriate, in FindOrInstantiateDerivedType().
 
   // Storage for all Symbols. Every Symbol is in allSymbols and every Symbol*
   // or Symbol& points to one in there.
diff --git a/include/flang/Semantics/symbol.h b/include/flang/Semantics/symbol.h
index fb53c61..957bffd 100644
--- a/include/flang/Semantics/symbol.h
+++ b/include/flang/Semantics/symbol.h
@@ -18,7 +18,7 @@
 #include <functional>
 #include <list>
 #include <optional>
-#include <unordered_set>
+#include <set>
 #include <vector>
 
 namespace llvm {
@@ -595,10 +595,13 @@
 
   bool operator==(const Symbol &that) const { return this == &that; }
   bool operator!=(const Symbol &that) const { return !(*this == that); }
-  bool operator<(const Symbol &that) const {
-    // Used to collate symbols by creation order
-    return sortIndex_ < that.sortIndex_;
-  }
+
+  // Symbol comparison is based on the order of cooked source
+  // stream creation and, when both are from the same cooked source,
+  // their positions in that cooked source stream.
+  // (This function is implemented in Evaluate/tools.cpp to
+  // satisfy complicated shared library interdependency.)
+  bool operator<(const Symbol &) const;
 
   int Rank() const {
     return std::visit(
@@ -651,10 +654,11 @@
   // for a parameterized derived type instantiation with the instance's scope.
   const DerivedTypeSpec *GetParentTypeSpec(const Scope * = nullptr) const;
 
+  SemanticsContext &GetSemanticsContext() const;
+
 private:
   const Scope *owner_;
   SourceName name_;
-  std::size_t sortIndex_; // to implement "operator<" platform independently
   Attrs attrs_;
   Flags flags_;
   Scope *scope_{nullptr};
@@ -689,7 +693,6 @@
     Symbol &symbol = Get();
     symbol.owner_ = &owner;
     symbol.name_ = name;
-    symbol.sortIndex_ = ++symbolCount_;
     symbol.attrs_ = attrs;
     symbol.details_ = std::move(details);
     return symbol;
@@ -700,7 +703,6 @@
   std::list<blockType *> blocks_;
   std::size_t nextIndex_{0};
   blockType *currBlock_{nullptr};
-  static inline std::size_t symbolCount_ = 0;
 
   Symbol &Get() {
     if (nextIndex_ == 0) {
@@ -765,17 +767,13 @@
       details_);
 }
 
-inline bool operator<(SymbolRef x, SymbolRef y) { return *x < *y; }
-inline bool operator<(MutableSymbolRef x, MutableSymbolRef y) {
-  return *x < *y;
+inline bool operator<(SymbolRef x, SymbolRef y) {
+  return *x < *y; // name source position ordering
 }
-struct SymbolHash {
-  std::size_t operator()(SymbolRef symRef) const {
-    std::hash<std::string> hasher;
-    return hasher(symRef->name().ToString());
-  }
-};
-using SymbolSet = std::unordered_set<SymbolRef, SymbolHash>;
+inline bool operator<(MutableSymbolRef x, MutableSymbolRef y) {
+  return *x < *y; // name source position ordering
+}
+using SymbolSet = std::set<SymbolRef>;
 
 } // namespace Fortran::semantics
 
diff --git a/lib/Evaluate/tools.cpp b/lib/Evaluate/tools.cpp
index 0685f14..638b794 100644
--- a/lib/Evaluate/tools.cpp
+++ b/lib/Evaluate/tools.cpp
@@ -1203,4 +1203,16 @@
   return FindFunctionResult(symbol, seen);
 }
 
+// These are here in Evaluate/tools.cpp so that Evaluate can use
+// them; they cannot be defined in symbol.h due to the dependence
+// on Scope.
+
+bool Symbol::operator<(const Symbol &that) const {
+  return GetSemanticsContext().allCookedSources().Precedes(name_, that.name_);
+}
+
+SemanticsContext &Symbol::GetSemanticsContext() const {
+  return DEREF(owner_).context();
+}
+
 } // namespace Fortran::semantics
diff --git a/lib/Parser/parsing.cpp b/lib/Parser/parsing.cpp
index 81097b2..0afa2a9 100644
--- a/lib/Parser/parsing.cpp
+++ b/lib/Parser/parsing.cpp
@@ -88,7 +88,7 @@
     // message about nonstandard usage will have provenance.
     currentCooked_->Put('\n', range.start());
   }
-  currentCooked_->Marshal(allSources);
+  currentCooked_->Marshal(allCooked_);
   if (options.needProvenanceRangeToCharBlockMappings) {
     currentCooked_->CompileProvenanceRangeToOffsetMappings(allSources);
   }
diff --git a/lib/Parser/provenance.cpp b/lib/Parser/provenance.cpp
index 14124a5..79cb286 100644
--- a/lib/Parser/provenance.cpp
+++ b/lib/Parser/provenance.cpp
@@ -442,11 +442,13 @@
 
 std::size_t CookedSource::BufferedBytes() const { return buffer_.bytes(); }
 
-void CookedSource::Marshal(AllSources &allSources) {
+void CookedSource::Marshal(AllCookedSources &allCookedSources) {
   CHECK(provenanceMap_.SizeInBytes() == buffer_.bytes());
-  provenanceMap_.Put(allSources.AddCompilerInsertion("(after end of source)"));
+  provenanceMap_.Put(allCookedSources.allSources().AddCompilerInsertion(
+      "(after end of source)"));
   data_ = buffer_.Marshal();
   buffer_.clear();
+  allCookedSources.Register(*this);
 }
 
 void CookedSource::CompileProvenanceRangeToOffsetMappings(
@@ -534,6 +536,16 @@
   return cooked_.emplace_back();
 }
 
+const CookedSource *AllCookedSources::Find(CharBlock x) const {
+  auto pair{index_.equal_range(x)};
+  for (auto iter{pair.first}; iter != pair.second; ++iter) {
+    if (iter->second.AsCharBlock().Contains(x)) {
+      return &iter->second;
+    }
+  }
+  return nullptr;
+}
+
 std::optional<ProvenanceRange> AllCookedSources::GetProvenanceRange(
     CharBlock cb) const {
   if (const CookedSource * c{Find(cb)}) {
@@ -589,4 +601,27 @@
   }
 }
 
+bool AllCookedSources::Precedes(CharBlock x, CharBlock y) const {
+  const CookedSource *ySource{Find(y)};
+  if (const CookedSource * xSource{Find(x)}) {
+    if (ySource) {
+      int xNum{xSource->number()};
+      int yNum{ySource->number()};
+      return xNum < yNum || (xNum == yNum && x.begin() < y.begin());
+    } else {
+      return true; // by fiat, all cooked source < anything outside
+    }
+  } else if (ySource) {
+    return false;
+  } else {
+    // Both names are compiler-created (SaveTempName).
+    return x < y;
+  }
+}
+
+void AllCookedSources::Register(CookedSource &cooked) {
+  index_.emplace(cooked.AsCharBlock(), cooked);
+  cooked.set_number(static_cast<int>(index_.size()));
+}
+
 } // namespace Fortran::parser
diff --git a/lib/Semantics/check-io.cpp b/lib/Semantics/check-io.cpp
index c6b67a5..897b7fd 100644
--- a/lib/Semantics/check-io.cpp
+++ b/lib/Semantics/check-io.cpp
@@ -930,7 +930,8 @@
   if (const auto *var{parser::Unwrap<parser::Variable>(variable)}) {
     if (auto expr{AnalyzeExpr(context_, *var)}) {
       auto at{var->GetSource()};
-      if (auto whyNot{WhyNotModifiable(at, *expr, context_.FindScope(at))}) {
+      if (auto whyNot{WhyNotModifiable(at, *expr, context_.FindScope(at),
+              true /*vectorSubscriptIsOk*/)}) {
         const Symbol *base{GetFirstSymbol(*expr)};
         context_
             .Say(at, "%s variable '%s' must be definable"_err_en_US, s,
diff --git a/lib/Semantics/resolve-names.cpp b/lib/Semantics/resolve-names.cpp
index df358d8..813debb 100644
--- a/lib/Semantics/resolve-names.cpp
+++ b/lib/Semantics/resolve-names.cpp
@@ -6393,7 +6393,7 @@
       CheckPossibleBadForwardRef(symbol);
     }
   }
-  currScope().InstantiateDerivedTypes(context());
+  currScope().InstantiateDerivedTypes();
   for (const auto &decl : decls) {
     if (const auto *statement{std::get_if<
             parser::Statement<common::Indirection<parser::StmtFunctionStmt>>>(
diff --git a/lib/Semantics/scope.cpp b/lib/Semantics/scope.cpp
index 597f554..2e2b8f7 100644
--- a/lib/Semantics/scope.cpp
+++ b/lib/Semantics/scope.cpp
@@ -50,7 +50,7 @@
 }
 
 Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {
-  return children_.emplace_back(*this, kind, symbol);
+  return children_.emplace_back(*this, kind, symbol, context_);
 }
 
 template <typename T>
@@ -404,11 +404,11 @@
   return *child;
 }
 
-void Scope::InstantiateDerivedTypes(SemanticsContext &context) {
+void Scope::InstantiateDerivedTypes() {
   for (DeclTypeSpec &type : declTypeSpecs_) {
     if (type.category() == DeclTypeSpec::TypeDerived ||
         type.category() == DeclTypeSpec::ClassDerived) {
-      type.derivedTypeSpec().Instantiate(*this, context);
+      type.derivedTypeSpec().Instantiate(*this, context_);
     }
   }
 }
diff --git a/lib/Semantics/semantics.cpp b/lib/Semantics/semantics.cpp
index f299897..24bc5e3 100644
--- a/lib/Semantics/semantics.cpp
+++ b/lib/Semantics/semantics.cpp
@@ -185,8 +185,9 @@
     : defaultKinds_{defaultKinds}, languageFeatures_{languageFeatures},
       allCookedSources_{allCookedSources},
       intrinsics_{evaluate::IntrinsicProcTable::Configure(defaultKinds_)},
-      foldingContext_{
-          parser::ContextualMessages{&messages_}, defaultKinds_, intrinsics_} {}
+      globalScope_{*this}, foldingContext_{
+                               parser::ContextualMessages{&messages_},
+                               defaultKinds_, intrinsics_} {}
 
 SemanticsContext::~SemanticsContext() {}
 
diff --git a/test/Semantics/data05.f90 b/test/Semantics/data05.f90
index ff4d068..8e059c2 100644
--- a/test/Semantics/data05.f90
+++ b/test/Semantics/data05.f90
@@ -73,15 +73,15 @@
   end function
   subroutine s11
     real, target, save :: arr(3,4) ! CHECK: arr, SAVE, TARGET size=48 offset=0: ObjectEntity type: REAL(4) shape: 1_8:3_8,1_8:4_8
-    type(t1) :: d1 = t1(1,reshape([1,2,3,4],[2,2]),(6.,7.),.false.,'ab',arr,ifunc2,rfunc,extrfunc) ! CHECK: d1 size=192 offset=48: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(c=[CHARACTER(KIND=1,LEN=1)::"a","a"],ifptr=ifunc2,j=1_4,rp=rfunc,t=.false._4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),xp=arr,xrp=extrfunc,z=(6._4,7._4))
+    type(t1) :: d1 = t1(1,reshape([1,2,3,4],[2,2]),(6.,7.),.false.,'ab',arr,ifunc2,rfunc,extrfunc) ! CHECK: d1 size=184 offset=48: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc)
     type(t1(4,len=1)) :: d2 = t1(4)(xrp=extrfunc,rp=rfunc,ifptr=ifunc2,xp=arr,c='a&
-      &b',t=.false.,z=(6.,7.),x=reshape([1,2,3,4],[2,2]),j=1) ! CHECK: d2 size=192 offset=240: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(c=[CHARACTER(KIND=1,LEN=1)::"a","a"],ifptr=ifunc2,j=1_4,rp=rfunc,t=.false._4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),xp=arr,xrp=extrfunc,z=(6._4,7._4))
-    type(t1(2+2)) :: d3 ! CHECK: d3 (InDataStmt) size=192 offset=432: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(c=[CHARACTER(KIND=1,LEN=1)::"a","a"],ifptr=ifunc2,j=1_4,rp=rfunc,t=.false._4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),xp=arr,xrp=extrfunc,z=(6._4,7._4))
+      &b',t=.false.,z=(6.,7.),x=reshape([1,2,3,4],[2,2]),j=1) ! CHECK: d2 size=184 offset=232: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc)
+    type(t1(2+2)) :: d3 ! CHECK: d3 (InDataStmt) size=184 offset=416: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc)
     data d3/t1(1,reshape([1,2,3,4],[2,2]),(6.,7.),.false.,'ab',arr,ifunc2,rfunc,extrfunc)/
-    type(t1) :: d4 ! CHECK: d4 (InDataStmt) size=192 offset=624: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(c=[CHARACTER(KIND=1,LEN=1)::"a","a"],ifptr=ifunc2,j=1_4,rp=rfunc,t=.false._4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),xp=arr,xrp=extrfunc,z=(6._4,7._4))
+    type(t1) :: d4 ! CHECK: d4 (InDataStmt) size=184 offset=600: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","a"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc)
     data d4/t1(4)(xrp=extrfunc,rp=rfunc,ifptr=ifunc2,xp=arr,c='ab',t=.false.,z=(6&
       &.,7.),x=reshape([1,2,3,4],[2,2]),j=1)/
-    type(t1) :: d5 ! CHECK: d5 (InDataStmt) size=192 offset=816: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(c=[CHARACTER(KIND=1,LEN=1)::"a","b"],ifptr=ifunc2,j=1_4,rp=rfunc,t=.false._4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),xp=arr,xrp=extrfunc,z=(6._4,7._4))
+    type(t1) :: d5 ! CHECK: d5 (InDataStmt) size=184 offset=784: ObjectEntity type: TYPE(t1(kind=4_1,len=1_2)) init:t1(kind=4_1,len=1_2)(j=1_4,x=reshape([REAL(4)::1._4,2._4,3._4,4._4],shape=[2,2]),z=(6._4,7._4),t=.false._4,c=[CHARACTER(KIND=1,LEN=1)::"a","b"],xp=arr,ifptr=ifunc2,rp=rfunc,xrp=extrfunc)
     data d5%j/1/,d5%x/1,2,3,4/,d5%z%re/6./,d5%z%im/7./,d5%t/.false./,d5%c(1:1)/'a'/,d5%c(2:&
       &2)/'b'/,d5%xp/arr/,d5%ifptr/ifunc2/,d5%rp/rfunc/,d5%xrp/extrfunc/
   end subroutine
diff --git a/test/Semantics/modfile21.f90 b/test/Semantics/modfile21.f90
index d7b45f7..e48f633 100644
--- a/test/Semantics/modfile21.f90
+++ b/test/Semantics/modfile21.f90
@@ -26,10 +26,10 @@
 !  real(4)::v
 !  complex(4)::w
 !  real(4)::cb
-!  common//t,w,u,v
 !  common/cb/x,y,z
 !  bind(c, name="CB")::/cb/
 !  common/cb2/a,b,c
 !  bind(c)::/cb2/
 !  common/b/cb
+!  common//t,w,u,v
 !end
diff --git a/test/Semantics/resolve102.f90 b/test/Semantics/resolve102.f90
index fec8314..4f900a1 100644
--- a/test/Semantics/resolve102.f90
+++ b/test/Semantics/resolve102.f90
@@ -9,7 +9,7 @@
 end subroutine
 
 subroutine circular
-  !ERROR: Procedure 'p' is recursively defined.  Procedures in the cycle: 'sub', 'p', 'p2'
+  !ERROR: Procedure 'p' is recursively defined.  Procedures in the cycle: 'p', 'sub', 'p2'
   procedure(sub) :: p
 
   call p(sub)
@@ -21,7 +21,7 @@
 end subroutine circular
 
 program iface
-  !ERROR: Procedure 'p' is recursively defined.  Procedures in the cycle: 'sub', 'p', 'p2'
+  !ERROR: Procedure 'p' is recursively defined.  Procedures in the cycle: 'p', 'sub', 'p2'
   procedure(sub) :: p
   interface
     subroutine sub(p2)
@@ -38,7 +38,7 @@
   Call p(sub)
 
   contains
-    !ERROR: Procedure 'sub1' is recursively defined.  Procedures in the cycle: 'sub1', 'p', 'arg'
+    !ERROR: Procedure 'sub1' is recursively defined.  Procedures in the cycle: 'p', 'sub1', 'arg'
     Subroutine sub1(arg)
       procedure(sub1) :: arg
     End Subroutine
@@ -54,7 +54,7 @@
   Call p(sub)
 
   contains
-    !ERROR: Procedure 'sub1' is recursively defined.  Procedures in the cycle: 'sub1', 'sub', 'p', 'arg', 'p2'
+    !ERROR: Procedure 'sub1' is recursively defined.  Procedures in the cycle: 'p', 'sub1', 'arg', 'sub', 'p2'
     Subroutine sub1(arg)
       procedure(sub) :: arg
     End Subroutine
@@ -68,6 +68,7 @@
   !ERROR: The interface for procedure 'p1' is recursively defined
   !ERROR: The interface for procedure 'p2' is recursively defined
   procedure(p1) p2
+  !ERROR: 'p2' must be an abstract interface or a procedure with an explicit interface
   procedure(p2) p1
   call p1
   call p2
@@ -75,8 +76,10 @@
 
 program threeCycle
   !ERROR: The interface for procedure 'p1' is recursively defined
+  !ERROR: 'p1' must be an abstract interface or a procedure with an explicit interface
   !ERROR: The interface for procedure 'p2' is recursively defined
   procedure(p1) p2
+  !ERROR: 'p2' must be an abstract interface or a procedure with an explicit interface
   !ERROR: The interface for procedure 'p3' is recursively defined
   procedure(p2) p3
   procedure(p3) p1
diff --git a/test/Semantics/typeinfo01.f90 b/test/Semantics/typeinfo01.f90
index 3e8b818..3575aca 100644
--- a/test/Semantics/typeinfo01.f90
+++ b/test/Semantics/typeinfo01.f90
@@ -231,7 +231,7 @@
   subroutine s1(x)
 !CHECK: .b.t.1.allocatable, SAVE, TARGET: ObjectEntity type: TYPE(value) shape: 0_8:1_8,0_8:0_8 init:reshape([value::value(genre=1_1,value=0_8),value(genre=1_1,value=0_8)],shape=[2,1])
 !CHECK: .b.t.1.automatic, SAVE, TARGET: ObjectEntity type: TYPE(value) shape: 0_8:1_8,0_8:0_8 init:reshape([value::value(genre=2_1,value=1_8),value(genre=3_1,value=0_8)],shape=[2,1])
-!CHECK: .c.t.1, SAVE, TARGET: ObjectEntity type: TYPE(component) shape: 0_8:3_8 init:[component::component(name=.n.allocatable,genre=3_1,category=1_1,kind=4_1,rank=1_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=.b.t.1.allocatable,initialization=NULL()),component(name=.n.automatic,genre=4_1,category=1_1,kind=4_1,rank=1_1,offset=48_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=.b.t.1.automatic,initialization=NULL()),component(name=.n.chauto,genre=4_1,category=3_1,kind=1_1,rank=0_1,offset=96_8,characterlen=value(genre=3_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.pointer,genre=2_1,category=1_1,kind=4_1,rank=0_1,offset=120_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=target)]
+!CHECK: .c.t.1, SAVE, TARGET: ObjectEntity type: TYPE(component) shape: 0_8:3_8 init:[component::component(name=.n.allocatable,genre=3_1,category=1_1,kind=4_1,rank=1_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=.b.t.1.allocatable,initialization=NULL()),component(name=.n.automatic,genre=4_1,category=1_1,kind=4_1,rank=1_1,offset=96_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=.b.t.1.automatic,initialization=NULL()),component(name=.n.chauto,genre=4_1,category=3_1,kind=1_1,rank=0_1,offset=72_8,characterlen=value(genre=3_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.pointer,genre=2_1,category=1_1,kind=4_1,rank=0_1,offset=48_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=target)]
 !CHECK: .dt.t.1, SAVE, TARGET: ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=144_8,parent=NULL(),uninstantiated=.dt.t,kindparameter=NULL(),lenparameterkind=.lpk.t.1,component=.c.t.1,procptr=NULL(),special=NULL())
 !CHECK: .lpk.t.1, SAVE, TARGET: ObjectEntity type: INTEGER(1) shape: 0_8:0_8 init:[INTEGER(1)::8_1]
     type(t(*)), intent(in) :: x
diff --git a/unittests/Evaluate/intrinsics.cpp b/unittests/Evaluate/intrinsics.cpp
index 52507b8..a36dbf5 100644
--- a/unittests/Evaluate/intrinsics.cpp
+++ b/unittests/Evaluate/intrinsics.cpp
@@ -24,7 +24,7 @@
     offsets_[s] = cooked_.Put(s);
     cooked_.PutProvenance(allSources_.AddCompilerInsertion(s));
   }
-  void Marshal() { cooked_.Marshal(allSources_); }
+  void Marshal() { cooked_.Marshal(allCookedSources_); }
   parser::CharBlock operator()(const std::string &s) {
     return {cooked_.AsCharBlock().begin() + offsets_[s], s.size()};
   }