Skip to content

Commit 1fba01a

Browse files
authored
[flang] Consolidate & clean up COMMON block checks (#161286)
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 8fd8fb4 commit 1fba01a

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
@@ -625,7 +625,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
625625
for (const parser::OmpObject &obj : x.v) {
626626
auto *name{std::get_if<parser::Name>(&obj.u)};
627627
if (name && !name->symbol) {
628-
Resolve(*name, currScope().MakeCommonBlock(name->source));
628+
Resolve(*name, currScope().MakeCommonBlock(name->source, name->source));
629629
}
630630
}
631631
}

flang/lib/Semantics/resolve-names.cpp

Lines changed: 13 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,8 +1106,9 @@ class DeclarationVisitor : public ArraySpecVisitor,
11061106
// or nullptr on error.
11071107
Symbol *DeclareStatementEntity(const parser::DoVariable &,
11081108
const std::optional<parser::IntegerTypeSpec> &);
1109-
Symbol &MakeCommonBlockSymbol(const parser::Name &);
1110-
Symbol &MakeCommonBlockSymbol(const std::optional<parser::Name> &);
1109+
Symbol &MakeCommonBlockSymbol(const parser::Name &, SourceName);
1110+
Symbol &MakeCommonBlockSymbol(
1111+
const std::optional<parser::Name> &, SourceName);
11111112
bool CheckUseError(const parser::Name &);
11121113
void CheckAccessibility(const SourceName &, bool, Symbol &);
11131114
void CheckCommonBlocks();
@@ -1244,8 +1245,6 @@ class DeclarationVisitor : public ArraySpecVisitor,
12441245
bool OkToAddComponent(const parser::Name &, const Symbol *extends = nullptr);
12451246
ParamValue GetParamValue(
12461247
const parser::TypeParamValue &, common::TypeParamAttr attr);
1247-
void CheckCommonBlockDerivedType(
1248-
const SourceName &, const Symbol &, UnorderedSymbolSet &);
12491248
Attrs HandleSaveName(const SourceName &, Attrs);
12501249
void AddSaveName(std::set<SourceName> &, const SourceName &);
12511250
bool HandleUnrestrictedSpecificIntrinsicFunction(const parser::Name &);
@@ -5564,7 +5563,7 @@ bool DeclarationVisitor::Pre(const parser::BindEntity &x) {
55645563
if (kind == parser::BindEntity::Kind::Object) {
55655564
symbol = &HandleAttributeStmt(Attr::BIND_C, name);
55665565
} else {
5567-
symbol = &MakeCommonBlockSymbol(name);
5566+
symbol = &MakeCommonBlockSymbol(name, name.source);
55685567
SetExplicitAttr(*symbol, Attr::BIND_C);
55695568
}
55705569
// 8.6.4(1)
@@ -7147,7 +7146,7 @@ bool DeclarationVisitor::Pre(const parser::SaveStmt &x) {
71477146
auto kind{std::get<parser::SavedEntity::Kind>(y.t)};
71487147
const auto &name{std::get<parser::Name>(y.t)};
71497148
if (kind == parser::SavedEntity::Kind::Common) {
7150-
MakeCommonBlockSymbol(name);
7149+
MakeCommonBlockSymbol(name, name.source);
71517150
AddSaveName(specPartState_.saveInfo.commons, name.source);
71527151
} else {
71537152
HandleAttributeStmt(Attr::SAVE, name);
@@ -7227,103 +7226,29 @@ void DeclarationVisitor::CheckCommonBlocks() {
72277226
if (symbol.get<CommonBlockDetails>().objects().empty() &&
72287227
symbol.attrs().test(Attr::BIND_C)) {
72297228
Say(symbol.name(),
7230-
"'%s' appears as a COMMON block in a BIND statement but not in"
7231-
" a COMMON statement"_err_en_US);
7232-
}
7233-
}
7234-
// check objects in common blocks
7235-
for (const auto &name : specPartState_.commonBlockObjects) {
7236-
const auto *symbol{currScope().FindSymbol(name)};
7237-
if (!symbol) {
7238-
continue;
7239-
}
7240-
const auto &attrs{symbol->attrs()};
7241-
if (attrs.test(Attr::ALLOCATABLE)) {
7242-
Say(name,
7243-
"ALLOCATABLE object '%s' may not appear in a COMMON block"_err_en_US);
7244-
} else if (attrs.test(Attr::BIND_C)) {
7245-
Say(name,
7246-
"Variable '%s' with BIND attribute may not appear in a COMMON block"_err_en_US);
7247-
} else if (IsNamedConstant(*symbol)) {
7248-
Say(name,
7249-
"A named constant '%s' may not appear in a COMMON block"_err_en_US);
7250-
} else if (IsDummy(*symbol)) {
7251-
Say(name,
7252-
"Dummy argument '%s' may not appear in a COMMON block"_err_en_US);
7253-
} else if (symbol->IsFuncResult()) {
7254-
Say(name,
7255-
"Function result '%s' may not appear in a COMMON block"_err_en_US);
7256-
} else if (const DeclTypeSpec * type{symbol->GetType()}) {
7257-
if (type->category() == DeclTypeSpec::ClassStar) {
7258-
Say(name,
7259-
"Unlimited polymorphic pointer '%s' may not appear in a COMMON block"_err_en_US);
7260-
} else if (const auto *derived{type->AsDerived()}) {
7261-
if (!IsSequenceOrBindCType(derived)) {
7262-
Say(name,
7263-
"Derived type '%s' in COMMON block must have the BIND or"
7264-
" SEQUENCE attribute"_err_en_US);
7265-
}
7266-
UnorderedSymbolSet typeSet;
7267-
CheckCommonBlockDerivedType(name, derived->typeSymbol(), typeSet);
7268-
}
7229+
"'%s' appears as a COMMON block in a BIND statement but not in a COMMON statement"_err_en_US);
72697230
}
72707231
}
72717232
specPartState_.commonBlockObjects = {};
72727233
}
72737234

7274-
Symbol &DeclarationVisitor::MakeCommonBlockSymbol(const parser::Name &name) {
7275-
return Resolve(name, currScope().MakeCommonBlock(name.source));
7235+
Symbol &DeclarationVisitor::MakeCommonBlockSymbol(
7236+
const parser::Name &name, SourceName location) {
7237+
return Resolve(name, currScope().MakeCommonBlock(name.source, location));
72767238
}
72777239
Symbol &DeclarationVisitor::MakeCommonBlockSymbol(
7278-
const std::optional<parser::Name> &name) {
7240+
const std::optional<parser::Name> &name, SourceName location) {
72797241
if (name) {
7280-
return MakeCommonBlockSymbol(*name);
7242+
return MakeCommonBlockSymbol(*name, location);
72817243
} else {
7282-
return MakeCommonBlockSymbol(parser::Name{});
7244+
return MakeCommonBlockSymbol(parser::Name{}, location);
72837245
}
72847246
}
72857247

72867248
bool DeclarationVisitor::NameIsKnownOrIntrinsic(const parser::Name &name) {
72877249
return FindSymbol(name) || HandleUnrestrictedSpecificIntrinsicFunction(name);
72887250
}
72897251

7290-
// Check if this derived type can be in a COMMON block.
7291-
void DeclarationVisitor::CheckCommonBlockDerivedType(const SourceName &name,
7292-
const Symbol &typeSymbol, UnorderedSymbolSet &typeSet) {
7293-
if (auto iter{typeSet.find(SymbolRef{typeSymbol})}; iter != typeSet.end()) {
7294-
return;
7295-
}
7296-
typeSet.emplace(typeSymbol);
7297-
if (const auto *scope{typeSymbol.scope()}) {
7298-
for (const auto &pair : *scope) {
7299-
const Symbol &component{*pair.second};
7300-
if (component.attrs().test(Attr::ALLOCATABLE)) {
7301-
Say2(name,
7302-
"Derived type variable '%s' may not appear in a COMMON block"
7303-
" due to ALLOCATABLE component"_err_en_US,
7304-
component.name(), "Component with ALLOCATABLE attribute"_en_US);
7305-
return;
7306-
}
7307-
const auto *details{component.detailsIf<ObjectEntityDetails>()};
7308-
if (component.test(Symbol::Flag::InDataStmt) ||
7309-
(details && details->init())) {
7310-
Say2(name,
7311-
"Derived type variable '%s' may not appear in a COMMON block due to component with default initialization"_err_en_US,
7312-
component.name(), "Component with default initialization"_en_US);
7313-
return;
7314-
}
7315-
if (details) {
7316-
if (const auto *type{details->type()}) {
7317-
if (const auto *derived{type->AsDerived()}) {
7318-
const Symbol &derivedTypeSymbol{derived->typeSymbol()};
7319-
CheckCommonBlockDerivedType(name, derivedTypeSymbol, typeSet);
7320-
}
7321-
}
7322-
}
7323-
}
7324-
}
7325-
}
7326-
73277252
bool DeclarationVisitor::HandleUnrestrictedSpecificIntrinsicFunction(
73287253
const parser::Name &name) {
73297254
if (auto interface{context().intrinsics().IsSpecificIntrinsicFunction(
@@ -9655,7 +9580,7 @@ void ResolveNamesVisitor::CreateCommonBlockSymbols(
96559580
const parser::CommonStmt &commonStmt) {
96569581
for (const parser::CommonStmt::Block &block : commonStmt.blocks) {
96579582
const auto &[name, objects] = block.t;
9658-
Symbol &commonBlock{MakeCommonBlockSymbol(name)};
9583+
Symbol &commonBlock{MakeCommonBlockSymbol(name, commonStmt.source)};
96599584
for (const auto &object : objects) {
96609585
Symbol &obj{DeclareObjectEntity(std::get<parser::Name>(object.t))};
96619586
if (auto *details{obj.detailsIf<ObjectEntityDetails>()}) {

0 commit comments

Comments
 (0)