Skip to content

Commit faae05d

Browse files
committed
[flang] Consolidate & clean up COMMON block checks
COMMON block checks are split between name resolution and declaration checking. We generally want declaration checks to take place after name resolution, and the COMMON block checks that are currently in name resolution have some derived type analyses that are redundant with the derived type component iteration framework used elsewhere in semantics. So move as much as possible into declaration checking, use the component iteration framework, and cope with the missing COMMON block name case that arises with blank COMMON when placing the error messages.
1 parent 0963cc2 commit faae05d

File tree

15 files changed

+186
-144
lines changed

15 files changed

+186
-144
lines changed

flang/include/flang/Parser/parse-tree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,6 +1639,7 @@ struct CommonStmt {
16391639
BOILERPLATE(CommonStmt);
16401640
CommonStmt(std::optional<Name> &&, std::list<CommonBlockObject> &&,
16411641
std::list<Block> &&);
1642+
CharBlock source;
16421643
std::list<Block> blocks;
16431644
};
16441645

flang/include/flang/Semantics/scope.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ class Scope {
188188
void add_crayPointer(const SourceName &, Symbol &);
189189
mapType &commonBlocks() { return commonBlocks_; }
190190
const mapType &commonBlocks() const { return commonBlocks_; }
191-
Symbol &MakeCommonBlock(const SourceName &);
191+
Symbol &MakeCommonBlock(SourceName, SourceName location);
192192
Symbol *FindCommonBlock(const SourceName &) const;
193193

194194
/// Make a Symbol but don't add it to the scope.

flang/include/flang/Semantics/symbol.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,17 +570,21 @@ class NamelistDetails {
570570

571571
class CommonBlockDetails : public WithBindName {
572572
public:
573+
explicit CommonBlockDetails(SourceName location)
574+
: sourceLocation_{location} {}
575+
SourceName sourceLocation() const { return sourceLocation_; }
573576
MutableSymbolVector &objects() { return objects_; }
574577
const MutableSymbolVector &objects() const { return objects_; }
575578
void add_object(Symbol &object) { objects_.emplace_back(object); }
576579
void replace_object(Symbol &object, unsigned index) {
577-
CHECK(index < (unsigned)objects_.size());
580+
CHECK(index < objects_.size());
578581
objects_[index] = object;
579582
}
580583
std::size_t alignment() const { return alignment_; }
581584
void set_alignment(std::size_t alignment) { alignment_ = alignment; }
582585

583586
private:
587+
SourceName sourceLocation_;
584588
MutableSymbolVector objects_;
585589
std::size_t alignment_{0}; // required alignment in bytes
586590
};

flang/include/flang/Semantics/type.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,9 @@ class DerivedTypeSpec {
285285
bool IsForwardReferenced() const;
286286
bool HasDefaultInitialization(
287287
bool ignoreAllocatable = false, bool ignorePointer = true) const;
288+
std::optional<std::string> // component path suitable for error messages
289+
ComponentWithDefaultInitialization(
290+
bool ignoreAllocatable = false, bool ignorePointer = true) const;
288291
bool HasDestruction() const;
289292

290293
// The "raw" type parameter list is a simple transcription from the

flang/lib/Evaluate/tools.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,15 @@ parser::Message *AttachDeclaration(
12091209
message.Attach(use->location(),
12101210
"'%s' is USE-associated with '%s' in module '%s'"_en_US, symbol.name(),
12111211
unhosted->name(), GetUsedModule(*use).name());
1212+
} else if (const auto *common{
1213+
unhosted->detailsIf<semantics::CommonBlockDetails>()}) {
1214+
parser::CharBlock at{unhosted->name()};
1215+
if (at.empty()) { // blank COMMON, with or without //
1216+
at = common->sourceLocation();
1217+
}
1218+
if (!at.empty()) {
1219+
message.Attach(at, "Declaration of /%s/"_en_US, unhosted->name());
1220+
}
12121221
} else {
12131222
message.Attach(
12141223
unhosted->name(), "Declaration of '%s'"_en_US, unhosted->name());

flang/lib/Parser/Fortran-parsers.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,14 +1100,14 @@ TYPE_PARSER(construct<EquivalenceObject>(indirect(designator)))
11001100
// R873 common-stmt ->
11011101
// COMMON [/ [common-block-name] /] common-block-object-list
11021102
// [[,] / [common-block-name] / common-block-object-list]...
1103-
TYPE_PARSER(
1103+
TYPE_PARSER(sourced(
11041104
construct<CommonStmt>("COMMON" >> defaulted("/" >> maybe(name) / "/"),
11051105
nonemptyList("expected COMMON block objects"_err_en_US,
11061106
Parser<CommonBlockObject>{}),
11071107
many(maybe(","_tok) >>
11081108
construct<CommonStmt::Block>("/" >> maybe(name) / "/",
11091109
nonemptyList("expected COMMON block objects"_err_en_US,
1110-
Parser<CommonBlockObject>{})))))
1110+
Parser<CommonBlockObject>{}))))))
11111111
11121112
// R874 common-block-object -> variable-name [( array-spec )]
11131113
TYPE_PARSER(construct<CommonBlockObject>(name, maybe(arraySpec)))

