[flang] Generalize tools, clean up common/unwrap.h with new-found knowledge

Original-commit: flang-compiler/f18@aac16907cd
Reviewed-on: https://github.com/flang-compiler/f18/pull/416
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-04-16 15:59:04 -07:00
parent bfb65b5476
commit f79e3dd0b9
9 changed files with 240 additions and 161 deletions

View File

@ -46,107 +46,103 @@ template<typename A, typename B>
using Constify = std::conditional_t<std::is_const_v<B> && !std::is_const_v<A>,
std::add_const_t<A>, A>;
// Base case
// 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;
}
}
// 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>
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>
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>
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>
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>
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... 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, bool COPY>
static auto Unwrap(const Indirection<B, COPY> &p) -> Constify<A, B> * {
return Unwrap<A>(*p);
}
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> * {
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;
}
}
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>
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>
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 B, bool COPY>
auto Unwrap(const Indirection<B, COPY> &p) -> Constify<A, B> * {
return Unwrap<A>(*p);
}
template<typename A, typename B>
auto Unwrap(const CountedReference<B> &p) -> Constify<A, B> * {
if (p.get() != nullptr) {
return Unwrap<A>(*p);
} else {
return nullptr;
}
return UnwrapperHelper::Unwrap<A>(x);
}
// Returns a copy of a wrapped value, if present, otherwise a vacant optional.

View File

@ -26,6 +26,7 @@ add_library(FortranParser
provenance.cc
source.cc
token-sequence.cc
tools.cc
unparse.cc
user-state.cc
)

View File

@ -55,6 +55,7 @@ CLASS_TRAIT(EmptyTrait)
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
@ -272,6 +273,7 @@ using Location = const char *;
// 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;
@ -279,6 +281,7 @@ template<typename A> struct Scalar {
};
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;
@ -286,6 +289,7 @@ template<typename A> struct Constant {
};
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;
@ -293,6 +297,7 @@ template<typename A> struct Integer {
};
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;
@ -300,6 +305,7 @@ template<typename A> struct Logical {
};
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;

71
flang/lib/parser/tools.cc Normal file
View File

@ -0,0 +1,71 @@
// 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);
}
}

View File

@ -14,62 +14,75 @@
#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; }
// 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 StructureComponent &x) {
return GetLastName(x.component);
}
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 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);
}
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 Substring &x) {
return GetType(std::get<DataRef>(x.t));
}
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 Designator &x) {
return std::visit([](const auto &y) { return GetType(y); }, x.u);
}
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 ProcComponentRef &x) {
return GetType(x.v.thing);
}
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 ProcedureDesignator &x) {
return std::visit([](const auto &y) { return GetType(y); }, x.u);
}
const Name &GetLastName(const Call &x) {
return GetType(std::get<ProcedureDesignator>(x.t));
}
const Name &GetLastName(const FunctionReference &x) { return GetType(x.v); }
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);
}
}

View File

@ -19,6 +19,7 @@
#include "../evaluate/expression.h"
#include "../parser/message.h"
#include "../parser/parse-tree.h"
#include "../parser/tools.h"
namespace Fortran::semantics {
@ -56,7 +57,7 @@ void CoarrayChecker::Leave(const parser::FormTeamStmt &x) {
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())) {
@ -86,8 +87,7 @@ void CoarrayChecker::CheckNamesAreDistinct(
*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

View File

@ -34,6 +34,7 @@
#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>
@ -4668,7 +4669,7 @@ bool ResolveNamesVisitor::Pre(const parser::PointerAssignmentStmt &x) {
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;
}

View File

@ -111,7 +111,7 @@ bool RewriteMutator::Pre(parser::ExecutionPart &x) {
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
@ -134,13 +134,10 @@ void RewriteMutator::Post(parser::IoUnit &x) {
// 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();
}

View File

@ -97,11 +97,5 @@ const Symbol *FindExternallyVisibleObject(
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_