55cb1ac4db
When a StmtFunctionStmt was rewritten as an array element assignment the subscripts were not getting correct source locations. They need to be copied from the function args. Also, the entire array element expression (e.g. `a(i)`) did not have a source position. This was tricky because there is no source position in the original parse that matches what we need. So we take the source position from the beginning of the function name to the end of the last arg and extend it one more character to include the closing parenthesis. Change `ActualArgToExpr()` to return `Expr` rather than `std::optional<Expr>` because callers always call `.value()` on the result anyway. Add `WithSource()` utility to update the `source` data member of a parse tree node. This bug shows up as incorrect source positions for error messages. For example, in this program the error (due to real subscript) did not have a source position: ``` real :: a(10), x, y a(x) = y end ``` Original-commit: flang-compiler/f18@a9bcf68ceb Reviewed-on: https://github.com/flang-compiler/f18/pull/433
197 lines
7 KiB
C++
197 lines
7 KiB
C++
// Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "parse-tree.h"
|
|
#include "user-state.h"
|
|
#include "../common/idioms.h"
|
|
#include "../common/indirection.h"
|
|
#include <algorithm>
|
|
|
|
// So "delete Expr;" calls an external destructor for its typedExpr.
|
|
namespace Fortran::evaluate {
|
|
struct GenericExprWrapper {
|
|
~GenericExprWrapper();
|
|
};
|
|
}
|
|
|
|
namespace Fortran::parser {
|
|
|
|
// R867
|
|
ImportStmt::ImportStmt(common::ImportKind &&k, std::list<Name> &&n)
|
|
: kind{k}, names(std::move(n)) {
|
|
CHECK(kind == common::ImportKind::Default ||
|
|
kind == common::ImportKind::Only || names.empty());
|
|
}
|
|
|
|
// R873
|
|
CommonStmt::CommonStmt(std::optional<Name> &&name,
|
|
std::list<CommonBlockObject> &&objects, std::list<Block> &&others) {
|
|
blocks.emplace_front(std::move(name), std::move(objects));
|
|
blocks.splice(blocks.end(), std::move(others));
|
|
}
|
|
|
|
// R901 designator
|
|
bool Designator::EndsInBareName() const {
|
|
return std::visit(
|
|
common::visitors{
|
|
[](const DataRef &dr) {
|
|
return std::holds_alternative<Name>(dr.u) ||
|
|
std::holds_alternative<common::Indirection<StructureComponent>>(
|
|
dr.u);
|
|
},
|
|
[](const Substring &) { return false; },
|
|
},
|
|
u);
|
|
}
|
|
|
|
// R911 data-ref -> part-ref [% part-ref]...
|
|
DataRef::DataRef(std::list<PartRef> &&prl) : u{std::move(prl.front().name)} {
|
|
for (bool first{true}; !prl.empty(); first = false, prl.pop_front()) {
|
|
PartRef &pr{prl.front()};
|
|
if (!first) {
|
|
u = common::Indirection<StructureComponent>::Make(
|
|
std::move(*this), std::move(pr.name));
|
|
}
|
|
if (!pr.subscripts.empty()) {
|
|
u = common::Indirection<ArrayElement>::Make(
|
|
std::move(*this), std::move(pr.subscripts));
|
|
}
|
|
if (pr.imageSelector.has_value()) {
|
|
u = common::Indirection<CoindexedNamedObject>::Make(
|
|
std::move(*this), std::move(*pr.imageSelector));
|
|
}
|
|
}
|
|
}
|
|
|
|
// R1001 - R1022 expression
|
|
Expr::Expr(Designator &&x)
|
|
: u{common::Indirection<Designator>::Make(std::move(x))} {}
|
|
Expr::Expr(FunctionReference &&x)
|
|
: u{common::Indirection<FunctionReference>::Make(std::move(x))} {}
|
|
|
|
bool DoConstruct::IsDoConcurrent() const {
|
|
auto &doStmt{std::get<Statement<NonLabelDoStmt>>(t).statement};
|
|
auto &control{std::get<std::optional<LoopControl>>(doStmt.t)};
|
|
return control && std::holds_alternative<LoopControl::Concurrent>(control->u);
|
|
}
|
|
|
|
static Designator MakeArrayElementRef(
|
|
const Name &name, std::list<Expr> &&subscripts) {
|
|
ArrayElement arrayElement{DataRef{Name{name}}, std::list<SectionSubscript>{}};
|
|
for (Expr &expr : subscripts) {
|
|
arrayElement.subscripts.push_back(SectionSubscript{
|
|
Scalar{Integer{common::Indirection{std::move(expr)}}}});
|
|
}
|
|
return Designator{DataRef{common::Indirection{std::move(arrayElement)}}};
|
|
}
|
|
|
|
// Set source in any type of node that has it.
|
|
template<typename T> T WithSource(CharBlock source, T &&x) {
|
|
x.source = source;
|
|
return std::move(x);
|
|
}
|
|
|
|
static Expr ActualArgToExpr(ActualArgSpec &arg) {
|
|
return std::visit(
|
|
common::visitors{
|
|
[&](common::Indirection<Expr> &y) { return std::move(y.value()); },
|
|
[&](common::Indirection<Variable> &y) {
|
|
return std::visit(
|
|
common::visitors{
|
|
[&](common::Indirection<Designator> &z) {
|
|
return WithSource(
|
|
z.value().source, Expr{std::move(z.value())});
|
|
},
|
|
[&](common::Indirection<FunctionReference> &z) {
|
|
return WithSource(
|
|
z.value().v.source, Expr{std::move(z.value())});
|
|
},
|
|
},
|
|
y.value().u);
|
|
},
|
|
[&](auto &) -> Expr { common::die("unexpected type"); },
|
|
},
|
|
std::get<ActualArg>(arg.t).u);
|
|
}
|
|
|
|
Designator FunctionReference::ConvertToArrayElementRef() {
|
|
auto &name{std::get<parser::Name>(std::get<ProcedureDesignator>(v.t).u)};
|
|
std::list<Expr> args;
|
|
for (auto &arg : std::get<std::list<ActualArgSpec>>(v.t)) {
|
|
args.emplace_back(ActualArgToExpr(arg));
|
|
}
|
|
return WithSource(v.source, MakeArrayElementRef(name, std::move(args)));
|
|
}
|
|
|
|
StructureConstructor FunctionReference::ConvertToStructureConstructor(
|
|
const semantics::DerivedTypeSpec &derived) {
|
|
Name name{std::get<parser::Name>(std::get<ProcedureDesignator>(v.t).u)};
|
|
std::list<ComponentSpec> components;
|
|
for (auto &arg : std::get<std::list<ActualArgSpec>>(v.t)) {
|
|
std::optional<Keyword> keyword;
|
|
if (auto &kw{std::get<std::optional<Keyword>>(arg.t)}) {
|
|
keyword.emplace(Keyword{Name{kw->v}});
|
|
}
|
|
components.emplace_back(
|
|
std::move(keyword), ComponentDataSource{ActualArgToExpr(arg)});
|
|
}
|
|
DerivedTypeSpec spec{std::move(name), std::list<TypeParamSpec>{}};
|
|
spec.derivedTypeSpec = &derived;
|
|
return StructureConstructor{std::move(spec), std::move(components)};
|
|
}
|
|
|
|
Substring ArrayElement::ConvertToSubstring() {
|
|
auto iter{subscripts.begin()};
|
|
CHECK(iter != subscripts.end());
|
|
auto &triplet{std::get<SubscriptTriplet>(iter->u)};
|
|
SubstringRange range{
|
|
std::move(std::get<0>(triplet.t)), std::move(std::get<1>(triplet.t))};
|
|
CHECK(!std::get<2>(triplet.t).has_value());
|
|
CHECK(++iter == subscripts.end());
|
|
return Substring{std::move(base), std::move(range)};
|
|
}
|
|
|
|
// R1544 stmt-function-stmt
|
|
// Convert this stmt-function-stmt to an array element assignment statement.
|
|
Statement<ActionStmt> StmtFunctionStmt::ConvertToAssignment() {
|
|
auto &funcName{std::get<Name>(t)};
|
|
auto &funcArgs{std::get<std::list<Name>>(t)};
|
|
auto &funcExpr{std::get<Scalar<Expr>>(t).thing};
|
|
CharBlock source{funcName.source};
|
|
std::list<Expr> subscripts;
|
|
for (Name &arg : funcArgs) {
|
|
subscripts.push_back(WithSource(arg.source,
|
|
Expr{common::Indirection{
|
|
WithSource(arg.source, Designator{DataRef{Name{arg}}})}}));
|
|
source.ExtendToCover(arg.source);
|
|
}
|
|
// extend source to include closing paren
|
|
CHECK(*source.end() == ')');
|
|
source = CharBlock{source.begin(), source.end() + 1};
|
|
auto variable{Variable{common::Indirection{WithSource(
|
|
source, MakeArrayElementRef(funcName, std::move(subscripts)))}}};
|
|
return Statement{std::nullopt,
|
|
ActionStmt{common::Indirection{
|
|
AssignmentStmt{std::move(variable), std::move(funcExpr)}}}};
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &os, const Name &x) {
|
|
return os << x.ToString();
|
|
}
|
|
std::ostream &operator<<(std::ostream &os, const CharBlock &x) {
|
|
return os << x.ToString();
|
|
}
|
|
}
|
|
|
|
template class std::unique_ptr<Fortran::evaluate::GenericExprWrapper>;
|