using Constify = std::conditional_t<std::is_const_v<B> && !std::is_const_v<A>,
std::add_const_t<A>, A>;
-// Base case
-template<typename A, typename B> auto Unwrap(B &x) -> Constify<A, B> * {
- if constexpr (std::is_same_v<std::decay_t<A>, std::decay_t<B>>) {
- return &x;
- } else {
- return nullptr;
+// Unwrap's mutually-recursive template functions are packaged in a struct
+// to avoid a need for prototypes.
+struct UnwrapperHelper {
+
+ // Base case
+ template<typename A, typename B>
+ static auto Unwrap(B &x) -> Constify<A, B> * {
+ if constexpr (std::is_same_v<std::decay_t<A>, std::decay_t<B>>) {
+ return &x;
+ } else {
+ return nullptr;
+ }
}
-}
-// Prototypes of specializations, to enable mutual recursion
-template<typename A, typename B> auto Unwrap(B *p) -> Constify<A, B> *;
-template<typename A, typename B>
-auto Unwrap(const std::unique_ptr<B> &) -> Constify<A, B> *;
-template<typename A, typename B>
-auto Unwrap(const std::shared_ptr<B> &) -> Constify<A, B> *;
-template<typename A, typename B>
-auto Unwrap(std::optional<B> &) -> Constify<A, B> *;
-template<typename A, typename B>
-auto Unwrap(const std::optional<B> &) -> std::add_const_t<A> *;
-template<typename A, typename... Bs> A *Unwrap(std::variant<Bs...> &);
-template<typename A, typename... Bs>
-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> *;
-
-// Implementations of specializations
-template<typename A, typename B> auto Unwrap(B *p) -> Constify<A, B> * {
- if (p != nullptr) {
- return Unwrap<A>(*p);
- } else {
- return nullptr;
+ // Implementations of specializations
+ template<typename A, typename B>
+ static auto Unwrap(B *p) -> Constify<A, B> * {
+ if (p != nullptr) {
+ return Unwrap<A>(*p);
+ } else {
+ return nullptr;
+ }
}
-}
-template<typename A, typename B>
-auto Unwrap(const std::unique_ptr<B> &p) -> Constify<A, B> * {
- if (p.get() != nullptr) {
- return Unwrap<A>(*p);
- } else {
- return nullptr;
+ template<typename A, typename B>
+ static auto Unwrap(const std::unique_ptr<B> &p) -> Constify<A, B> * {
+ if (p.get() != nullptr) {
+ return Unwrap<A>(*p);
+ } else {
+ return nullptr;
+ }
}
-}
-template<typename A, typename B>
-auto Unwrap(const std::shared_ptr<B> &p) -> Constify<A, B> * {
- if (p.get() != nullptr) {
- return Unwrap<A>(*p);
- } else {
- return nullptr;
+ template<typename A, typename B>
+ static auto Unwrap(const std::shared_ptr<B> &p) -> Constify<A, B> * {
+ if (p.get() != nullptr) {
+ return Unwrap<A>(*p);
+ } else {
+ return nullptr;
+ }
}
-}
-template<typename A, typename B>
-auto Unwrap(std::optional<B> &x) -> Constify<A, B> * {
- if (x.has_value()) {
- return Unwrap<A>(*x);
- } else {
- return nullptr;
+ template<typename A, typename B>
+ static auto Unwrap(std::optional<B> &x) -> Constify<A, B> * {
+ if (x.has_value()) {
+ return Unwrap<A>(*x);
+ } else {
+ return nullptr;
+ }
}
-}
-template<typename A, typename B>
-auto Unwrap(const std::optional<B> &x) -> Constify<A, B> * {
- if (x.has_value()) {
- return Unwrap<A>(*x);
- } else {
- return nullptr;
+ template<typename A, typename B>
+ static auto Unwrap(const std::optional<B> &x) -> Constify<A, B> * {
+ if (x.has_value()) {
+ return Unwrap<A>(*x);
+ } else {
+ return nullptr;
+ }
}
-}
-
-template<typename A, typename... Bs> A *Unwrap(std::variant<Bs...> &u) {
- return std::visit(
- [](auto &x) -> A * {
- using Ty = std::decay_t<decltype(Unwrap<A>(x))>;
- if constexpr (!std::is_const_v<std::remove_pointer_t<Ty>> ||
- std::is_const_v<A>) {
- return Unwrap<A>(x);
- }
- return nullptr;
- },
- u);
-}
-template<typename A, typename... Bs>
-auto Unwrap(const std::variant<Bs...> &u) -> std::add_const_t<A> * {
- return std::visit(
- [](const auto &x) -> std::add_const_t<A> * { return Unwrap<A>(x); }, u);
-}
+ template<typename A, typename... Bs>
+ static A *Unwrap(std::variant<Bs...> &u) {
+ return std::visit(
+ [](auto &x) -> A * {
+ using Ty = std::decay_t<decltype(Unwrap<A>(x))>;
+ if constexpr (!std::is_const_v<std::remove_pointer_t<Ty>> ||
+ std::is_const_v<A>) {
+ return Unwrap<A>(x);
+ }
+ return nullptr;
+ },
+ u);
+ }
-template<typename A, typename B, bool COPY>
-auto Unwrap(const Indirection<B, COPY> &p) -> Constify<A, B> * {
- return Unwrap<A>(*p);
-}
+ template<typename A, typename... Bs>
+ static auto Unwrap(const std::variant<Bs...> &u) -> std::add_const_t<A> * {
+ return std::visit(
+ [](const auto &x) -> std::add_const_t<A> * { return Unwrap<A>(x); }, u);
+ }
-template<typename A, typename B>
-auto Unwrap(const CountedReference<B> &p) -> Constify<A, B> * {
- if (p.get() != nullptr) {
+ template<typename A, typename B, bool COPY>
+ static auto Unwrap(const Indirection<B, COPY> &p) -> Constify<A, B> * {
return Unwrap<A>(*p);
- } else {
- return nullptr;
}
+
+ template<typename A, typename B>
+ static auto Unwrap(const CountedReference<B> &p) -> Constify<A, B> * {
+ if (p.get() != nullptr) {
+ return Unwrap<A>(*p);
+ } else {
+ return nullptr;
+ }
+ }
+};
+
+template<typename A, typename B> auto Unwrap(B &x) -> Constify<A, B> * {
+ return UnwrapperHelper::Unwrap<A>(x);
}
// Returns a copy of a wrapped value, if present, otherwise a vacant optional.
provenance.cc
source.cc
token-sequence.cc
+ tools.cc
unparse.cc
user-state.cc
)
CLASS_TRAIT(WrapperTrait)
CLASS_TRAIT(UnionTrait)
CLASS_TRAIT(TupleTrait)
+CLASS_TRAIT(ConstraintTrait)
// Some parse tree nodes have fields in them to cache the results of a
// successful semantic analysis later. Their types are forward declared
// These template class wrappers correspond to the Standard's modifiers
// scalar-xyz, constant-xzy, int-xzy, default-char-xyz, & logical-xyz.
template<typename A> struct Scalar {
+ using ConstraintTrait = std::true_type;
Scalar(Scalar &&that) = default;
Scalar(A &&that) : thing(std::move(that)) {}
Scalar &operator=(Scalar &&) = default;
};
template<typename A> struct Constant {
+ using ConstraintTrait = std::true_type;
Constant(Constant &&that) = default;
Constant(A &&that) : thing(std::move(that)) {}
Constant &operator=(Constant &&) = default;
};
template<typename A> struct Integer {
+ using ConstraintTrait = std::true_type;
Integer(Integer &&that) = default;
Integer(A &&that) : thing(std::move(that)) {}
Integer &operator=(Integer &&) = default;
};
template<typename A> struct Logical {
+ using ConstraintTrait = std::true_type;
Logical(Logical &&that) = default;
Logical(A &&that) : thing(std::move(that)) {}
Logical &operator=(Logical &&) = default;
};
template<typename A> struct DefaultChar {
+ using ConstraintTrait = std::true_type;
DefaultChar(DefaultChar &&that) = default;
DefaultChar(A &&that) : thing(std::move(that)) {}
DefaultChar &operator=(DefaultChar &&) = default;
--- /dev/null
+// Copyright (c) 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 "tools.h"
+
+namespace Fortran::parser {
+
+const Name &GetLastName(const Name &x) { return x; }
+
+const Name &GetLastName(const StructureComponent &x) {
+ return GetLastName(x.component);
+}
+
+const Name &GetLastName(const DataRef &x) {
+ return std::visit(
+ common::visitors{
+ [](const Name &name) -> const Name & { return name; },
+ [](const common::Indirection<StructureComponent> &sc)
+ -> const Name & { return GetLastName(sc.value()); },
+ [](const common::Indirection<ArrayElement> &sc) -> const Name & {
+ return GetLastName(sc.value().base);
+ },
+ [](const common::Indirection<CoindexedNamedObject> &ci)
+ -> const Name & { return GetLastName(ci.value().base); },
+ },
+ x.u);
+}
+
+const Name &GetLastName(const Substring &x) {
+ return GetLastName(std::get<DataRef>(x.t));
+}
+
+const Name &GetLastName(const Designator &x) {
+ return std::visit(
+ [](const auto &y) -> const Name & { return GetLastName(y); }, x.u);
+}
+
+const Name &GetLastName(const ProcComponentRef &x) {
+ return GetLastName(x.v.thing);
+}
+
+const Name &GetLastName(const ProcedureDesignator &x) {
+ return std::visit(
+ [](const auto &y) -> const Name & { return GetLastName(y); }, x.u);
+}
+
+const Name &GetLastName(const Call &x) {
+ return GetLastName(std::get<ProcedureDesignator>(x.t));
+}
+
+const Name &GetLastName(const FunctionReference &x) { return GetLastName(x.v); }
+
+const Name &GetLastName(const Variable &x) {
+ return std::visit(
+ [](const auto &indirection) -> const Name & {
+ return GetLastName(indirection.value());
+ },
+ x.u);
+}
+}
#ifndef FORTRAN_PARSER_TOOLS_H_
#define FORTRAN_PARSER_TOOLS_H_
+
#include "parse-tree.h"
+
namespace Fortran::parser {
// GetLastName() isolates and returns a reference to the rightmost Name
// in a variable (i.e., the Name whose symbol's type determines the type
// of the variable or expression).
+const Name &GetLastName(const Name &);
+const Name &GetLastName(const StructureComponent &);
+const Name &GetLastName(const DataRef &);
+const Name &GetLastName(const Substring &);
+const Name &GetLastName(const Designator &);
+const Name &GetLastName(const ProcComponentRef &);
+const Name &GetLastName(const ProcedureDesignator &);
+const Name &GetLastName(const Call &);
+const Name &GetLastName(const FunctionReference &);
+const Name &GetLastName(const Variable &);
-const Name &GetLastName(const Name &x) { return x; }
-
-const Name &GetLastName(const StructureComponent &x) {
- return GetLastName(x.component);
-}
-
-const Name &GetLastName(const DataRef &x) {
- return std::visit(
- common::visitors{
- [](const Name &name) { return GetLastName(name); },
- [](const common::Indirection<StructureComponent> &sc) {
- return GetLastName(sc.value());
- },
- [](const common::Indirection<ArrayElement> &sc) {
- return GetLastName(sc.value().base);
- },
- [](const common::Indirection<CoindexedNamedObject> &ci) {
- return GetLastName(ci.value().base);
- },
- },
- x.u);
-}
-
-const Name &GetLastName(const Substring &x) {
- return GetType(std::get<DataRef>(x.t));
-}
+// When a parse tree node is an instance of a specific type wrapped in
+// layers of packaging, return a pointer to that object.
+// Implemented with mutually recursive template functions that are
+// wrapped in a struct to avoid prototypes.
+struct UnwrapperHelper {
-const Name &GetLastName(const Designator &x) {
- return std::visit([](const auto &y) { return GetType(y); }, x.u);
-}
+ template<typename A, typename B> static const A *Unwrap(B *p) {
+ if (p != nullptr) {
+ return Unwrap<A>(*p);
+ } else {
+ return nullptr;
+ }
+ }
-const Name &GetLastName(const ProcComponentRef &x) {
- return GetType(x.v.thing);
-}
+ template<typename A, typename B, bool COPY>
+ static const A *Unwrap(const common::Indirection<B, COPY> &x) {
+ return Unwrap<A>(x.value());
+ }
-const Name &GetLastName(const ProcedureDesignator &x) {
- return std::visit([](const auto &y) { return GetType(y); }, x.u);
-}
+ template<typename A, typename... Bs>
+ static const A *Unwrap(const std::variant<Bs...> &x) {
+ return std::visit([](const auto &y) { return Unwrap<A>(y); }, x);
+ }
-const Name &GetLastName(const Call &x) {
- return GetType(std::get<ProcedureDesignator>(x.t));
-}
+ template<typename A, typename B>
+ static const A *Unwrap(const std::optional<B> &o) {
+ if (o.has_value()) {
+ return Unwrap<A>(*o);
+ } else {
+ return nullptr;
+ }
+ }
-const Name &GetLastName(const FunctionReference &x) { return GetType(x.v); }
+ template<typename A, typename B> static const A *Unwrap(B &x) {
+ if constexpr (std::is_same_v<std::decay_t<A>, std::decay_t<B>>) {
+ return &x;
+ } else if constexpr (ConstraintTrait<B>) {
+ return Unwrap<A>(x.thing);
+ } else if constexpr (WrapperTrait<B>) {
+ return Unwrap<A>(x.v);
+ } else if constexpr (UnionTrait<B>) {
+ return Unwrap<A>(x.u);
+ } else {
+ return nullptr;
+ }
+ }
+};
-const Name &GetLastName(const Variable &x) {
- return std::visit(
- [](const auto &indirection) { return GetType(indirection.value()); },
- x.u);
+template<typename A, typename B> const A *Unwrap(const B &x) {
+ return UnwrapperHelper::Unwrap<A>(x);
}
}
#include "../evaluate/expression.h"
#include "../parser/message.h"
#include "../parser/parse-tree.h"
+#include "../parser/tools.h"
namespace Fortran::semantics {
AnalyzeExpr(context_, std::get<parser::ScalarIntExpr>(x.t));
const auto &teamVar{std::get<parser::TeamVariable>(x.t)};
AnalyzeExpr(context_, teamVar);
- const parser::Name *name{GetSimpleName(teamVar.thing)};
+ const parser::Name *name{parser::Unwrap<parser::Name>(teamVar)};
CHECK(name);
if (const auto *type{name->symbol->GetType()}) {
if (!IsTeamType(type->AsDerived())) {
*prev, "Previous use of '%s'"_en_US);
}
// ResolveNames verified the selector is a simple name
- const auto &variable{std::get<parser::Variable>(selector.u)};
- const parser::Name *name{GetSimpleName(variable)};
+ const parser::Name *name{parser::Unwrap<parser::Name>(selector)};
CHECK(name);
if (auto *prev{getPreviousUse(*name)}) {
Say2(name->source, // C1113, C1115
#include "../evaluate/type.h"
#include "../parser/parse-tree-visitor.h"
#include "../parser/parse-tree.h"
+#include "../parser/tools.h"
#include <list>
#include <map>
#include <memory>
ResolveDataRef(dataRef);
Walk(bounds);
// Resolve unrestricted specific intrinsic procedures as in "p => cos".
- if (const parser::Name * name{GetSimpleName(expr)}) {
+ if (const parser::Name * name{parser::Unwrap<parser::Name>(expr)}) {
if (NameIsKnownOrIntrinsic(*name)) {
return false;
}
void RewriteMutator::Post(parser::IoUnit &x) {
if (auto *var{std::get_if<parser::Variable>(&x.u)}) {
- parser::Name &last{parser::GetLastName(*var)};
+ const parser::Name &last{parser::GetLastName(*var)};
DeclTypeSpec *type{last.symbol ? last.symbol->GetType() : nullptr};
if (type == nullptr || type->category() != DeclTypeSpec::Character) {
// If the Variable is not known to be character (any kind), transform
// name had appeared with NML=.
template<typename READ_OR_WRITE>
void FixMisparsedUntaggedNamelistName(READ_OR_WRITE &x) {
- if (x.iounit.has_value() && x.format.has_value()) {
- if (auto *charExpr{
- std::get_if<parser::DefaultCharExpr>(&x.format.value().u)}) {
- parser::Expr &expr{charExpr->thing.value()};
- parser::Name *name{GetSimpleName(expr)};
- if (name != nullptr && name->symbol != nullptr &&
- name->symbol->has<NamelistDetails>()) {
+ if (x.iounit.has_value() && x.format.has_value() &&
+ std::holds_alternative<parser::DefaultCharExpr>(x.format->u)) {
+ if (const parser::Name * name{parser::Unwrap<parser::Name>(x.format)}) {
+ if (name->symbol != nullptr && name->symbol->has<NamelistDetails>()) {
x.controls.emplace_front(parser::IoControlSpec{std::move(*name)});
x.format.reset();
}
bool ExprHasTypeCategory(
const evaluate::GenericExprWrapper &expr, const common::TypeCategory &type);
-
-// If this Expr or Variable represents a simple Name, return it.
-parser::Name *GetSimpleName(parser::Expr &);
-const parser::Name *GetSimpleName(const parser::Expr &);
-parser::Name *GetSimpleName(parser::Variable &);
-const parser::Name *GetSimpleName(const parser::Variable &);
}
#endif // FORTRAN_SEMANTICS_TOOLS_H_