Skip to content

Commit 46ade6d

Browse files
committed
[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
1 parent c2f3b2f commit 46ade6d

File tree

16 files changed

+136
-54
lines changed

16 files changed

+136
-54
lines changed

flang/include/flang/Parser/char-block.h

+7
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@ inline bool operator>(const char *left, const CharBlock &right) {
138138
return right < left;
139139
}
140140

141+
// An alternative comparator based on pointer values; use with care!
142+
struct CharBlockPointerComparator {
143+
bool operator()(CharBlock x, CharBlock y) const {
144+
return x.end() < y.begin();
145+
}
146+
};
147+
141148
llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const CharBlock &x);
142149

143150
} // namespace Fortran::parser

flang/include/flang/Parser/provenance.h

+29-10
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ namespace Fortran::parser {
4747
// necessary.)
4848

4949
class AllSources;
50+
class AllCookedSources;
5051

5152
class Provenance {
5253
public:
@@ -219,6 +220,9 @@ class AllSources {
219220
// single instances of CookedSource.
220221
class CookedSource {
221222
public:
223+
int number() const { return number_; }
224+
void set_number(int n) { number_ = n; }
225+
222226
CharBlock AsCharBlock() const { return CharBlock{data_}; }
223227
std::optional<ProvenanceRange> GetProvenanceRange(CharBlock) const;
224228
std::optional<CharBlock> GetCharBlock(ProvenanceRange) const;
@@ -242,11 +246,12 @@ class CookedSource {
242246
}
243247

244248
std::size_t BufferedBytes() const;
245-
void Marshal(AllSources &); // marshals text into one contiguous block
249+
void Marshal(AllCookedSources &); // marshals text into one contiguous block
246250
void CompileProvenanceRangeToOffsetMappings(AllSources &);
247251
llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
248252

249253
private:
254+
int number_{0}; // for sorting purposes
250255
CharBuffer buffer_; // before Marshal()
251256
std::string data_; // all of it, prescanned and preprocessed
252257
OffsetToProvenanceMappings provenanceMap_;
@@ -263,15 +268,8 @@ class AllCookedSources {
263268

264269
CookedSource &NewCookedSource();
265270

266-
template <typename A> // const char * or CharBlock
267-
const CookedSource *Find(A x) const {
268-
for (const auto &c : cooked_) {
269-
if (c.AsCharBlock().Contains(x)) {
270-
return &c;
271-
}
272-
}
273-
return nullptr;
274-
}
271+
const CookedSource *Find(CharBlock) const;
272+
const CookedSource *Find(const char *p) const { return Find(CharBlock{p}); }
275273

276274
bool IsValid(ProvenanceRange r) const { return allSources_.IsValid(r); }
277275

@@ -283,9 +281,30 @@ class AllCookedSources {
283281
std::optional<CharBlock> GetCharBlock(ProvenanceRange) const;
284282
void Dump(llvm::raw_ostream &) const;
285283

284+
// For sorting symbol names without being dependent on pointer values
285+
bool Precedes(CharBlock, CharBlock) const;
286+
287+
// Once a CookedSource is complete, add it to index_ and assign its number_
288+
void Register(CookedSource &);
289+
286290
private:
287291
AllSources &allSources_;
288292
std::list<CookedSource> cooked_; // owns all CookedSource instances
293+
int counter_{0};
294+
std::map<CharBlock, const CookedSource &, CharBlockPointerComparator> index_;
289295
};
296+
297+
// For use as a Comparator for maps, sets, sorting, &c.
298+
class CharBlockComparator {
299+
public:
300+
explicit CharBlockComparator(const AllCookedSources &all) : all_{all} {}
301+
bool operator()(CharBlock x, CharBlock y) const {
302+
return all_.Precedes(x, y);
303+
}
304+
305+
private:
306+
const AllCookedSources &all_;
307+
};
308+
290309
} // namespace Fortran::parser
291310
#endif // FORTRAN_PARSER_PROVENANCE_H_

flang/include/flang/Semantics/scope.h

+11-5
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ class Scope {
6262
using ImportKind = common::ImportKind;
6363

6464
// Create the Global scope -- the root of the scope tree
65-
Scope() : Scope{*this, Kind::Global, nullptr} {}
66-
Scope(Scope &parent, Kind kind, Symbol *symbol)
67-
: parent_{parent}, kind_{kind}, symbol_{symbol} {
65+
explicit Scope(SemanticsContext &context)
66+
: Scope{*this, Kind::Global, nullptr, context} {}
67+
Scope(Scope &parent, Kind kind, Symbol *symbol, SemanticsContext &context)
68+
: parent_{parent}, kind_{kind}, symbol_{symbol}, context_{context} {
6869
if (symbol) {
6970
symbol->set_scope(this);
7071
}
@@ -99,6 +100,7 @@ class Scope {
99100
}
100101
Symbol *symbol() { return symbol_; }
101102
const Symbol *symbol() const { return symbol_; }
103+
SemanticsContext &context() const { return context_; }
102104

103105
inline const Symbol *GetSymbol() const;
104106
const Scope *GetDerivedTypeParent() const;
@@ -107,6 +109,9 @@ class Scope {
107109
bool Contains(const Scope &) const;
108110
/// Make a scope nested in this one
109111
Scope &MakeScope(Kind kind, Symbol *symbol = nullptr);
112+
SemanticsContext &GetMutableSemanticsContext() const {
113+
return const_cast<SemanticsContext &>(context());
114+
}
110115

111116
using size_type = mapType::size_type;
112117
using iterator = mapType::iterator;
@@ -244,7 +249,7 @@ class Scope {
244249
symbol_->test(Symbol::Flag::ModFile);
245250
}
246251

247-
void InstantiateDerivedTypes(SemanticsContext &);
252+
void InstantiateDerivedTypes();
248253

249254
const Symbol *runtimeDerivedTypeDescription() const {
250255
return runtimeDerivedTypeDescription_;
@@ -273,8 +278,9 @@ class Scope {
273278
parser::Message::Reference instantiationContext_;
274279
bool hasSAVE_{false}; // scope has a bare SAVE statement
275280
const Symbol *runtimeDerivedTypeDescription_{nullptr};
281+
SemanticsContext &context_;
276282
// When additional data members are added to Scope, remember to
277-
// copy them, if appropriate, in InstantiateDerivedType().
283+
// copy them, if appropriate, in FindOrInstantiateDerivedType().
278284

279285
// Storage for all Symbols. Every Symbol is in allSymbols and every Symbol*
280286
// or Symbol& points to one in there.

flang/include/flang/Semantics/symbol.h

+15-17
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include <functional>
1919
#include <list>
2020
#include <optional>
21-
#include <unordered_set>
21+
#include <set>
2222
#include <vector>
2323

2424
namespace llvm {
@@ -595,10 +595,13 @@ class Symbol {
595595

596596
bool operator==(const Symbol &that) const { return this == &that; }
597597
bool operator!=(const Symbol &that) const { return !(*this == that); }
598-
bool operator<(const Symbol &that) const {
599-
// Used to collate symbols by creation order
600-
return sortIndex_ < that.sortIndex_;
601-
}
598+
599+
// Symbol comparison is based on the order of cooked source
600+
// stream creation and, when both are from the same cooked source,
601+
// their positions in that cooked source stream.
602+
// (This function is implemented in Evaluate/tools.cpp to
603+
// satisfy complicated shared library interdependency.)
604+
bool operator<(const Symbol &) const;
602605

603606
int Rank() const {
604607
return std::visit(
@@ -651,10 +654,11 @@ class Symbol {
651654
// for a parameterized derived type instantiation with the instance's scope.
652655
const DerivedTypeSpec *GetParentTypeSpec(const Scope * = nullptr) const;
653656

657+
SemanticsContext &GetSemanticsContext() const;
658+
654659
private:
655660
const Scope *owner_;
656661
SourceName name_;
657-
std::size_t sortIndex_; // to implement "operator<" platform independently
658662
Attrs attrs_;
659663
Flags flags_;
660664
Scope *scope_{nullptr};
@@ -689,7 +693,6 @@ template <std::size_t BLOCK_SIZE> class Symbols {
689693
Symbol &symbol = Get();
690694
symbol.owner_ = &owner;
691695
symbol.name_ = name;
692-
symbol.sortIndex_ = ++symbolCount_;
693696
symbol.attrs_ = attrs;
694697
symbol.details_ = std::move(details);
695698
return symbol;
@@ -700,7 +703,6 @@ template <std::size_t BLOCK_SIZE> class Symbols {
700703
std::list<blockType *> blocks_;
701704
std::size_t nextIndex_{0};
702705
blockType *currBlock_{nullptr};
703-
static inline std::size_t symbolCount_ = 0;
704706

705707
Symbol &Get() {
706708
if (nextIndex_ == 0) {
@@ -765,17 +767,13 @@ inline const DeclTypeSpec *Symbol::GetType() const {
765767
details_);
766768
}
767769

768-
inline bool operator<(SymbolRef x, SymbolRef y) { return *x < *y; }
770+
inline bool operator<(SymbolRef x, SymbolRef y) {
771+
return *x < *y; // name source position ordering
772+
}
769773
inline bool operator<(MutableSymbolRef x, MutableSymbolRef y) {
770-
return *x < *y;
774+
return *x < *y; // name source position ordering
771775
}
772-
struct SymbolHash {
773-
std::size_t operator()(SymbolRef symRef) const {
774-
std::hash<std::string> hasher;
775-
return hasher(symRef->name().ToString());
776-
}
777-
};
778-
using SymbolSet = std::unordered_set<SymbolRef, SymbolHash>;
776+
using SymbolSet = std::set<SymbolRef>;
779777

780778
} // namespace Fortran::semantics
781779

flang/lib/Evaluate/tools.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -1203,4 +1203,16 @@ const Symbol *FindFunctionResult(const Symbol &symbol) {
12031203
return FindFunctionResult(symbol, seen);
12041204
}
12051205

1206+
// These are here in Evaluate/tools.cpp so that Evaluate can use
1207+
// them; they cannot be defined in symbol.h due to the dependence
1208+
// on Scope.
1209+
1210+
bool Symbol::operator<(const Symbol &that) const {
1211+
return GetSemanticsContext().allCookedSources().Precedes(name_, that.name_);
1212+
}
1213+
1214+
SemanticsContext &Symbol::GetSemanticsContext() const {
1215+
return DEREF(owner_).context();
1216+
}
1217+
12061218
} // namespace Fortran::semantics

flang/lib/Parser/parsing.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) {
8888
// message about nonstandard usage will have provenance.
8989
currentCooked_->Put('\n', range.start());
9090
}
91-
currentCooked_->Marshal(allSources);
91+
currentCooked_->Marshal(allCooked_);
9292
if (options.needProvenanceRangeToCharBlockMappings) {
9393
currentCooked_->CompileProvenanceRangeToOffsetMappings(allSources);
9494
}

flang/lib/Parser/provenance.cpp

+37-2
Original file line numberDiff line numberDiff line change
@@ -442,11 +442,13 @@ std::optional<CharBlock> CookedSource::GetCharBlock(
442442

443443
std::size_t CookedSource::BufferedBytes() const { return buffer_.bytes(); }
444444

445-
void CookedSource::Marshal(AllSources &allSources) {
445+
void CookedSource::Marshal(AllCookedSources &allCookedSources) {
446446
CHECK(provenanceMap_.SizeInBytes() == buffer_.bytes());
447-
provenanceMap_.Put(allSources.AddCompilerInsertion("(after end of source)"));
447+
provenanceMap_.Put(allCookedSources.allSources().AddCompilerInsertion(
448+
"(after end of source)"));
448449
data_ = buffer_.Marshal();
449450
buffer_.clear();
451+
allCookedSources.Register(*this);
450452
}
451453

452454
void CookedSource::CompileProvenanceRangeToOffsetMappings(
@@ -534,6 +536,16 @@ CookedSource &AllCookedSources::NewCookedSource() {
534536
return cooked_.emplace_back();
535537
}
536538

539+
const CookedSource *AllCookedSources::Find(CharBlock x) const {
540+
auto pair{index_.equal_range(x)};
541+
for (auto iter{pair.first}; iter != pair.second; ++iter) {
542+
if (iter->second.AsCharBlock().Contains(x)) {
543+
return &iter->second;
544+
}
545+
}
546+
return nullptr;
547+
}
548+
537549
std::optional<ProvenanceRange> AllCookedSources::GetProvenanceRange(
538550
CharBlock cb) const {
539551
if (const CookedSource * c{Find(cb)}) {
@@ -589,4 +601,27 @@ void AllCookedSources::Dump(llvm::raw_ostream &o) const {
589601
}
590602
}
591603

604+
bool AllCookedSources::Precedes(CharBlock x, CharBlock y) const {
605+
const CookedSource *ySource{Find(y)};
606+
if (const CookedSource * xSource{Find(x)}) {
607+
if (ySource) {
608+
int xNum{xSource->number()};
609+
int yNum{ySource->number()};
610+
return xNum < yNum || (xNum == yNum && x.begin() < y.begin());
611+
} else {
612+
return true; // by fiat, all cooked source < anything outside
613+
}
614+
} else if (ySource) {
615+
return false;
616+
} else {
617+
// Both names are compiler-created (SaveTempName).
618+
return x < y;
619+
}
620+
}
621+
622+
void AllCookedSources::Register(CookedSource &cooked) {
623+
index_.emplace(cooked.AsCharBlock(), cooked);
624+
cooked.set_number(static_cast<int>(index_.size()));
625+
}
626+
592627
} // namespace Fortran::parser

flang/lib/Semantics/check-io.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,8 @@ void IoChecker::CheckForDefinableVariable(
930930
if (const auto *var{parser::Unwrap<parser::Variable>(variable)}) {
931931
if (auto expr{AnalyzeExpr(context_, *var)}) {
932932
auto at{var->GetSource()};
933-
if (auto whyNot{WhyNotModifiable(at, *expr, context_.FindScope(at))}) {
933+
if (auto whyNot{WhyNotModifiable(at, *expr, context_.FindScope(at),
934+
true /*vectorSubscriptIsOk*/)}) {
934935
const Symbol *base{GetFirstSymbol(*expr)};
935936
context_
936937
.Say(at, "%s variable '%s' must be definable"_err_en_US, s,

flang/lib/Semantics/resolve-names.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -6393,7 +6393,7 @@ void ResolveNamesVisitor::FinishSpecificationPart(
63936393
CheckPossibleBadForwardRef(symbol);
63946394
}
63956395
}
6396-
currScope().InstantiateDerivedTypes(context());
6396+
currScope().InstantiateDerivedTypes();
63976397
for (const auto &decl : decls) {
63986398
if (const auto *statement{std::get_if<
63996399
parser::Statement<common::Indirection<parser::StmtFunctionStmt>>>(

flang/lib/Semantics/scope.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ std::string EquivalenceObject::AsFortran() const {
5050
}
5151

5252
Scope &Scope::MakeScope(Kind kind, Symbol *symbol) {
53-
return children_.emplace_back(*this, kind, symbol);
53+
return children_.emplace_back(*this, kind, symbol, context_);
5454
}
5555

5656
template <typename T>
@@ -404,11 +404,11 @@ const Scope &Scope::GetDerivedTypeBase() const {
404404
return *child;
405405
}
406406

407-
void Scope::InstantiateDerivedTypes(SemanticsContext &context) {
407+
void Scope::InstantiateDerivedTypes() {
408408
for (DeclTypeSpec &type : declTypeSpecs_) {
409409
if (type.category() == DeclTypeSpec::TypeDerived ||
410410
type.category() == DeclTypeSpec::ClassDerived) {
411-
type.derivedTypeSpec().Instantiate(*this, context);
411+
type.derivedTypeSpec().Instantiate(*this, context_);
412412
}
413413
}
414414
}

flang/lib/Semantics/semantics.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,9 @@ SemanticsContext::SemanticsContext(
185185
: defaultKinds_{defaultKinds}, languageFeatures_{languageFeatures},
186186
allCookedSources_{allCookedSources},
187187
intrinsics_{evaluate::IntrinsicProcTable::Configure(defaultKinds_)},
188-
foldingContext_{
189-
parser::ContextualMessages{&messages_}, defaultKinds_, intrinsics_} {}
188+
globalScope_{*this}, foldingContext_{
189+
parser::ContextualMessages{&messages_},
190+
defaultKinds_, intrinsics_} {}
190191

191192
SemanticsContext::~SemanticsContext() {}
192193

flang/test/Semantics/data05.f90

+5-5
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,15 @@ integer function ifunc2(n)
7373
end function
7474
subroutine s11
7575
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
76-
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))
76+
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)
7777
type(t1(4,len=1)) :: d2 = t1(4)(xrp=extrfunc,rp=rfunc,ifptr=ifunc2,xp=arr,c='a&
78-
&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))
79-
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))
78+
&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)
79+
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)
8080
data d3/t1(1,reshape([1,2,3,4],[2,2]),(6.,7.),.false.,'ab',arr,ifunc2,rfunc,extrfunc)/
81-
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))
81+
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)
8282
data d4/t1(4)(xrp=extrfunc,rp=rfunc,ifptr=ifunc2,xp=arr,c='ab',t=.false.,z=(6&
8383
&.,7.),x=reshape([1,2,3,4],[2,2]),j=1)/
84-
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))
84+
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)
8585
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:&
8686
&2)/'b'/,d5%xp/arr/,d5%ifptr/ifunc2/,d5%rp/rfunc/,d5%xrp/extrfunc/
8787
end subroutine

flang/test/Semantics/modfile21.f90

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ module m
2626
! real(4)::v
2727
! complex(4)::w
2828
! real(4)::cb
29-
! common//t,w,u,v
3029
! common/cb/x,y,z
3130
! bind(c, name="CB")::/cb/
3231
! common/cb2/a,b,c
3332
! bind(c)::/cb2/
3433
! common/b/cb
34+
! common//t,w,u,v
3535
!end

0 commit comments

Comments
 (0)