Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,7 @@ struct CommonStmt {
BOILERPLATE(CommonStmt);
CommonStmt(std::optional<Name> &&, std::list<CommonBlockObject> &&,
std::list<Block> &&);
CharBlock source;
std::list<Block> blocks;
};

Expand Down
2 changes: 1 addition & 1 deletion flang/include/flang/Semantics/scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class Scope {
void add_crayPointer(const SourceName &, Symbol &);
mapType &commonBlocks() { return commonBlocks_; }
const mapType &commonBlocks() const { return commonBlocks_; }
Symbol &MakeCommonBlock(const SourceName &);
Symbol &MakeCommonBlock(SourceName, SourceName location);
Symbol *FindCommonBlock(const SourceName &) const;

/// Make a Symbol but don't add it to the scope.
Expand Down
6 changes: 5 additions & 1 deletion flang/include/flang/Semantics/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -570,17 +570,21 @@ class NamelistDetails {

class CommonBlockDetails : public WithBindName {
public:
explicit CommonBlockDetails(SourceName location)
: sourceLocation_{location} {}
SourceName sourceLocation() const { return sourceLocation_; }
MutableSymbolVector &objects() { return objects_; }
const MutableSymbolVector &objects() const { return objects_; }
void add_object(Symbol &object) { objects_.emplace_back(object); }
void replace_object(Symbol &object, unsigned index) {
CHECK(index < (unsigned)objects_.size());
CHECK(index < objects_.size());
objects_[index] = object;
}
std::size_t alignment() const { return alignment_; }
void set_alignment(std::size_t alignment) { alignment_ = alignment; }

private:
SourceName sourceLocation_;
MutableSymbolVector objects_;
std::size_t alignment_{0}; // required alignment in bytes
};
Expand Down
3 changes: 3 additions & 0 deletions flang/include/flang/Semantics/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,9 @@ class DerivedTypeSpec {
bool IsForwardReferenced() const;
bool HasDefaultInitialization(
bool ignoreAllocatable = false, bool ignorePointer = true) const;
std::optional<std::string> // component path suitable for error messages
ComponentWithDefaultInitialization(
bool ignoreAllocatable = false, bool ignorePointer = true) const;
bool HasDestruction() const;

// The "raw" type parameter list is a simple transcription from the
Expand Down
9 changes: 9 additions & 0 deletions flang/lib/Evaluate/tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,15 @@ parser::Message *AttachDeclaration(
message.Attach(use->location(),
"'%s' is USE-associated with '%s' in module '%s'"_en_US, symbol.name(),
unhosted->name(), GetUsedModule(*use).name());
} else if (const auto *common{
unhosted->detailsIf<semantics::CommonBlockDetails>()}) {
parser::CharBlock at{unhosted->name()};
if (at.empty()) { // blank COMMON, with or without //
at = common->sourceLocation();
}
if (!at.empty()) {
message.Attach(at, "Declaration of /%s/"_en_US, unhosted->name());
}
} else {
message.Attach(
unhosted->name(), "Declaration of '%s'"_en_US, unhosted->name());
Expand Down
4 changes: 2 additions & 2 deletions flang/lib/Parser/Fortran-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1100,14 +1100,14 @@ TYPE_PARSER(construct<EquivalenceObject>(indirect(designator)))
// R873 common-stmt ->
// COMMON [/ [common-block-name] /] common-block-object-list
// [[,] / [common-block-name] / common-block-object-list]...
TYPE_PARSER(
TYPE_PARSER(sourced(
construct<CommonStmt>("COMMON" >> defaulted("/" >> maybe(name) / "/"),
nonemptyList("expected COMMON block objects"_err_en_US,
Parser<CommonBlockObject>{}),
many(maybe(","_tok) >>
construct<CommonStmt::Block>("/" >> maybe(name) / "/",
nonemptyList("expected COMMON block objects"_err_en_US,
Parser<CommonBlockObject>{})))))
Parser<CommonBlockObject>{}))))))

// R874 common-block-object -> variable-name [( array-spec )]
TYPE_PARSER(construct<CommonBlockObject>(name, maybe(arraySpec)))
Expand Down
126 changes: 99 additions & 27 deletions flang/lib/Semantics/check-declarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -512,39 +512,111 @@ void CheckHelper::Check(const Symbol &symbol) {
}

