endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic")
- set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DDEBUG")
+ set(CMAKE_CXX_FLAGS_RELEASE "-O2")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-O2 '-DCHECK=(void)'")
- set(CMAKE_CXX_FLAGS_DEBUG "-g -DDEBUG")
+ set(CMAKE_CXX_FLAGS_DEBUG "-g -DDEBUGF18")
# Building shared libraries is death on performance with GCC by default
# due to the need to preserve the right to override external entry points
wherever appropriate.
* `std::unique_ptr<>`: A nullable pointer with ownership, null by default,
not copyable, reassignable.
+F18 has a helpful `Deleter<>` class template that makes `unique_ptr<>`
+easier to use with forward-referenced data types.
* `std::shared_ptr<>`: A nullable pointer with shared ownership via reference
counting, null by default, shallowly copyable, reassignable, and slow.
-* `OwningPointer<>`: A nullable pointer with ownership, better suited
-for use with forward-defined types than `std::unique_ptr<>` is.
-Null by default, optionally copyable, reassignable.
-Does not have direct means for allocating data, and inconveniently requires
-the definition of an external destructor.
* `Indirection<>`: A non-nullable pointer with ownership and
optional deep copy semantics; reassignable.
Often better than a reference (due to ownership) or `std::unique_ptr<>`
(due to non-nullability and copyability).
Can be wrapped in `std::optional<>` when nullability is required.
-* `ForwardReference<>`: A non-nullable `OwningPointer<>`, or a variant of
-`Indirection<>` that works with forward-declared content types; it's both.
+Usable with forward-referenced data types with some use of `extern template`
+in headers and explicit template instantiation in source files.
* `CountedReference<>`: A nullable pointer with shared ownership via
reference counting, null by default, shallowly copyable, reassignable.
Safe to use *only* when the data are private to just one
| ------- | -------- | ------------ | ------ | ------------ | -------- | ------------------ |
| `*p` | yes | no | no | yes | shallowly | yes |
| `&r` | no | n/a | no | no | shallowly | yes |
-| `unique_ptr<>` | yes | yes | yes | yes | no | no |
+| `unique_ptr<>` | yes | yes | yes | yes | no | yes, with work |
| `shared_ptr<>` | yes | yes | yes | yes | shallowly | no |
-| `OwningPointer<>` | yes | yes | yes | yes | optionally deeply | yes |
-| `Indirection<>` | no | n/a | yes | yes | optionally deeply | no |
-| `ForwardReference<>` | no | n/a | yes | yes | optionally deeply | yes |
+| `Indirection<>` | no | n/a | yes | yes | optionally deeply | yes, with work |
| `CountedReference<>` | yes | yes | yes | yes | shallowly | no |
### Overall design preferences
namespace Fortran::FIR {
namespace {
-Expression *ExprRef(const parser::Expr &a) { return &a.typedExpr.value(); }
+Expression *ExprRef(const parser::Expr &a) { return a.typedExpr.get(); }
Expression *ExprRef(const common::Indirection<parser::Expr> &a) {
- return &a.value().typedExpr.value();
+ return a.value().typedExpr.get();
}
struct LinearOp;
const std::vector<LinearLabelRef> &refs) {
auto &cases{
std::get<std::list<parser::CaseConstruct::Case>>(caseConstruct->t)};
- SwitchCaseArguments result{
- GetSwitchCaseSelector(caseConstruct), unspecifiedLabel,
- populateSwitchValues(builder_, cases), std::move(refs)};
+ SwitchCaseArguments result{GetSwitchCaseSelector(caseConstruct),
+ unspecifiedLabel, populateSwitchValues(builder_, cases),
+ std::move(refs)};
cleanupSwitchPairs<SwitchCaseStmt>(
result.defLab, result.values, result.labels);
return result;
}
// Given a const reference to a value, return a copy of the value.
-
template<typename A> A Clone(const A &x) { return x; }
}
#endif // FORTRAN_COMMON_IDIOMS_H_
#ifndef FORTRAN_COMMON_INDIRECTION_H_
#define FORTRAN_COMMON_INDIRECTION_H_
-// Defines several smart pointer class templates that are rather like
-// std::unique_ptr<>.
-// - Indirection<> is, like a C++ reference type, restricted to be non-null
-// when constructed or assigned.
-// - OwningPointer<> is like a std::unique_ptr<> with an out-of-line destructor.
-// This makes it suitable for use with forward-declared content types
-// in a way that bare C pointers allow but std::unique_ptr<> cannot.
-// - ForwardReference<> is a kind of Indirection<> that, like OwningPointer<>,
-// accommodates the use of forward declarations.
-// Users of Indirection<> and ForwardReference<> need to check whether their
-// pointers are null. Like a C++ reference, they are meant to be as invisible
-// as possible.
-// All of these can optionally support copy construction
-// and copy assignment.
+// Define a smart pointer class template that is rather like
+// non-nullable std::unique_ptr<>. Indirection<> is, like a C++ reference
+// type, restricted to be non-null when constructed or assigned.
+// Indirection<> optionally supports copy construction and copy assignment.
+//
+// To use Indirection<> with forward-referenced types, add
+// extern template class Fortran::common::Indirection<FORWARD_TYPE>;
+// outside any namespace in a header before use, and
+// template class Fortran::common::Indirection<FORWARD_TYPE>;
+// in one C++ source file later where a definition of the type is visible.
#include "../common/idioms.h"
#include <memory>
A &value() { return *p_; }
const A &value() const { return *p_; }
- bool operator==(const A &x) const { return *p_ == x; }
+ bool operator==(const A &that) const { return *p_ == that; }
bool operator==(const Indirection &that) const { return *p_ == *that.p_; }
+ bool operator!=(const A &that) const { return *p_ != that; }
+ bool operator!=(const Indirection &that) const { return *p_ != *that.p_; }
template<typename... ARGS> static Indirection Make(ARGS &&... args) {
return {new A(std::forward<ARGS>(args)...)};
A &value() { return *p_; }
const A &value() const { return *p_; }
- bool operator==(const A &x) const { return *p_ == x; }
+ bool operator==(const A &that) const { return *p_ == that; }
bool operator==(const Indirection &that) const { return *p_ == *that.p_; }
+ bool operator!=(const A &that) const { return *p_ != that; }
+ bool operator!=(const Indirection &that) const { return *p_ != *that.p_; }
template<typename... ARGS> static Indirection Make(ARGS &&... args) {
return {new A(std::forward<ARGS>(args)...)};
A *p_{nullptr};
};
-// A variant of Indirection suitable for use with forward-referenced types.
-// These are nullable pointers, not references. Allocation is not available,
-// and a single externalized destructor must be defined. Copyable if an
-// external copy constructor and operator= are implemented.
-template<typename A> class OwningPointer {
-public:
- using element_type = A;
-
- OwningPointer() {}
- OwningPointer(OwningPointer &&that) : p_{that.p_} { that.p_ = nullptr; }
- explicit OwningPointer(std::unique_ptr<A> &&that) : p_{that.release()} {}
- explicit OwningPointer(A *&&p) : p_{p} { p = nullptr; }
-
- // Must be externally defined; see DEFINE_OWNING_DESTRUCTOR below
- ~OwningPointer();
-
- // Must be externally defined if copying is needed.
- OwningPointer(const A &);
- OwningPointer(const OwningPointer &);
- OwningPointer &operator=(const A &);
- OwningPointer &operator=(const OwningPointer &);
-
- OwningPointer &operator=(OwningPointer &&that) {
- auto tmp{p_};
- p_ = that.p_;
- that.p_ = tmp;
- return *this;
- }
- OwningPointer &operator=(A *&&p) {
- return *this = OwningPointer(std::move(p));
- }
-
- bool has_value() const { return p_ != nullptr; }
- A &value() {
- CHECK(p_ != nullptr);
- return *p_;
- }
- const A &value() const {
- CHECK(p_ != nullptr);
- return *p_;
- }
+template<typename A> using CopyableIndirection = Indirection<A, true>;
- bool operator==(const A &x) const { return p_ != nullptr && *p_ == x; }
- bool operator==(const OwningPointer &that) const {
- return (p_ == nullptr && that.p_ == nullptr) ||
- (that.p_ != nullptr && *this == *that.p_);
- }
-
-private:
- A *p_{nullptr};
-};
-
-// ForwardReference can be viewed as either a non-nullable variant of
-// OwningPointer or as a variant of Indirection that accommodates use with
-// a forward-declared content type.
-template<typename A> class ForwardReference {
+// For use with std::unique_ptr<> when declaring owning pointers to
+// forward-referenced types, here's a minimal custom deleter that avoids
+// some of the drama with std::default_delete<>. Invoke DEFINE_DELETER()
+// later in exactly one C++ source file where a complete definition of the
+// type is visible. Be advised, std::unique_ptr<> does not have copy
+// semantics; if you need ownership, copy semantics, and nullability,
+// std::optional<CopyableIndirection<>> works.
+template<typename A> class Deleter {
public:
- using element_type = A;
-
- explicit ForwardReference(std::unique_ptr<A> &&that) : p_{that.release()} {}
- explicit ForwardReference(A *&&p) : p_{p} {
- CHECK(p_ && "assigning null pointer to ForwardReference");
- p = nullptr;
- }
- ForwardReference(ForwardReference<A> &&that) : p_{that.p_} {
- CHECK(p_ &&
- "move construction of ForwardReference from null ForwardReference");
- that.p_ = nullptr;
- }
-
- // Must be externally defined; see DEFINE_OWNING_DESTRUCTOR below
- ~ForwardReference();
-
- // Must be externally defined if copying is needed.
- ForwardReference(const A &);
- ForwardReference(const ForwardReference &);
- ForwardReference &operator=(const A &);
- ForwardReference &operator=(const ForwardReference &);
-
- ForwardReference &operator=(ForwardReference &&that) {
- CHECK(that.p_ &&
- "move assignment of null ForwardReference to ForwardReference");
- auto tmp{p_};
- p_ = that.p_;
- that.p_ = tmp;
- return *this;
- }
- ForwardReference &operator=(A *&&p) {
- return *this = ForwardReference(std::move(p));
- }
-
- A &value() { return *p_; }
- const A &value() const { return *p_; }
-
- bool operator==(const A &x) const { return *p_ == x; }
- bool operator==(const ForwardReference &that) const {
- return *p_ == *that.p_;
- }
-
-private:
- A *p_{nullptr};
+ void operator()(A *) const;
};
}
-
-// Mandatory instantiation and definition -- put somewhere, not in a namespace
-// CLASS here is OwningPointer or ForwardReference.
-#define DEFINE_OWNING_DESTRUCTOR(CLASS, A) \
- namespace Fortran::common { \
- template class CLASS<A>; \
- template<> CLASS<A>::~CLASS() { \
- delete p_; \
- p_ = nullptr; \
- } \
- }
-
-// Optional definitions for OwningPointer and ForwardReference
-#define DEFINE_OWNING_COPY_CONSTRUCTORS(CLASS, A) \
- namespace Fortran::common { \
- template<> CLASS<A>::CLASS(const A &that) : p_{new A(that)} {} \
- template<> \
- CLASS<A>::CLASS(const CLASS<A> &that) \
- : p_{that.p_ ? new A(*that.p_) : nullptr} {} \
+#define DEFINE_DELETER(A) \
+ template<> void Fortran::common::Deleter<A>::operator()(A *p) const { \
+ delete p; \
}
-#define DEFINE_OWNING_COPY_ASSIGNMENTS(CLASS, A) \
- namespace Fortran::common { \
- template<> CLASS<A> &CLASS<A>::operator=(const A &that) { \
- delete p_; \
- p_ = new A(that); \
- return *this; \
- } \
- template<> CLASS<A> &CLASS<A>::operator=(const CLASS<A> &that) { \
- delete p_; \
- p_ = that.p_ ? new A(*that.p_) : nullptr; \
- return *this; \
- } \
- }
-
-#define DEFINE_OWNING_COPY_FUNCTIONS(CLASS, A) \
- DEFINE_OWNING_COPY_CONSTRUCTORS(CLASS, A) \
- DEFINE_OWNING_COPY_ASSIGNMENTS(CLASS, A)
-#define DEFINE_OWNING_SPECIAL_FUNCTIONS(CLASS, A) \
- DEFINE_OWNING_DESTRUCTOR(CLASS, A) \
- DEFINE_OWNING_COPY_FUNCTIONS(CLASS, A)
-
#endif // FORTRAN_COMMON_INDIRECTION_H_
-// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
+// 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.
auto Unwrap(const std::variant<Bs...> &) -> std::add_const_t<A> *;
template<typename A, typename B, bool COPY>
auto Unwrap(const Indirection<B, COPY> &) -> Constify<A, B> *;
-template<typename A, typename B>
-auto Unwrap(const OwningPointer<B> &) -> Constify<A, B> *;
-template<typename A, typename B>
-auto Unwrap(const CountedReference<B> &) -> Constify<A, B> *;
// Implementations of specializations
template<typename A, typename B> auto Unwrap(B *p) -> Constify<A, B> * {
}
template<typename A, typename B>
-auto Unwrap(const OwningPointer<B> &p) -> Constify<A, B> * {
- if (p.get() != nullptr) {
- return Unwrap<A>(*p);
- } else {
- return nullptr;
- }
-}
-
-template<typename A, typename B>
auto Unwrap(const CountedReference<B> &p) -> Constify<A, B> * {
if (p.get() != nullptr) {
return Unwrap<A>(*p);
class ActualArgument {
public:
explicit ActualArgument(Expr<SomeType> &&x) : value_{std::move(x)} {}
- explicit ActualArgument(CopyableIndirection<Expr<SomeType>> &&v)
+ explicit ActualArgument(common::CopyableIndirection<Expr<SomeType>> &&v)
: value_{std::move(v)} {}
Expr<SomeType> &value() { return value_.value(); }
// e.g. between X and (X). The parser attempts to parse each argument
// first as a variable, then as an expression, and the distinction appears
// in the parse tree.
- CopyableIndirection<Expr<SomeType>> value_;
+ common::CopyableIndirection<Expr<SomeType>> value_;
};
using ActualArguments = std::vector<std::optional<ActualArgument>>;
return o << (sep == '(' ? "()" : ")");
}
}
-
-// Define OwningPointer special member functions
-DEFINE_OWNING_SPECIAL_FUNCTIONS(
- OwningPointer, evaluate::characteristics::Procedure)
+DEFINE_DELETER(Fortran::evaluate::characteristics::Procedure)
struct DummyProcedure {
ENUM_CLASS(Attr, Pointer, Optional)
DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(DummyProcedure)
- common::OwningPointer<Procedure> explicitProcedure;
+ std::unique_ptr<Procedure, common::Deleter<Procedure>> explicitProcedure;
common::EnumSet<Attr, 32> attrs;
bool operator==(const DummyProcedure &) const;
std::ostream &Dump(std::ostream &) const;
// - There are full copy and move semantics for construction and assignment.
// - Discriminated unions have a std::variant<> member "u" and support
// explicit copy and move constructors as well as comparison for equality.
+#define DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(t) \
+ t(const t &); \
+ t(t &&); \
+ t &operator=(const t &); \
+ t &operator=(t &&);
#define DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(t) \
t(const t &) = default; \
t(t &&) = default; \
t &operator=(const t &) = default; \
t &operator=(t &&) = default;
+#define DEFINE_DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(t) \
+ t::t(const t &) = default; \
+ t::t(t &&) = default; \
+ t &t::operator=(const t &) = default; \
+ t &t::operator=(t &&) = default;
#define CLASS_BOILERPLATE(t) \
t() = delete; \
: u(std::move(x)) {} \
bool operator==(const t &that) const { return u == that.u; }
-// Force availability of copy construction and assignment
-template<typename A> using CopyableIndirection = common::Indirection<A, true>;
-
// Forward definition of Expr<> so that it can be indirectly used in its own
// definition
template<typename A> class Expr;
std::vector<std::int64_t> shape_;
};
-using StructureConstructorValues =
- std::map<const semantics::Symbol *, CopyableIndirection<Expr<SomeType>>>;
+using StructureConstructorValues = std::map<const semantics::Symbol *,
+ common::CopyableIndirection<Expr<SomeType>>>;
template<>
class Constant<SomeDerived>
}
}
- template<typename X> void Descend(const CopyableIndirection<X> &p) {
+ template<typename X, bool COPY>
+ void Descend(const common::Indirection<X, COPY> &p) {
Visit(p.value());
}
- template<typename X> void Descend(CopyableIndirection<X> &p) {
+ template<typename X, bool COPY>
+ void Descend(common::Indirection<X, COPY> &p) {
Visit(p.value());
}
}
template<typename T>
-std::ostream &Emit(std::ostream &o, const CopyableIndirection<Expr<T>> &expr) {
+std::ostream &Emit(
+ std::ostream &o, const common::CopyableIndirection<Expr<T>> &expr) {
return expr.value().AsFortran(o);
}
o << "z'" << x.Hexadecimal() << "'";
},
[&](const NullPointer &) { o << "NULL()"; },
- [&](const CopyableIndirection<Substring> &s) {
+ [&](const common::CopyableIndirection<Substring> &s) {
s.value().AsFortran(o);
},
[&](const ImpliedDoIndex &i) { o << i.name.ToString(); },
u);
}
-Expr<SomeType>::~Expr() {}
+Expr<SomeType>::~Expr() = default;
#if defined(__APPLE__) && defined(__GNUC__)
template<typename A>
return o;
}
+GenericExprWrapper::~GenericExprWrapper() = default;
+
bool GenericExprWrapper::operator==(const GenericExprWrapper &that) const {
return v == that.v;
}
+template<TypeCategory CAT> int Expr<SomeKind<CAT>>::GetKind() const {
+ return std::visit(
+ [](const auto &kx) { return std::decay_t<decltype(kx)>::Result::kind; },
+ u);
+}
+
+int Expr<SomeCharacter>::GetKind() const {
+ return std::visit(
+ [](const auto &kx) { return std::decay_t<decltype(kx)>::Result::kind; },
+ u);
+}
+
+Expr<SubscriptInteger> Expr<SomeCharacter>::LEN() const {
+ return std::visit([](const auto &kx) { return kx.LEN(); }, u);
+}
+
// Template instantiations to resolve the "extern template" declarations
// that appear in expression.h.
FOR_EACH_INTRINSIC_KIND(template class ArrayConstructorValues)
FOR_EACH_INTRINSIC_KIND(template class ArrayConstructor)
}
-
-// For reclamation of analyzed expressions to which owning pointers have
-// been embedded in the parse tree. This destructor appears here, where
-// definitions for all the necessary types are available, to obviate a
-// need to include lib/evaluate/*.h headers in the parser proper.
-DEFINE_OWNING_SPECIAL_FUNCTIONS(OwningPointer, evaluate::GenericExprWrapper)
+DEFINE_DELETER(Fortran::evaluate::GenericExprWrapper)
// Unary operations wrap a single Expr with a CopyableIndirection.
// Binary operations wrap a tuple of CopyableIndirections to Exprs.
private:
- using Container =
- std::conditional_t<operands == 1, CopyableIndirection<Expr<Operand<0>>>,
- std::tuple<CopyableIndirection<Expr<OPERANDS>>...>>;
+ using Container = std::conditional_t<operands == 1,
+ common::CopyableIndirection<Expr<Operand<0>>>,
+ std::tuple<common::CopyableIndirection<Expr<OPERANDS>>...>>;
public:
CLASS_BOILERPLATE(Operation)
private:
parser::CharBlock name_;
- CopyableIndirection<Expr<Index>> lower_, upper_, stride_;
- CopyableIndirection<ArrayConstructorValues<Result>> values_;
+ common::CopyableIndirection<Expr<Index>> lower_, upper_, stride_;
+ common::CopyableIndirection<ArrayConstructorValues<Result>> values_;
};
template<typename RESULT> struct ArrayConstructorValue {
using Result = RESULT;
EVALUATE_UNION_CLASS_BOILERPLATE(ArrayConstructorValue)
- std::variant<CopyableIndirection<Expr<Result>>, ImpliedDo<Result>> u;
+ std::variant<common::CopyableIndirection<Expr<Result>>, ImpliedDo<Result>> u;
};
template<typename RESULT> class ArrayConstructorValues {
const Expr<SubscriptInteger> &LEN() const { return length_.value(); }
private:
- CopyableIndirection<Expr<SubscriptInteger>> length_;
+ common::CopyableIndirection<Expr<SubscriptInteger>> length_;
};
template<>
public:
using Result = SomeKind<CAT>;
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
- int GetKind() const {
- return std::visit(
- [](const auto &x) { return std::decay_t<decltype(x)>::Result::kind; },
- u);
- }
+ int GetKind() const;
common::MapTemplate<Expr, CategoryTypes<CAT>> u;
};
+template<> class Expr<SomeCharacter> : public ExpressionBase<SomeCharacter> {
+public:
+ using Result = SomeCharacter;
+ EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
+ int GetKind() const;
+ Expr<SubscriptInteger> LEN() const;
+ common::MapTemplate<Expr, CategoryTypes<TypeCategory::Character>> u;
+};
+
// BOZ literal "typeless" constants must be wide enough to hold a numeric
// value of any supported kind of INTEGER or REAL. They must also be
// distinguishable from other integer constants, since they are permitted
};
// This wrapper class is used, by means of a forward reference with
-// OwningPointer, to implement owning pointers to analyzed expressions
-// from parse tree nodes.
+// an owning pointer, to cache analyzed expressions in parse tree nodes.
struct GenericExprWrapper {
GenericExprWrapper(Expr<SomeType> &&x) : v{std::move(x)} {}
+ ~GenericExprWrapper();
bool operator==(const GenericExprWrapper &) const;
Expr<SomeType> v;
};
}
private:
- bool FoldArray(const CopyableIndirection<Expr<T>> &expr) {
+ bool FoldArray(const common::CopyableIndirection<Expr<T>> &expr) {
Expr<T> folded{Fold(context_, common::Clone(expr.value()))};
if (auto *c{UnwrapExpr<Constant<T>>(folded)}) {
// Copy elements in Fortran array element order
// Many expressions, including subscripts, CHARACTER lengths, array bounds,
// and effective type parameter values, are of a maximal kind of INTEGER.
using IndirectSubscriptIntegerExpr =
- CopyableIndirection<Expr<SubscriptInteger>>;
+ common::CopyableIndirection<Expr<SubscriptInteger>>;
// A predicate that is true when a kind value is a kind that could possibly
// be supported for an intrinsic type category on some target instruction
return o;
}
-template<typename A>
-std::ostream &Emit(std::ostream &o, const CopyableIndirection<A> &p,
+template<typename A, bool COPY>
+std::ostream &Emit(std::ostream &o, const common::Indirection<A, COPY> &p,
const char *kw = nullptr) {
if (kw != nullptr) {
o << kw;
CLASS_BOILERPLATE(Component)
Component(const DataRef &b, const Symbol &c) : base_{b}, symbol_{&c} {}
Component(DataRef &&b, const Symbol &c) : base_{std::move(b)}, symbol_{&c} {}
- Component(CopyableIndirection<DataRef> &&b, const Symbol &c)
+ Component(common::CopyableIndirection<DataRef> &&b, const Symbol &c)
: base_{std::move(b)}, symbol_{&c} {}
const DataRef &base() const { return base_.value(); }
std::ostream &AsFortran(std::ostream &) const;
private:
- CopyableIndirection<DataRef> base_;
+ common::CopyableIndirection<DataRef> base_;
const Symbol *symbol_;
};
private:
std::vector<const Symbol *> base_;
std::vector<Expr<SubscriptInteger>> subscript_, cosubscript_;
- std::optional<CopyableIndirection<Expr<SomeInteger>>> stat_, team_;
+ std::optional<common::CopyableIndirection<Expr<SomeInteger>>> stat_, team_;
bool teamIsTeamNumber_{false}; // false: TEAM=, true: TEAM_NUMBER=
};
#include "../common/indirection.h"
#include <algorithm>
+// So "delete Expr::typedExpr;" calls an external destructor.
+namespace Fortran::evaluate {
+struct GenericExprWrapper {
+ ~GenericExprWrapper();
+};
+}
+
namespace Fortran::parser {
// R867
return os << x.ToString();
}
}
+
+template class std::unique_ptr<Fortran::evaluate::GenericExprWrapper>;
#include "../common/indirection.h"
#include <cinttypes>
#include <list>
+#include <memory>
#include <optional>
#include <string>
#include <tuple>
// Expressions in the parse tree have owning pointers that can be set to
// type-checked generic expression representations by semantic analysis.
-// OwningPointer<> is used for leak safety without having to include
-// the bulk of lib/evaluate/*.h headers into the parser proper.
namespace Fortran::evaluate {
struct GenericExprWrapper; // forward definition, wraps Expr<SomeType>
}
-namespace Fortran::common {
-extern template class OwningPointer<evaluate::GenericExprWrapper>;
-}
// Most non-template classes in this file use these default definitions
// for their move constructor and move assignment operator=, and disable
// R1023 defined-binary-op -> . letter [letter]... .
// R1414 local-defined-operator -> defined-unary-op | defined-binary-op
// R1415 use-defined-operator -> defined-unary-op | defined-binary-op
-// The Name here is stored with the dots; e.g., .FOO.
+// The Name here is stored without the dots; e.g., FOO, not .FOO.
WRAPPER_CLASS(DefinedOpName, Name);
// R608 intrinsic-operator ->
explicit Expr(Designator &&);
explicit Expr(FunctionReference &&);
- // Filled in after successful semantic analysis of the expression.
- mutable common::OwningPointer<evaluate::GenericExprWrapper> typedExpr;
+ // Filled in with expression after successful semantic analysis.
+ mutable std::unique_ptr<evaluate::GenericExprWrapper,
+ common::Deleter<evaluate::GenericExprWrapper>>
+ typedExpr;
CharBlock source;
};
// R1162 stop-code -> scalar-default-char-expr | scalar-int-expr
-// We can't distinguish character expressions from integer
-// expressions during parsing, so we just parse an expr and
-// check its type later.
-WRAPPER_CLASS(StopCode, Scalar<Expr>);
+struct StopCode {
+ UNION_CLASS_BOILERPLATE(StopCode);
+ std::variant<ScalarDefaultCharExpr, ScalarIntExpr> u;
+};
// R1160 stop-stmt -> STOP [stop-code] [, QUIET = scalar-logical-expr]
// R1161 error-stop-stmt ->
EMPTY_CLASS(ReadUnformatted);
EMPTY_CLASS(WriteFormatted);
EMPTY_CLASS(WriteUnformatted);
- CharBlock source;
std::variant<Name, DefinedOperator, Assignment, ReadFormatted,
ReadUnformatted, WriteFormatted, WriteUnformatted>
u;
#include "semantics.h"
#include "../common/indirection.h"
+#include "../evaluate/expression.h"
namespace Fortran::parser {
template<typename> struct Statement;
struct ForallConstruct;
}
+namespace Fortran::evaluate {
+void CheckPointerAssignment(parser::ContextualMessages &, const Symbol &,
+ const evaluate::Expr<evaluate::SomeType> &);
+}
+
namespace Fortran::semantics {
class AssignmentContext;
+}
+extern template class Fortran::common::Indirection<
+ Fortran::semantics::AssignmentContext>;
+
+namespace Fortran::semantics {
class AssignmentChecker : public virtual BaseChecker {
public:
explicit AssignmentChecker(SemanticsContext &);
+ ~AssignmentChecker();
void Enter(const parser::AssignmentStmt &);
void Enter(const parser::PointerAssignmentStmt &);
void Enter(const parser::WhereStmt &);
void Enter(const parser::ForallConstruct &);
private:
- common::ForwardReference<AssignmentContext> context_;
+ common::Indirection<AssignmentContext> context_;
};
// Semantic analysis of an assignment statement or WHERE/FORALL construct.
// well as in DO CONCURRENT loops.
void AnalyzeConcurrentHeader(
SemanticsContext &, const parser::ConcurrentHeader &);
-
}
#endif // FORTRAN_SEMANTICS_ASSIGNMENT_H_
static CS GatherReferencesFromExpression(const parser::Expr &expression) {
// Use the new expression traversal framework if possible, for testing.
- if (expression.typedExpr.has_value()) {
+ if (expression.typedExpr) {
struct CollectSymbols : public virtual evaluate::VisitorBase<CS> {
explicit CollectSymbols(int) {}
void Handle(const Symbol *symbol) { result().push_back(symbol); }
};
return evaluate::Visitor<CS, CollectSymbols>{0}.Traverse(
- expression.typedExpr.value());
+ *expression.typedExpr);
} else {
GatherSymbols gatherSymbols;
parser::Walk(expression, gatherSymbols);
auto &logicalExpr{
std::get<parser::ScalarLogicalExpr>(optionalLoopControl->u)
.thing.thing};
- if (!ExpressionHasTypeCategory(logicalExpr.value().typedExpr.value(),
+ CHECK(logicalExpr.value().typedExpr);
+ if (!ExpressionHasTypeCategory(*logicalExpr.value().typedExpr,
common::TypeCategory::Logical)) {
messages_.Say(currentStatementSourcePosition_,
"DO WHILE must have LOGICAL expression"_err_en_US);
} // namespace Fortran::semantics
-DEFINE_OWNING_DESTRUCTOR(ForwardReference, semantics::DoConcurrentContext)
-
namespace Fortran::semantics {
DoConcurrentChecker::DoConcurrentChecker(SemanticsContext &context)
: context_{new DoConcurrentContext{context}} {}
+DoConcurrentChecker::~DoConcurrentChecker() = default;
+
// DO loops must be canonicalized prior to calling
void DoConcurrentChecker::Leave(const parser::DoConstruct &x) {
context_.value().Check(x);
}
} // namespace Fortran::semantics
+
+template class Fortran::common::Indirection<
+ Fortran::semantics::DoConcurrentContext>;
namespace Fortran::parser {
struct DoConstruct;
}
-
namespace Fortran::semantics {
class DoConcurrentContext;
+}
+extern template class Fortran::common::Indirection<
+ Fortran::semantics::DoConcurrentContext>;
+namespace Fortran::semantics {
class DoConcurrentChecker : public virtual BaseChecker {
public:
explicit DoConcurrentChecker(SemanticsContext &);
+ ~DoConcurrentChecker();
void Leave(const parser::DoConstruct &);
private:
- common::ForwardReference<DoConcurrentContext> context_;
+ common::Indirection<DoConcurrentContext> context_;
};
}
-// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
+// 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.
// Each is based on operator<< for that type. There are overloadings for
// reference and pointer, and for dumping to a provided ostream or cerr.
-#ifdef DEBUG
+#ifdef DEBUGF18
#include <iostream>
// The parse tree has slots in which pointers to typed expressions may be
// placed. When using the parser without the expression library, as here,
-// we need to stub out the dependence.
+// we need to stub out the dependence on the external destructor, which
+// will never actually be called.
#include "../../lib/common/indirection.h"
namespace Fortran::evaluate {
struct GenericExprWrapper {
- bool operator==(const GenericExprWrapper &) const { return false; }
+ ~GenericExprWrapper();
};
+GenericExprWrapper::~GenericExprWrapper() = default;
}
-DEFINE_OWNING_DESTRUCTOR(OwningPointer, evaluate::GenericExprWrapper)
+DEFINE_DELETER(Fortran::evaluate::GenericExprWrapper)