flang/lib/Semantics/check-declarations.cpp

Lines changed: 99 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -512,39 +512,111 @@ void CheckHelper::Check(const Symbol &symbol) {
512512
}
513513

514514
void CheckHelper::CheckCommonBlock(const Symbol &symbol) {
515-
auto restorer{messages_.SetLocation(symbol.name())};
516515
CheckGlobalName(symbol);
517-
if (symbol.attrs().test(Attr::BIND_C)) {
516+
const auto &common{symbol.get<CommonBlockDetails>()};
517+
SourceName location{symbol.name()};
518+
if (location.empty()) {
519+
location = common.sourceLocation();
520+
}
521+
bool isBindCCommon{symbol.attrs().test(Attr::BIND_C)};
522+
if (isBindCCommon) {
518523
CheckBindC(symbol);
519-
for (auto ref : symbol.get<CommonBlockDetails>().objects()) {
520-
if (ref->has<ObjectEntityDetails>()) {
521-
if (auto msgs{WhyNotInteroperableObject(*ref,
522-
/*allowInteroperableType=*/false, /*forCommonBlock=*/true)};
523-
!msgs.empty()) {
524-
parser::Message &reason{msgs.messages().front()};
525-
parser::Message *msg{nullptr};
526-
if (reason.IsFatal()) {
527-
msg = messages_.Say(symbol.name(),
528-
"'%s' may not be a member of BIND(C) COMMON block /%s/"_err_en_US,
529-
ref->name(), symbol.name());
530-
} else {
531-
msg = messages_.Say(symbol.name(),
532-
"'%s' should not be a member of BIND(C) COMMON block /%s/"_warn_en_US,
533-
ref->name(), symbol.name());
534-
}
535-
if (msg) {
536-
msg->Attach(
537-
std::move(reason.set_severity(parser::Severity::Because)));
538-
}
524+
}
525+
for (auto ref : symbol.get<CommonBlockDetails>().objects()) {
526+
auto restorer{
527+
messages_.SetLocation(location.empty() ? ref->name() : location)};
528+
if (isBindCCommon && ref->has<ObjectEntityDetails>()) {
529+
if (auto msgs{WhyNotInteroperableObject(*ref,
530+
/*allowInteroperableType=*/false, /*forCommonBlock=*/true)};
531+
!msgs.empty()) {
532+
parser::Message &reason{msgs.messages().front()};
533+
parser::Message *msg{nullptr};
534+
if (reason.IsFatal()) {
535+
msg = messages_.Say(
536+
"'%s' may not be a member of BIND(C) COMMON block /%s/"_err_en_US,
537+
ref->name(), symbol.name());
538+
} else {
539+
msg = messages_.Say(
540+
"'%s' should not be a member of BIND(C) COMMON block /%s/"_warn_en_US,
541+
ref->name(), symbol.name());
539542
}
543+
if (msg) {
544+
msg = &msg->Attach(
545+
std::move(reason.set_severity(parser::Severity::Because)));
546+
}
547+
evaluate::AttachDeclaration(msg, *ref);
540548
}
541549
}
542-
}
543-
for (auto ref : symbol.get<CommonBlockDetails>().objects()) {
544550
if (ref->test(Symbol::Flag::CrayPointee)) {
545-
messages_.Say(ref->name(),
546-
"Cray pointee '%s' may not be a member of a COMMON block"_err_en_US,
547-
ref->name());
551+
evaluate::AttachDeclaration(
552+
messages_.Say(
553+
"Cray pointee '%s' may not be a member of COMMON block /%s/"_err_en_US,
554+
ref->name(), symbol.name()),
555+
*ref);
556+
}
557+
if (IsAllocatable(*ref)) {
558+
evaluate::AttachDeclaration(
559+
messages_.Say(
560+
"ALLOCATABLE object '%s' may not appear in COMMON block /%s/"_err_en_US,
561+
ref->name(), symbol.name()),
562+
*ref);
563+
}
564+
if (ref->attrs().test(Attr::BIND_C)) {
565+
evaluate::AttachDeclaration(
566+
messages_.Say(
567+
"BIND(C) object '%s' may not appear in COMMON block /%s/"_err_en_US,
568+
ref->name(), symbol.name()),
569+
*ref);
570+
}
571+
if (IsNamedConstant(*ref)) {
572+
evaluate::AttachDeclaration(
573+
messages_.Say(
574+
"Named constant '%s' may not appear in COMMON block /%s/"_err_en_US,
575+
ref->name(), symbol.name()),
576+
*ref);
577+
}
578+
if (IsDummy(*ref)) {
579+
evaluate::AttachDeclaration(
580+
messages_.Say(
581+
"Dummy argument '%s' may not appear in COMMON block /%s/"_err_en_US,
582+
ref->name(), symbol.name()),
583+
*ref);
584+
}
585+
if (ref->IsFuncResult()) {
586+
evaluate::AttachDeclaration(
587+
messages_.Say(
588+
"Function result '%s' may not appear in COMMON block /%s/"_err_en_US,
589+
ref->name(), symbol.name()),
590+
*ref);
591+
}
592+
if (const auto *type{ref->GetType()}) {
593+
if (type->category() == DeclTypeSpec::ClassStar) {
594+
evaluate::AttachDeclaration(
595+
messages_.Say(
596+
"Unlimited polymorphic pointer '%s' may not appear in COMMON block /%s/"_err_en_US,
597+
ref->name(), symbol.name()),
598+
*ref);
599+
} else if (const auto *derived{type->AsDerived()}) {
600+
if (!IsSequenceOrBindCType(derived)) {
601+
evaluate::AttachDeclaration(
602+
evaluate::AttachDeclaration(
603+
messages_.Say(
604+
"Object '%s' whose derived type '%s' is neither SEQUENCE nor BIND(C) may not appear in COMMON block /%s/"_err_en_US,
605+
ref->name(), derived->name(), symbol.name()),
606+
derived->typeSymbol()),
607+
*ref);
608+
} else if (auto componentPath{
609+
derived->ComponentWithDefaultInitialization()}) {
610+
evaluate::AttachDeclaration(
611+
evaluate::AttachDeclaration(
612+
messages_.Say(
613+
"COMMON block /%s/ may not have the member '%s' whose derived type '%s' has a component '%s' that is ALLOCATABLE or has default initialization"_err_en_US,
614+
symbol.name(), ref->name(), derived->name(),
615+
*componentPath),
616+
derived->typeSymbol()),
617+
*ref);
618+
}
619+
}
548620
}
549621
}
550622
}

flang/lib/Semantics/resolve-directives.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
603603
for (const parser::OmpObject &obj : x.v) {
604604
auto *name{std::get_if<parser::Name>(&obj.u)};
605605
if (name && !name->symbol) {
606-
Resolve(*name, currScope().MakeCommonBlock(name->source));
606+
Resolve(*name, currScope().MakeCommonBlock(name->source, name->source));
607607
}
608608
}
609609
}

flang/lib/Semantics/resolve-names.cpp

Lines changed: 13 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,8 +1105,9 @@ class DeclarationVisitor : public ArraySpecVisitor,
11051105
// or nullptr on error.
11061106
Symbol *DeclareStatementEntity(const parser::DoVariable &,
11071107
const std::optional<parser::IntegerTypeSpec> &);
1108-
Symbol &MakeCommonBlockSymbol(const parser::Name &);
1109-
Symbol &MakeCommonBlockSymbol(const std::optional<parser::Name> &);
1108+
Symbol &MakeCommonBlockSymbol(const parser::Name &, SourceName);
1109+
Symbol &MakeCommonBlockSymbol(
1110+
const std::optional<parser::Name> &, SourceName);
11101111
bool CheckUseError(const parser::Name &);
11111112
void CheckAccessibility(const SourceName &, bool, Symbol &);
11121113
void CheckCommonBlocks();
@@ -1243,8 +1244,6 @@ class DeclarationVisitor : public ArraySpecVisitor,
12431244
bool OkToAddComponent(const parser::Name &, const Symbol *extends = nullptr);
12441245
ParamValue GetParamValue(
12451246
const parser::TypeParamValue &, common::TypeParamAttr attr);
1246-
void CheckCommonBlockDerivedType(
1247-
const SourceName &, const Symbol &, UnorderedSymbolSet &);
12481247
Attrs HandleSaveName(const SourceName &, Attrs);
12491248
void AddSaveName(std::set<SourceName> &, const SourceName &);
12501249
bool HandleUnrestrictedSpecificIntrinsicFunction(const parser::Name &);
@@ -5508,7 +5507,7 @@ bool DeclarationVisitor::Pre(const parser::BindEntity &x) {
55085507
if (kind == parser::BindEntity::Kind::Object) {
55095508
symbol = &HandleAttributeStmt(Attr::BIND_C, name);
55105509
} else {
5511-
symbol = &MakeCommonBlockSymbol(name);
5510+
symbol = &MakeCommonBlockSymbol(name, name.source);
55125511
SetExplicitAttr(*symbol, Attr::BIND_C);
55135512
}
55145513
// 8.6.4(1)
@@ -7090,7 +7089,7 @@ bool DeclarationVisitor::Pre(const parser::SaveStmt &x) {
70907089
auto kind{std::get<parser::SavedEntity::Kind>(y.t)};
70917090
const auto &name{std::get<parser::Name>(y.t)};
70927091
if (kind == parser::SavedEntity::Kind::Common) {
7093-
MakeCommonBlockSymbol(name);
7092+
MakeCommonBlockSymbol(name, name.source);
70947093
AddSaveName(specPartState_.saveInfo.commons, name.source);
70957094
} else {
70967095
HandleAttributeStmt(Attr::SAVE, name);
@@ -7170,103 +7169,29 @@ void DeclarationVisitor::CheckCommonBlocks() {
71707169
if (symbol.get<CommonBlockDetails>().objects().empty() &&
71717170
symbol.attrs().test(Attr::BIND_C)) {
71727171
Say(symbol.name(),
7173-
"'%s' appears as a COMMON block in a BIND statement but not in"
7174-
" a COMMON statement"_err_en_US);
7175-
}
7176-
}
7177-
// check objects in common blocks
7178-
for (const auto &name : specPartState_.commonBlockObjects) {
7179-
const auto *symbol{currScope().FindSymbol(name)};
7180-
if (!symbol) {
7181-
continue;
7182-
}
7183-
const auto &attrs{symbol->attrs()};
7184-
if (attrs.test(Attr::ALLOCATABLE)) {
7185-
Say(name,
7186-
"ALLOCATABLE object '%s' may not appear in a COMMON block"_err_en_US);
7187-
} else if (attrs.test(Attr::BIND_C)) {
7188-
Say(name,
7189-
"Variable '%s' with BIND attribute may not appear in a COMMON block"_err_en_US);
7190-
} else if (IsNamedConstant(*symbol)) {
7191-
Say(name,
7192-
"A named constant '%s' may not appear in a COMMON block"_err_en_US);
7193-
} else if (IsDummy(*symbol)) {
7194-
Say(name,
7195-
"Dummy argument '%s' may not appear in a COMMON block"_err_en_US);
7196-
} else if (symbol->IsFuncResult()) {
7197-
Say(name,
7198-
"Function result '%s' may not appear in a COMMON block"_err_en_US);
7199-
} else if (const DeclTypeSpec * type{symbol->GetType()}) {
7200-
if (type->category() == DeclTypeSpec::ClassStar) {
7201-
Say(name,
7202-
"Unlimited polymorphic pointer '%s' may not appear in a COMMON block"_err_en_US);
7203-
} else if (const auto *derived{type->AsDerived()}) {
7204-
if (!IsSequenceOrBindCType(derived)) {
7205-
Say(name,
7206-
"Derived type '%s' in COMMON block must have the BIND or"
7207-
" SEQUENCE attribute"_err_en_US);
7208-
}
7209-
UnorderedSymbolSet typeSet;
7210-
CheckCommonBlockDerivedType(name, derived->typeSymbol(), typeSet);
7211-
}
7172+
"'%s' appears as a COMMON block in a BIND statement but not in a COMMON statement"_err_en_US);
72127173
}
72137174
}
72147175
specPartState_.commonBlockObjects = {};
72157176
}
72167177

7217-
Symbol &DeclarationVisitor::MakeCommonBlockSymbol(const parser::Name &name) {
7218-
return Resolve(name, currScope().MakeCommonBlock(name.source));
7178+
Symbol &DeclarationVisitor::MakeCommonBlockSymbol(
7179+
const parser::Name &name, SourceName location) {
7180+
return Resolve(name, currScope().MakeCommonBlock(name.source, location));
72197181
}
72207182
Symbol &DeclarationVisitor::MakeCommonBlockSymbol(
7221-
const std::optional<parser::Name> &name) {
7183+
const std::optional<parser::Name> &name, SourceName location) {
72227184
if (name) {
7223-
return MakeCommonBlockSymbol(*name);
7185+
return MakeCommonBlockSymbol(*name, location);
72247186
} else {
7225-
return MakeCommonBlockSymbol(parser::Name{});
7187+
return MakeCommonBlockSymbol(parser::Name{}, location);
72267188
}
72277189
}
72287190

72297191
bool DeclarationVisitor::NameIsKnownOrIntrinsic(const parser::Name &name) {
72307192
return FindSymbol(name) || HandleUnrestrictedSpecificIntrinsicFunction(name);
72317193
}
72327194

7233-
// Check if this derived type can be in a COMMON block.
7234-
void DeclarationVisitor::CheckCommonBlockDerivedType(const SourceName &name,
7235-
const Symbol &typeSymbol, UnorderedSymbolSet &typeSet) {
7236-
if (auto iter{typeSet.find(SymbolRef{typeSymbol})}; iter != typeSet.end()) {
7237-
return;
7238-
}
7239-
typeSet.emplace(typeSymbol);
7240-
if (const auto *scope{typeSymbol.scope()}) {
7241-
for (const auto &pair : *scope) {
7242-
const Symbol &component{*pair.second};
7243-
if (component.attrs().test(Attr::ALLOCATABLE)) {
7244-
Say2(name,
7245-
"Derived type variable '%s' may not appear in a COMMON block"
7246-
" due to ALLOCATABLE component"_err_en_US,
7247-
component.name(), "Component with ALLOCATABLE attribute"_en_US);
7248-
return;
7249-
}
7250-
const auto *details{component.detailsIf<ObjectEntityDetails>()};
7251-
if (component.test(Symbol::Flag::InDataStmt) ||
7252-
(details && details->init())) {
7253-
Say2(name,
7254-
"Derived type variable '%s' may not appear in a COMMON block due to component with default initialization"_err_en_US,
7255-
component.name(), "Component with default initialization"_en_US);
7256-
return;
7257-
}
7258-
if (details) {
7259-
if (const auto *type{details->type()}) {
7260-
if (const auto *derived{type->AsDerived()}) {
7261-
const Symbol &derivedTypeSymbol{derived->typeSymbol()};
7262-
CheckCommonBlockDerivedType(name, derivedTypeSymbol, typeSet);
7263-
}
7264-
}
7265-
}
7266-
}
7267-
}
7268-
}
7269-
72707195
bool DeclarationVisitor::HandleUnrestrictedSpecificIntrinsicFunction(
72717196
const parser::Name &name) {
72727197
if (auto interface{context().intrinsics().IsSpecificIntrinsicFunction(
@@ -9598,7 +9523,7 @@ void ResolveNamesVisitor::CreateCommonBlockSymbols(
95989523
const parser::CommonStmt &commonStmt) {
95999524
for (const parser::CommonStmt::Block &block : commonStmt.blocks) {
96009525
const auto &[name, objects] = block.t;
9601-
Symbol &commonBlock{MakeCommonBlockSymbol(name)};
9526+
Symbol &commonBlock{MakeCommonBlockSymbol(name, commonStmt.source)};
96029527
for (const auto &object : objects) {
96039528
Symbol &obj{DeclareObjectEntity(std::get<parser::Name>(object.t))};
96049529
if (auto *details{obj.detailsIf<ObjectEntityDetails>()}) {

0 commit comments

Comments
 (0)