[flang] checkpoint once everything builds again

Original-commit: flang-compiler/f18@2075b88772
Reviewed-on: https://github.com/flang-compiler/f18/pull/144
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-07-11 14:50:08 -07:00
parent 6c4773012c
commit f24cd7dd2d
5 changed files with 240 additions and 72 deletions

View File

@ -61,15 +61,17 @@ std::ostream &Unary<A>::Dump(std::ostream &o, const char *opr) const {
}
template<typename A, typename B>
std::ostream &Binary<A, B>::Dump(std::ostream &o, const char *opr) const {
return y->Dump(x->Dump(o << '(') << opr) << ')';
std::ostream &Binary<A, B>::Dump(
std::ostream &o, const char *opr, const char *before) const {
return y->Dump(x->Dump(o << before) << opr) << ')';
}
template<int KIND>
std::ostream &Expr<Category::Integer, KIND>::Dump(std::ostream &o) const {
std::visit(
common::visitors{[&](const Constant &n) { o << n.SignedDecimal(); },
[&](const CopyableIndirection<Designator> &d) { d->Dump(o); },
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Parentheses &p) { p.Dump(o, "("); },
[&](const Negate &n) { n.Dump(o, "(-"); },
[&](const Add &a) { a.Dump(o, "+"); },
@ -77,6 +79,8 @@ std::ostream &Expr<Category::Integer, KIND>::Dump(std::ostream &o) const {
[&](const Multiply &m) { m.Dump(o, "*"); },
[&](const Divide &d) { d.Dump(o, "/"); },
[&](const Power &p) { p.Dump(o, "**"); },
[&](const Max &m) { m.Dump(o, ",", "MAX("); },
[&](const Min &m) { m.Dump(o, ",", "MIN("); },
[&](const auto &convert) { DumpExprWithType(o, convert.x->u); }},
u);
return o;
@ -86,6 +90,9 @@ template<int KIND>
std::ostream &Expr<Category::Real, KIND>::Dump(std::ostream &o) const {
std::visit(
common::visitors{[&](const Constant &n) { o << n.DumpHexadecimal(); },
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<ComplexPart> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Parentheses &p) { p.Dump(o, "("); },
[&](const Negate &n) { n.Dump(o, "(-"); },
[&](const Add &a) { a.Dump(o, "+"); },
@ -94,6 +101,8 @@ std::ostream &Expr<Category::Real, KIND>::Dump(std::ostream &o) const {
[&](const Divide &d) { d.Dump(o, "/"); },
[&](const Power &p) { p.Dump(o, "**"); },
[&](const IntPower &p) { p.Dump(o, "**"); },
[&](const Max &m) { m.Dump(o, ",", "MAX("); },
[&](const Min &m) { m.Dump(o, ",", "MIN("); },
[&](const RealPart &z) { z.Dump(o, "REAL("); },
[&](const AIMAG &p) { p.Dump(o, "AIMAG("); },
[&](const auto &convert) { DumpExprWithType(o, convert.x->u); }},
@ -105,6 +114,8 @@ template<int KIND>
std::ostream &Expr<Category::Complex, KIND>::Dump(std::ostream &o) const {
std::visit(
common::visitors{[&](const Constant &n) { o << n.DumpHexadecimal(); },
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Parentheses &p) { p.Dump(o, "("); },
[&](const Negate &n) { n.Dump(o, "(-"); },
[&](const Add &a) { a.Dump(o, "+"); },
@ -123,9 +134,10 @@ std::ostream &Expr<Category::Character, KIND>::Dump(std::ostream &o) const {
std::visit(common::visitors{[&](const Constant &s) {
o << parser::QuoteCharacterLiteral(s);
},
[&](const auto &concat) {
concat.y->Dump(concat.x->Dump(o) << "//");
}},
[&](const Concat &concat) { concat.Dump(o, "//"); },
[&](const Max &m) { m.Dump(o, ",", "MAX("); },
[&](const Min &m) { m.Dump(o, ",", "MIN("); },
[&](const auto &ind) { ind->Dump(o); }},
u);
return o;
}
@ -141,6 +153,8 @@ template<typename A> std::ostream &Comparison<A>::Dump(std::ostream &o) const {
std::ostream &Expr<Category::Logical, 1>::Dump(std::ostream &o) const {
std::visit(
common::visitors{[&](const bool &tf) { o << (tf ? ".T." : ".F."); },
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Not &n) { n.Dump(o, "(.NOT."); },
[&](const And &a) { a.Dump(o, ".AND."); },
[&](const Or &a) { a.Dump(o, ".OR."); },
@ -151,6 +165,28 @@ std::ostream &Expr<Category::Logical, 1>::Dump(std::ostream &o) const {
return o;
}
template<int KIND>
SubscriptIntegerExpr Expr<Category::Character, KIND>::LEN() const {
return std::visit(
common::visitors{
[](const Constant &c) { return SubscriptIntegerExpr{c.size()}; },
[](const Concat &c) { return c.x->LEN() + c.y->LEN(); },
[](const Max &c) {
return SubscriptIntegerExpr{
SubscriptIntegerExpr::Max{c.x->LEN(), c.y->LEN()}};
},
[](const Min &c) {
return SubscriptIntegerExpr{
SubscriptIntegerExpr::Max{c.x->LEN(), c.y->LEN()}};
},
[](const CopyableIndirection<DataRef> &dr) { return dr->LEN(); },
[](const CopyableIndirection<Substring> &ss) { return ss->LEN(); },
[](const CopyableIndirection<FunctionRef> &fr) {
return fr->proc.LEN();
}},
u);
}
template<int KIND>
void Expr<Category::Integer, KIND>::Fold(FoldingContext &context) {
std::visit(common::visitors{[&](Parentheses &p) {
@ -208,24 +244,6 @@ void Expr<Category::Integer, KIND>::Fold(FoldingContext &context) {
u);
}
template<int KIND>
typename CharacterExpr<KIND>::LengthExpr CharacterExpr<KIND>::LEN() const {
// Written thus, instead of with common::visitors{}, to dodge a
// bug in g++ 7.2.0 that failed to direct the std::string case to its
// specific alternative.
return std::visit(
[](const auto &x) {
if constexpr (std::is_same_v<
const typename CharacterExpr<KIND>::Constant &,
decltype(x)>) {
return LengthExpr{static_cast<std::uint64_t>(x.size())};
} else {
return LengthExpr{LengthExpr::Add{x.x->LEN(), x.y->LEN()}};
}
},
u);
}
template struct Expr<Category::Integer, 1>;
template struct Expr<Category::Integer, 2>;
template struct Expr<Category::Integer, 4>;

View File

@ -20,7 +20,6 @@
// context-independent hash table or sharing of common subexpressions.
// Both deep copy and move semantics are supported for expression construction
// and manipulation in place.
// TODO: elevate some intrinsics to operations
// TODO: convenience wrappers for constructing conversions
#include "common.h"
@ -57,7 +56,8 @@ template<typename A, typename B = A> struct Binary {
Binary(CopyableIndirection<const A> &&a, CopyableIndirection<const B> &&b)
: x{std::move(a)}, y{std::move(b)} {}
Binary(A &&a, B &&b) : x{std::move(a)}, y{std::move(b)} {}
std::ostream &Dump(std::ostream &, const char *opr) const;
std::ostream &Dump(
std::ostream &, const char *opr, const char *before = "(") const;
CopyableIndirection<A> x;
CopyableIndirection<B> y;
};
@ -91,6 +91,12 @@ template<int KIND> struct Expr<Category::Integer, KIND> {
struct Power : public Bin {
using Bin::Bin;
};
struct Max : public Bin {
using Bin::Bin;
};
struct Min : public Bin {
using Bin::Bin;
};
// TODO: R916 type-param-inquiry
CLASS_BOILERPLATE(Expr)
@ -110,13 +116,14 @@ template<int KIND> struct Expr<Category::Integer, KIND> {
(std::is_base_of_v<Un, A> || std::is_base_of_v<Bin, A>),
A> &&x)
: u(std::move(x)) {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u{std::move(x)} {}
void Fold(FoldingContext &);
// TODO: function reference
std::variant<Constant, CopyableIndirection<Designator>,
Convert<GenericIntegerExpr>, Convert<GenericRealExpr>, Parentheses,
Negate, Add, Subtract, Multiply, Divide, Power>
std::variant<Constant, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>, Convert<GenericIntegerExpr>,
Convert<GenericRealExpr>, Parentheses, Negate, Add, Subtract, Multiply,
Divide, Power, Max, Min>
u;
};
@ -155,6 +162,12 @@ template<int KIND> struct Expr<Category::Real, KIND> {
struct IntPower : public Binary<Expr, GenericIntegerExpr> {
using Binary<Expr, GenericIntegerExpr>::Binary;
};
struct Max : public Bin {
using Bin::Bin;
};
struct Min : public Bin {
using Bin::Bin;
};
using CplxUn = Unary<ComplexExpr<KIND>>;
struct RealPart : public CplxUn {
using CplxUn::CplxUn;
@ -174,10 +187,12 @@ template<int KIND> struct Expr<Category::Real, KIND> {
template<typename A> Expr(const A &x) : u{x} {}
template<typename A>
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u{std::move(x)} {}
// TODO: designators, function references
std::variant<Constant, Convert<GenericIntegerExpr>, Convert<GenericRealExpr>,
Parentheses, Negate, Add, Subtract, Multiply, Divide, Power, IntPower,
std::variant<Constant, CopyableIndirection<DataRef>,
CopyableIndirection<ComplexPart>, CopyableIndirection<FunctionRef>,
Convert<GenericIntegerExpr>, Convert<GenericRealExpr>, Parentheses,
Negate, Add, Subtract, Multiply, Divide, Power, IntPower, Max, Min,
RealPart, AIMAG>
u;
};
@ -220,28 +235,42 @@ template<int KIND> struct Expr<Category::Complex, KIND> {
template<typename A> Expr(const A &x) : u{x} {}
template<typename A>
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u{std::move(x)} {}
// TODO: designators, function references
std::variant<Constant, Parentheses, Negate, Add, Subtract, Multiply, Divide,
Power, IntPower, CMPLX>
std::variant<Constant, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>, Parentheses, Negate, Add, Subtract,
Multiply, Divide, Power, IntPower, CMPLX>
u;
};
template<int KIND> struct Expr<Category::Character, KIND> {
using Result = Type<Category::Character, KIND>;
using Constant = typename Result::Value;
using LengthExpr = IntegerExpr<IntrinsicTypeParameterType::kind>;
using Bin = Binary<Expr>;
struct Concat : public Bin {
using Bin::Bin;
};
struct Max : public Bin {
using Bin::Bin;
};
struct Min : public Bin {
using Bin::Bin;
};
CLASS_BOILERPLATE(Expr)
Expr(const Constant &x) : u{x} {}
Expr(Constant &&x) : u{std::move(x)} {}
Expr(const Expr &x, const Expr &y) : u{Binary<Expr>{x, y}} {}
Expr(Expr &&x, Expr &&y) : u{Binary<Expr>{std::move(x), std::move(y)}} {}
template<typename A> Expr(const A &x) : u{x} {}
template<typename A>
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u{std::move(x)} {}
LengthExpr LEN() const;
SubscriptIntegerExpr LEN() const;
// TODO: designators, function references
std::variant<Constant, Binary<Expr>> u;
std::variant<Constant, CopyableIndirection<DataRef>,
CopyableIndirection<Substring>, CopyableIndirection<FunctionRef>, Concat,
Max, Min>
u;
};
// The Comparison class template is a helper for constructing logical
@ -317,9 +346,10 @@ template<> struct Expr<Category::Logical, 1> {
template<typename A> Expr(const A &x) : u(x) {}
template<typename A>
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u{std::move(x)} {}
// TODO: designators, function references
std::variant<Constant, Not, And, Or, Eqv, Neqv,
std::variant<Constant, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>, Not, And, Or, Eqv, Neqv,
CategoryComparison<Category::Integer>, CategoryComparison<Category::Real>,
CategoryComparison<Category::Complex>,
CategoryComparison<Category::Character>>

View File

@ -0,0 +1,25 @@
// Copyright (c) 2018, 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.
#ifndef FORTRAN_EVALUATE_INTRINSICS_H_
#define FORTRAN_EVALUATE_INTRINSICS_H_
#include "../common/idioms.h"
namespace Fortran::evaluate {
ENUM_CLASS(IntrinsicProcedure, LEN, MAX, MIN)
} // namespace Fortran::evaluate
#endif // FORTRAN_EVALUATE_INTRINSICS_H_

View File

@ -25,13 +25,13 @@ Triplet::Triplet(std::optional<SubscriptIntegerExpr> &&l,
std::optional<SubscriptIntegerExpr> &&u,
std::optional<SubscriptIntegerExpr> &&s) {
if (l.has_value()) {
lower = SubscriptIntegerExpr{std::move(*l)};
lower = IndirectSubscriptIntegerExpr::Make(std::move(*l));
}
if (u.has_value()) {
upper = SubscriptIntegerExpr{std::move(*u)};
upper = IndirectSubscriptIntegerExpr::Make(std::move(*u));
}
if (s.has_value()) {
stride = SubscriptIntegerExpr{std::move(*s)};
stride = IndirectSubscriptIntegerExpr::Make(std::move(*s));
}
}
@ -88,6 +88,10 @@ template<> std::ostream &Emit(std::ostream &o, const Symbol &symbol) {
return o << symbol.name().ToString();
}
template<> std::ostream &Emit(std::ostream &o, const IntrinsicProcedure &p) {
return o << EnumToString(p);
}
std::ostream &Component::Dump(std::ostream &o) const {
base->Dump(o);
return Emit(o << '%', sym);
@ -119,7 +123,7 @@ std::ostream &CoarrayRef::Dump(std::ostream &o) const {
Emit(o, *sym);
}
char separator{'('};
for (const SubscriptIntegerExpr &ss : subscript) {
for (const auto &ss : subscript) {
Emit(o << separator, ss);
separator = ',';
}
@ -127,7 +131,7 @@ std::ostream &CoarrayRef::Dump(std::ostream &o) const {
o << ')';
}
separator = '[';
for (const SubscriptIntegerExpr &css : cosubscript) {
for (const auto &css : cosubscript) {
Emit(o << separator, css);
separator = ',';
}
@ -185,4 +189,85 @@ std::ostream &ActualSubroutineArg::Dump(std::ostream &o) const {
std::ostream &Label::Dump(std::ostream &o) const {
return o << '*' << std::dec << label;
}
CoarrayRef::CoarrayRef(std::vector<const Symbol *> &&c,
std::vector<SubscriptIntegerExpr> &&ss,
std::vector<SubscriptIntegerExpr> &&css)
: base(std::move(c)), subscript(std::move(ss)), cosubscript(std::move(css)) {
CHECK(!base.empty());
}
Substring::Substring(DataRef &&d, std::optional<SubscriptIntegerExpr> &&f,
std::optional<SubscriptIntegerExpr> &&l)
: u{std::move(d)} {
if (f.has_value()) {
first = IndirectSubscriptIntegerExpr::Make(std::move(*f));
}
if (l.has_value()) {
last = IndirectSubscriptIntegerExpr::Make(std::move(*l));
}
}
Substring::Substring(std::string &&s, std::optional<SubscriptIntegerExpr> &&f,
std::optional<SubscriptIntegerExpr> &&l)
: u{std::move(s)} {
if (f.has_value()) {
first = IndirectSubscriptIntegerExpr::Make(std::move(*f));
}
if (l.has_value()) {
last = IndirectSubscriptIntegerExpr::Make(std::move(*l));
}
}
SubscriptIntegerExpr Substring::First() const {
if (first.has_value()) {
return **first;
}
return {1};
}
SubscriptIntegerExpr Substring::Last() const {
if (last.has_value()) {
return **last;
}
return std::visit(common::visitors{[](const std::string &s) {
return SubscriptIntegerExpr{s.size()};
},
[](const DataRef &x) { return x.LEN(); }},
u);
}
// LEN()
static SubscriptIntegerExpr SymbolLEN(const Symbol *sym) {
return SubscriptIntegerExpr{0}; // TODO
}
SubscriptIntegerExpr Component::LEN() const { return SymbolLEN(sym); }
SubscriptIntegerExpr ArrayRef::LEN() const {
return std::visit(
common::visitors{[](const Symbol *s) { return SymbolLEN(s); },
[](const Component &x) { return x.LEN(); }},
u);
}
SubscriptIntegerExpr CoarrayRef::LEN() const { return SymbolLEN(base.back()); }
SubscriptIntegerExpr DataRef::LEN() const {
return std::visit(
common::visitors{[](const Symbol *s) { return SymbolLEN(s); },
[](const auto &x) { return x.LEN(); }},
u);
}
SubscriptIntegerExpr Substring::LEN() const {
return SubscriptIntegerExpr::Max{
SubscriptIntegerExpr{0}, Last() - First() + SubscriptIntegerExpr{1}};
}
SubscriptIntegerExpr ProcedureDesignator::LEN() const {
return std::visit(
common::visitors{[](const Symbol *s) { return SymbolLEN(s); },
[](const Component &c) { return c.LEN(); },
[](const auto &) {
CRASH_NO_CASE;
return SubscriptIntegerExpr{0};
}},
u);
}
} // namespace Fortran::evaluate

View File

@ -23,6 +23,7 @@
#include "common.h"
#include "expression-forward.h"
#include "intrinsics.h"
#include "../common/idioms.h"
#include "../semantics/symbol.h"
#include <optional>
@ -41,8 +42,8 @@ struct ActualFunctionArg;
// Subscript and cosubscript expressions are of a kind that matches the
// address size, at least at the top level.
using SubscriptIntegerExpr =
CopyableIndirection<IntegerExpr<SubscriptInteger::kind>>;
using SubscriptIntegerExpr = IntegerExpr<SubscriptInteger::kind>;
using IndirectSubscriptIntegerExpr = CopyableIndirection<SubscriptIntegerExpr>;
// R913 structure-component & C920: Defined to be a multi-part
// data-ref whose last part has no subscripts (or image-selector, although
@ -54,6 +55,7 @@ struct Component {
Component(const DataRef &b, const Symbol &c) : base{b}, sym{&c} {}
Component(CopyableIndirection<DataRef> &&b, const Symbol &c)
: base{std::move(b)}, sym{&c} {}
SubscriptIntegerExpr LEN() const;
CopyableIndirection<DataRef> base;
const Symbol *sym;
};
@ -64,17 +66,19 @@ struct Triplet {
Triplet(std::optional<SubscriptIntegerExpr> &&,
std::optional<SubscriptIntegerExpr> &&,
std::optional<SubscriptIntegerExpr> &&);
std::optional<SubscriptIntegerExpr> lower, upper, stride;
std::optional<IndirectSubscriptIntegerExpr> lower, upper, stride;
};
// R919 subscript when rank 0, R923 vector-subscript when rank 1
struct Subscript {
CLASS_BOILERPLATE(Subscript)
explicit Subscript(const SubscriptIntegerExpr &s) : u{s} {}
explicit Subscript(SubscriptIntegerExpr &&s) : u{std::move(s)} {}
explicit Subscript(const SubscriptIntegerExpr &s)
: u{IndirectSubscriptIntegerExpr::Make(s)} {}
explicit Subscript(SubscriptIntegerExpr &&s)
: u{IndirectSubscriptIntegerExpr::Make(std::move(s))} {}
explicit Subscript(const Triplet &t) : u{t} {}
explicit Subscript(Triplet &&t) : u{std::move(t)} {}
std::variant<SubscriptIntegerExpr, Triplet> u;
std::variant<IndirectSubscriptIntegerExpr, Triplet> u;
};
// R917 array-element, R918 array-section; however, the case of an
@ -88,6 +92,7 @@ struct ArrayRef {
: u{&n}, subscript(std::move(ss)) {}
ArrayRef(Component &&c, std::vector<Subscript> &&ss)
: u{std::move(c)}, subscript(std::move(ss)) {}
SubscriptIntegerExpr LEN() const;
std::variant<const Symbol *, Component> u;
std::vector<Subscript> subscript;
};
@ -101,11 +106,10 @@ struct ArrayRef {
// TODO C931 prohibits the use of a coindexed object as a stat-variable.
struct CoarrayRef {
CLASS_BOILERPLATE(CoarrayRef)
CoarrayRef(std::vector<const Symbol *> &&c,
std::vector<SubscriptIntegerExpr> &&ss,
std::vector<SubscriptIntegerExpr> &&css)
: base(std::move(c)), subscript(std::move(ss)),
cosubscript(std::move(css)) {}
CoarrayRef(std::vector<const Symbol *> &&,
std::vector<SubscriptIntegerExpr> &&,
std::vector<SubscriptIntegerExpr> &&); // TODO: stat & team?
SubscriptIntegerExpr LEN() const;
std::vector<const Symbol *> base;
std::vector<SubscriptIntegerExpr> subscript, cosubscript;
std::optional<CopyableIndirection<Variable>> stat, team;
@ -113,16 +117,17 @@ struct CoarrayRef {
};
// R911 data-ref is defined syntactically as a series of part-refs, which
// is far too expressive if the constraints are ignored. Here, the possible
// outcomes are spelled out. Note that a data-ref cannot include a terminal
// substring range or complex component designator; use R901 designator
// for that.
// would be far too expressive if the constraints were ignored. Here, the
// possible outcomes are spelled out. Note that a data-ref cannot include
// a terminal substring range or complex component designator; use
// R901 designator for that.
struct DataRef {
CLASS_BOILERPLATE(DataRef)
explicit DataRef(const Symbol &n) : u{&n} {}
explicit DataRef(Component &&c) : u{std::move(c)} {}
explicit DataRef(ArrayRef &&a) : u{std::move(a)} {}
explicit DataRef(CoarrayRef &&a) : u{std::move(a)} {}
SubscriptIntegerExpr LEN() const;
std::variant<const Symbol *, Component, ArrayRef, CoarrayRef> u;
};
@ -132,14 +137,17 @@ struct DataRef {
// variants of sections instead.
struct Substring {
CLASS_BOILERPLATE(Substring)
Substring(DataRef &&d, std::optional<SubscriptIntegerExpr> &&f,
std::optional<SubscriptIntegerExpr> &&l)
: u{std::move(d)}, first{std::move(f)}, last{std::move(l)} {}
Substring(std::string &&s, std::optional<SubscriptIntegerExpr> &&f,
std::optional<SubscriptIntegerExpr> &&l)
: u{std::move(s)}, first{std::move(f)}, last{std::move(l)} {}
Substring(DataRef &&, std::optional<SubscriptIntegerExpr> &&,
std::optional<SubscriptIntegerExpr> &&);
Substring(std::string &&, std::optional<SubscriptIntegerExpr> &&,
std::optional<SubscriptIntegerExpr> &&);
SubscriptIntegerExpr First() const;
SubscriptIntegerExpr Last() const;
SubscriptIntegerExpr LEN() const;
std::variant<DataRef, std::string> u;
std::optional<SubscriptIntegerExpr> first, last;
std::optional<IndirectSubscriptIntegerExpr> first, last;
};
// R915 complex-part-designator
@ -165,10 +173,12 @@ struct Designator {
struct ProcedureDesignator {
CLASS_BOILERPLATE(ProcedureDesignator)
explicit ProcedureDesignator(IntrinsicProcedure p) : u{p} {}
explicit ProcedureDesignator(const Symbol &n) : u{&n} {}
explicit ProcedureDesignator(const Component &c) : u{c} {}
explicit ProcedureDesignator(Component &&c) : u{std::move(c)} {}
std::variant<const Symbol *, Component> u;
SubscriptIntegerExpr LEN() const;
std::variant<IntrinsicProcedure, const Symbol *, Component> u;
};
template<typename ARG> struct ProcedureRef {