void CheckHelper::CheckCommonBlock(const Symbol &symbol) {
auto restorer{messages_.SetLocation(symbol.name())};
CheckGlobalName(symbol);
if (symbol.attrs().test(Attr::BIND_C)) {
const auto &common{symbol.get<CommonBlockDetails>()};
SourceName location{symbol.name()};
if (location.empty()) {
location = common.sourceLocation();
}
bool isBindCCommon{symbol.attrs().test(Attr::BIND_C)};
if (isBindCCommon) {
CheckBindC(symbol);
for (auto ref : symbol.get<CommonBlockDetails>().objects()) {
if (ref->has<ObjectEntityDetails>()) {
if (auto msgs{WhyNotInteroperableObject(*ref,
/*allowInteroperableType=*/false, /*forCommonBlock=*/true)};
!msgs.empty()) {
parser::Message &reason{msgs.messages().front()};
parser::Message *msg{nullptr};
if (reason.IsFatal()) {
msg = messages_.Say(symbol.name(),
"'%s' may not be a member of BIND(C) COMMON block /%s/"_err_en_US,
ref->name(), symbol.name());
} else {
msg = messages_.Say(symbol.name(),
"'%s' should not be a member of BIND(C) COMMON block /%s/"_warn_en_US,
ref->name(), symbol.name());
}
if (msg) {
msg->Attach(
std::move(reason.set_severity(parser::Severity::Because)));
}
}
for (auto ref : symbol.get<CommonBlockDetails>().objects()) {
auto restorer{
messages_.SetLocation(location.empty() ? ref->name() : location)};
if (isBindCCommon && ref->has<ObjectEntityDetails>()) {
if (auto msgs{WhyNotInteroperableObject(*ref,
/*allowInteroperableType=*/false, /*forCommonBlock=*/true)};
!msgs.empty()) {
parser::Message &reason{msgs.messages().front()};
parser::Message *msg{nullptr};
if (reason.IsFatal()) {
msg = messages_.Say(
"'%s' may not be a member of BIND(C) COMMON block /%s/"_err_en_US,
ref->name(), symbol.name());
} else {
msg = messages_.Say(
"'%s' should not be a member of BIND(C) COMMON block /%s/"_warn_en_US,
ref->name(), symbol.name());
}
if (msg) {
msg = &msg->Attach(
std::move(reason.set_severity(parser::Severity::Because)));
}
evaluate::AttachDeclaration(msg, *ref);
}
}
}
for (auto ref : symbol.get<CommonBlockDetails>().objects()) {
if (ref->test(Symbol::Flag::CrayPointee)) {
messages_.Say(ref->name(),
"Cray pointee '%s' may not be a member of a COMMON block"_err_en_US,
ref->name());
evaluate::AttachDeclaration(
messages_.Say(
"Cray pointee '%s' may not be a member of COMMON block /%s/"_err_en_US,
ref->name(), symbol.name()),
*ref);
}
if (IsAllocatable(*ref)) {
evaluate::AttachDeclaration(
messages_.Say(
"ALLOCATABLE object '%s' may not appear in COMMON block /%s/"_err_en_US,
ref->name(), symbol.name()),
*ref);
}
if (ref->attrs().test(Attr::BIND_C)) {
evaluate::AttachDeclaration(
messages_.Say(
"BIND(C) object '%s' may not appear in COMMON block /%s/"_err_en_US,
ref->name(), symbol.name()),
*ref);
}
if (IsNamedConstant(*ref)) {
evaluate::AttachDeclaration(
messages_.Say(
"Named constant '%s' may not appear in COMMON block /%s/"_err_en_US,
ref->name(), symbol.name()),
*ref);
}
if (IsDummy(*ref)) {
evaluate::AttachDeclaration(
messages_.Say(
"Dummy argument '%s' may not appear in COMMON block /%s/"_err_en_US,
ref->name(), symbol.name()),
*ref);
}
if (ref->IsFuncResult()) {
evaluate::AttachDeclaration(
messages_.Say(
"Function result '%s' may not appear in COMMON block /%s/"_err_en_US,
ref->name(), symbol.name()),
*ref);
}
if (const auto *type{ref->GetType()}) {
if (type->category() == DeclTypeSpec::ClassStar) {
evaluate::AttachDeclaration(
messages_.Say(
"Unlimited polymorphic pointer '%s' may not appear in COMMON block /%s/"_err_en_US,
ref->name(), symbol.name()),
*ref);
} else if (const auto *derived{type->AsDerived()}) {
if (!IsSequenceOrBindCType(derived)) {
evaluate::AttachDeclaration(
evaluate::AttachDeclaration(
messages_.Say(
"Object '%s' whose derived type '%s' is neither SEQUENCE nor BIND(C) may not appear in COMMON block /%s/"_err_en_US,
ref->name(), derived->name(), symbol.name()),
derived->typeSymbol()),
*ref);
} else if (auto componentPath{
derived->ComponentWithDefaultInitialization()}) {
evaluate::AttachDeclaration(
evaluate::AttachDeclaration(
messages_.Say(
"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,
symbol.name(), ref->name(), derived->name(),
*componentPath),
derived->typeSymbol()),
*ref);
}
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Semantics/resolve-directives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
for (const parser::OmpObject &obj : x.v) {
auto *name{std::get_if<parser::Name>(&obj.u)};
if (name && !name->symbol) {
Resolve(*name, currScope().MakeCommonBlock(name->source));
Resolve(*name, currScope().MakeCommonBlock(name->source, name->source));
}
}
}
Expand Down
101 changes: 13 additions & 88 deletions flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1105,8 +1105,9 @@ class DeclarationVisitor : public ArraySpecVisitor,
// or nullptr on error.
Symbol *DeclareStatementEntity(const parser::DoVariable &,
const std::optional<parser::IntegerTypeSpec> &);
Symbol &MakeCommonBlockSymbol(const parser::Name &);
Symbol &MakeCommonBlockSymbol(const std::optional<parser::Name> &);
Symbol &MakeCommonBlockSymbol(const parser::Name &, SourceName);
Symbol &MakeCommonBlockSymbol(
const std::optional<parser::Name> &, SourceName);
bool CheckUseError(const parser::Name &);
void CheckAccessibility(const SourceName &, bool, Symbol &);
void CheckCommonBlocks();
Expand Down Expand Up @@ -1243,8 +1244,6 @@ class DeclarationVisitor : public ArraySpecVisitor,
bool OkToAddComponent(const parser::Name &, const Symbol *extends = nullptr);
ParamValue GetParamValue(
const parser::TypeParamValue &, common::TypeParamAttr attr);
void CheckCommonBlockDerivedType(
const SourceName &, const Symbol &, UnorderedSymbolSet &);
Attrs HandleSaveName(const SourceName &, Attrs);
void AddSaveName(std::set<SourceName> &, const SourceName &);
bool HandleUnrestrictedSpecificIntrinsicFunction(const parser::Name &);
Expand Down Expand Up @@ -5508,7 +5507,7 @@ bool DeclarationVisitor::Pre(const parser::BindEntity &x) {
if (kind == parser::BindEntity::Kind::Object) {
symbol = &HandleAttributeStmt(Attr::BIND_C, name);
} else {
symbol = &MakeCommonBlockSymbol(name);
symbol = &MakeCommonBlockSymbol(name, name.source);
SetExplicitAttr(*symbol, Attr::BIND_C);
}
// 8.6.4(1)
Expand Down Expand Up @@ -7090,7 +7089,7 @@ bool DeclarationVisitor::Pre(const parser::SaveStmt &x) {
auto kind{std::get<parser::SavedEntity::Kind>(y.t)};
const auto &name{std::get<parser::Name>(y.t)};
if (kind == parser::SavedEntity::Kind::Common) {
MakeCommonBlockSymbol(name);
MakeCommonBlockSymbol(name, name.source);
AddSaveName(specPartState_.saveInfo.commons, name.source);
} else {
HandleAttributeStmt(Attr::SAVE, name);
Expand Down Expand Up @@ -7170,103 +7169,29 @@ void DeclarationVisitor::CheckCommonBlocks() {
if (symbol.get<CommonBlockDetails>().objects().empty() &&
symbol.attrs().test(Attr::BIND_C)) {
Say(symbol.name(),
"'%s' appears as a COMMON block in a BIND statement but not in"
" a COMMON statement"_err_en_US);
}
}
// check objects in common blocks
for (const auto &name : specPartState_.commonBlockObjects) {
const auto *symbol{currScope().FindSymbol(name)};
if (!symbol) {
continue;
}
const auto &attrs{symbol->attrs()};
if (attrs.test(Attr::ALLOCATABLE)) {
Say(name,
"ALLOCATABLE object '%s' may not appear in a COMMON block"_err_en_US);
} else if (attrs.test(Attr::BIND_C)) {
Say(name,
"Variable '%s' with BIND attribute may not appear in a COMMON block"_err_en_US);
} else if (IsNamedConstant(*symbol)) {
Say(name,
"A named constant '%s' may not appear in a COMMON block"_err_en_US);
} else if (IsDummy(*symbol)) {
Say(name,
"Dummy argument '%s' may not appear in a COMMON block"_err_en_US);
} else if (symbol->IsFuncResult()) {
Say(name,
"Function result '%s' may not appear in a COMMON block"_err_en_US);
} else if (const DeclTypeSpec * type{symbol->GetType()}) {
if (type->category() == DeclTypeSpec::ClassStar) {
Say(name,
"Unlimited polymorphic pointer '%s' may not appear in a COMMON block"_err_en_US);
} else if (const auto *derived{type->AsDerived()}) {
if (!IsSequenceOrBindCType(derived)) {
Say(name,
"Derived type '%s' in COMMON block must have the BIND or"
" SEQUENCE attribute"_err_en_US);
}
UnorderedSymbolSet typeSet;
CheckCommonBlockDerivedType(name, derived->typeSymbol(), typeSet);
}
"'%s' appears as a COMMON block in a BIND statement but not in a COMMON statement"_err_en_US);
}
}
specPartState_.commonBlockObjects = {};
}

Symbol &DeclarationVisitor::MakeCommonBlockSymbol(const parser::Name &name) {
return Resolve(name, currScope().MakeCommonBlock(name.source));
Symbol &DeclarationVisitor::MakeCommonBlockSymbol(
const parser::Name &name, SourceName location) {
return Resolve(name, currScope().MakeCommonBlock(name.source, location));
}
Symbol &DeclarationVisitor::MakeCommonBlockSymbol(
const std::optional<parser::Name> &name) {
const std::optional<parser::Name> &name, SourceName location) {
if (name) {
return MakeCommonBlockSymbol(*name);
return MakeCommonBlockSymbol(*name, location);
} else {
return MakeCommonBlockSymbol(parser::Name{});
return MakeCommonBlockSymbol(parser::Name{}, location);
}
}

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

// Check if this derived type can be in a COMMON block.
void DeclarationVisitor::CheckCommonBlockDerivedType(const SourceName &name,
const Symbol &typeSymbol, UnorderedSymbolSet &typeSet) {
if (auto iter{typeSet.find(SymbolRef{typeSymbol})}; iter != typeSet.end()) {
return;
}
typeSet.emplace(typeSymbol);
if (const auto *scope{typeSymbol.scope()}) {
for (const auto &pair : *scope) {
const Symbol &component{*pair.second};
if (component.attrs().test(Attr::ALLOCATABLE)) {
Say2(name,
"Derived type variable '%s' may not appear in a COMMON block"
" due to ALLOCATABLE component"_err_en_US,
component.name(), "Component with ALLOCATABLE attribute"_en_US);
return;
}
const auto *details{component.detailsIf<ObjectEntityDetails>()};
if (component.test(Symbol::Flag::InDataStmt) ||
(details && details->init())) {
Say2(name,
"Derived type variable '%s' may not appear in a COMMON block due to component with default initialization"_err_en_US,
component.name(), "Component with default initialization"_en_US);
return;
}
if (details) {
if (const auto *type{details->type()}) {
if (const auto *derived{type->AsDerived()}) {
const Symbol &derivedTypeSymbol{derived->typeSymbol()};
CheckCommonBlockDerivedType(name, derivedTypeSymbol, typeSet);
}
}
}
}
}
}

bool DeclarationVisitor::HandleUnrestrictedSpecificIntrinsicFunction(
const parser::Name &name) {
if (auto interface{context().intrinsics().IsSpecificIntrinsicFunction(
Expand Down Expand Up @@ -9598,7 +9523,7 @@ void ResolveNamesVisitor::CreateCommonBlockSymbols(
const parser::CommonStmt &commonStmt) {
for (const parser::CommonStmt::Block &block : commonStmt.blocks) {
const auto &[name, objects] = block.t;
Symbol &commonBlock{MakeCommonBlockSymbol(name)};
Symbol &commonBlock{MakeCommonBlockSymbol(name, commonStmt.source)};
for (const auto &object : objects) {
Symbol &obj{DeclareObjectEntity(std::get<parser::Name>(object.t))};
if (auto *details{obj.detailsIf<ObjectEntityDetails>()}) {
Expand Down
Loading