#if __cplusplus < 201703L
#error this is a C++17 program
#endif
-#if !defined(__clang__) && defined __GNUC__ && __GNUC__ < 7
-#error g++ >= 7.3 is required
+#if !__clang__ && defined __GNUC__ && __GNUC__ < 7
+#error g++ >= 7.2 is required
#endif
#include <list>
// Intended to be as invisible as a reference, wherever possible.
#include "../common/idioms.h"
+#include <type_traits>
#include <utility>
namespace Fortran::common {
-template<typename A> class Indirection {
+// The default case does not support (deep) copy construction and assignment.
+template<typename A, bool COPY = false> class Indirection {
+public:
+ using element_type = A;
+ Indirection() = delete;
+ Indirection(A *&&p) : p_{p} {
+ CHECK(p_ && "assigning null pointer to Indirection");
+ p = nullptr;
+ }
+ Indirection(A &&x) : p_{new A(std::move(x))} {}
+ Indirection(Indirection &&that) : p_{that.p_} {
+ CHECK(p_ && "move construction of Indirection from null Indirection");
+ that.p_ = nullptr;
+ }
+ ~Indirection() {
+ delete p_;
+ p_ = nullptr;
+ }
+ Indirection &operator=(Indirection &&that) {
+ CHECK(that.p_ && "move assignment of null Indirection to Indirection");
+ auto tmp = p_;
+ p_ = that.p_;
+ that.p_ = tmp;
+ return *this;
+ }
+ A &operator*() { return *p_; }
+ const A &operator*() const { return *p_; }
+ A *operator->() { return p_; }
+ const A *operator->() const { return p_; }
+
+ template<typename... ARGS> static Indirection Make(ARGS &&... args) {
+ return {new A(std::forward<ARGS>(args)...)};
+ }
+
+private:
+ A *p_{nullptr};
+};
+
+// Variant with copy construction and assignment
+template<typename A> class Indirection<A, true> {
public:
using element_type = A;
Indirection() = delete;
#include "../common/enum-set.h"
#include "../common/idioms.h"
+#include "../common/indirection.h"
#include <cinttypes>
namespace Fortran::evaluate {
t &operator=(t &&) = default; \
std::ostream &Dump(std::ostream &) const;
+// Force availability of copy construction and assignment
+template<typename A> using CopyableIndirection = common::Indirection<A, true>;
+
} // namespace Fortran::evaluate
#endif // FORTRAN_EVALUATE_COMMON_H_
std::ostream &Expr<Category::Integer, KIND>::Dump(std::ostream &o) const {
std::visit(
common::visitors{[&](const Constant &n) { o << n.SignedDecimal(); },
- [&](const common::Indirection<Designator> &d) { d->Dump(o); },
+ [&](const CopyableIndirection<Designator> &d) { d->Dump(o); },
[&](const Parentheses &p) { p.Dump(o, "("); },
[&](const Negate &n) { n.Dump(o, "(-"); },
[&](const Add &a) { a.Dump(o, "+"); },
template<int KIND>
typename CharacterExpr<KIND>::LengthExpr CharacterExpr<KIND>::LEN() const {
- return std::visit(common::visitors{[](const std::string &str) {
- return LengthExpr{str.size()};
- },
- [](const auto &concat) {
- return LengthExpr{LengthExpr::Add{
- concat.x->LEN(), concat.y->LEN()}};
- }},
+ // 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{x.size()};
+ } else {
+ return LengthExpr{LengthExpr::Add{x.x->LEN(), x.y->LEN()}};
+ }
+ },
u);
}
#include "type.h"
#include "variable.h"
#include "../lib/common/idioms.h"
-#include "../lib/common/indirection.h"
#include "../lib/parser/char-block.h"
#include "../lib/parser/message.h"
#include <ostream>
template<typename A> struct Unary {
CLASS_BOILERPLATE(Unary)
Unary(const A &a) : x{a} {}
- Unary(common::Indirection<A> &&a) : x{std::move(a)} {}
+ Unary(CopyableIndirection<A> &&a) : x{std::move(a)} {}
Unary(A &&a) : x{std::move(a)} {}
std::ostream &Dump(std::ostream &, const char *opr) const;
- common::Indirection<A> x;
+ CopyableIndirection<A> x;
};
template<typename A, typename B = A> struct Binary {
CLASS_BOILERPLATE(Binary)
Binary(const A &a, const B &b) : x{a}, y{b} {}
- Binary(common::Indirection<const A> &&a, common::Indirection<const B> &&b)
+ 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;
- common::Indirection<A> x;
- common::Indirection<B> y;
+ CopyableIndirection<A> x;
+ CopyableIndirection<B> y;
};
template<int KIND> struct Expr<Category::Integer, KIND> {
void Fold(FoldingContext &);
// TODO: function reference
- std::variant<Constant, common::Indirection<Designator>,
+ std::variant<Constant, CopyableIndirection<Designator>,
Convert<GenericIntegerExpr>, Convert<GenericRealExpr>, Parentheses,
Negate, Add, Subtract, Multiply, Divide, Power>
u;
}
template<typename A>
-std::ostream &Emit(std::ostream &o, const common::Indirection<A> &p,
+std::ostream &Emit(std::ostream &o, const CopyableIndirection<A> &p,
const char *kw = nullptr) {
if (kw != nullptr) {
o << kw;
#include "common.h"
#include "expression-forward.h"
#include "../common/idioms.h"
-#include "../common/indirection.h"
#include "../semantics/symbol.h"
#include <optional>
#include <ostream>
// Subscript and cosubscript expressions are of a kind that matches the
// address size, at least at the top level.
using SubscriptIntegerExpr =
- common::Indirection<IntegerExpr<SubscriptInteger::kind>>;
+ CopyableIndirection<IntegerExpr<SubscriptInteger::kind>>;
// R913 structure-component & C920: Defined to be a multi-part
// data-ref whose last part has no subscripts (or image-selector, although
struct Component {
CLASS_BOILERPLATE(Component)
Component(const DataRef &b, const Symbol &c) : base{b}, sym{&c} {}
- Component(common::Indirection<DataRef> &&b, const Symbol &c)
+ Component(CopyableIndirection<DataRef> &&b, const Symbol &c)
: base{std::move(b)}, sym{&c} {}
- common::Indirection<DataRef> base;
+ CopyableIndirection<DataRef> base;
const Symbol *sym;
};
cosubscript(std::move(css)) {}
std::vector<const Symbol *> base;
std::vector<SubscriptIntegerExpr> subscript, cosubscript;
- std::optional<common::Indirection<Variable>> stat, team;
+ std::optional<CopyableIndirection<Variable>> stat, team;
bool teamIsTeamNumber{false}; // false: TEAM=, true: TEAM_NUMBER=
};
};
template<typename ARG> struct ProcedureRef {
- using ArgumentType = common::Indirection<ARG>;
+ using ArgumentType = CopyableIndirection<ARG>;
CLASS_BOILERPLATE(ProcedureRef)
ProcedureRef(ProcedureDesignator &&p, std::vector<ArgumentType> &&a)
: proc{std::move(p)}, argument(std::move(a)) {}
CLASS_BOILERPLATE(ActualFunctionArg)
explicit ActualFunctionArg(GenericExpr &&x) : u{std::move(x)} {}
explicit ActualFunctionArg(Variable &&x) : u{std::move(x)} {}
- std::variant<common::Indirection<GenericExpr>, Variable> u;
+ std::variant<CopyableIndirection<GenericExpr>, Variable> u;
};
struct Label { // TODO: this is a placeholder
explicit ActualSubroutineArg(GenericExpr &&x) : u{std::move(x)} {}
explicit ActualSubroutineArg(Variable &&x) : u{std::move(x)} {}
explicit ActualSubroutineArg(const Label &l) : u{&l} {}
- std::variant<common::Indirection<GenericExpr>, Variable, const Label *> u;
+ std::variant<CopyableIndirection<GenericExpr>, Variable, const Label *> u;
};
using SubroutineRef = ProcedureRef<ActualSubroutineArg>;