Skip to content

Commit

Permalink
[flang] Fix crash in error recovery
Browse files Browse the repository at this point in the history
EQUIVALENCE set processing assumes that any arrays have explicit
shape and constant lower bounds.  When an erroneous program
violates those assumptions, the compiler crashes.  Fix.

Fixes #92636.
  • Loading branch information
klausler committed May 20, 2024
1 parent ab7930b commit e326918
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 20 deletions.
1 change: 1 addition & 0 deletions flang/include/flang/Semantics/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,7 @@ class Symbol {
void SetIsExplicitBindName(bool);
bool IsFuncResult() const;
bool IsObjectArray() const;
const ArraySpec *GetShape() const;
bool IsSubprogram() const;
bool IsFromModFile() const;
bool HasExplicitInterface() const {
Expand Down
44 changes: 27 additions & 17 deletions flang/lib/Semantics/resolve-names-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,25 +376,35 @@ static void PropagateSaveAttr(const EquivalenceSet &src, EquivalenceSet &dst) {

void EquivalenceSets::AddToSet(const parser::Designator &designator) {
if (CheckDesignator(designator)) {
Symbol &symbol{*currObject_.symbol};
if (!currSet_.empty()) {
// check this symbol against first of set for compatibility
Symbol &first{currSet_.front().symbol};
CheckCanEquivalence(designator.source, first, symbol) &&
CheckCanEquivalence(designator.source, symbol, first);
}
auto subscripts{currObject_.subscripts};
if (subscripts.empty() && symbol.IsObjectArray()) {
// record a whole array as its first element
for (const ShapeSpec &spec : symbol.get<ObjectEntityDetails>().shape()) {
auto &lbound{spec.lbound().GetExplicit().value()};
subscripts.push_back(evaluate::ToInt64(lbound).value());
if (Symbol * symbol{currObject_.symbol}) {
if (!currSet_.empty()) {
// check this symbol against first of set for compatibility
Symbol &first{currSet_.front().symbol};
CheckCanEquivalence(designator.source, first, *symbol) &&
CheckCanEquivalence(designator.source, *symbol, first);
}
auto subscripts{currObject_.subscripts};
if (subscripts.empty()) {
if (const ArraySpec * shape{symbol->GetShape()};
shape && shape->IsExplicitShape()) {
// record a whole array as its first element
for (const ShapeSpec &spec : *shape) {
if (auto lbound{spec.lbound().GetExplicit()}) {
if (auto lbValue{evaluate::ToInt64(*lbound)}) {
subscripts.push_back(*lbValue);
continue;
}
}
subscripts.clear(); // error recovery
break;
}
}
}
auto substringStart{currObject_.substringStart};
currSet_.emplace_back(
*symbol, subscripts, substringStart, designator.source);
PropagateSaveAttr(currSet_.back(), currSet_);
}
auto substringStart{currObject_.substringStart};
currSet_.emplace_back(
symbol, subscripts, substringStart, designator.source);
PropagateSaveAttr(currSet_.back(), currSet_);
}
currObject_ = {};
}
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6227,7 +6227,7 @@ void DeclarationVisitor::CheckEquivalenceSets() {
}
for (const parser::EquivalenceObject &object : *set) {
const auto &designator{object.v.value()};
// The designator was not resolved when it was encountered so do it now.
// The designator was not resolved when it was encountered, so do it now.
// AnalyzeExpr causes array sections to be changed to substrings as needed
Walk(designator);
if (AnalyzeExpr(context(), designator)) {
Expand Down
12 changes: 10 additions & 2 deletions flang/lib/Semantics/symbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,17 @@ bool Symbol::IsFuncResult() const {
details_);
}

const ArraySpec *Symbol::GetShape() const {
if (const auto *details{std::get_if<ObjectEntityDetails>(&details_)}) {
return &details->shape();
} else {
return nullptr;
}
}

bool Symbol::IsObjectArray() const {
const auto *details{std::get_if<ObjectEntityDetails>(&details_)};
return details && details->IsArray();
const ArraySpec *shape{GetShape()};
return shape && !shape->empty();
}

bool Symbol::IsSubprogram() const {
Expand Down

0 comments on commit e326918

Please sign in to comment.