[flang] Generalize tools, clean up common/unwrap.h with new-found knowledge
authorpeter klausler <pklausler@nvidia.com>
Tue, 16 Apr 2019 22:59:04 +0000 (15:59 -0700)
committerpeter klausler <pklausler@nvidia.com>
Tue, 16 Apr 2019 22:59:04 +0000 (15:59 -0700)
Original-commit: flang-compiler/f18@aac16907cd0da6d9b68239f2b1a5c697af58e3f8
Reviewed-on: https://github.com/flang-compiler/f18/pull/416
Tree-same-pre-rewrite: false

flang/lib/common/unwrap.h
flang/lib/parser/CMakeLists.txt
flang/lib/parser/parse-tree.h
flang/lib/parser/tools.cc [new file with mode: 0644]
flang/lib/parser/tools.h
flang/lib/semantics/check-coarray.cc
flang/lib/semantics/resolve-names.cc
flang/lib/semantics/rewrite-parse-tree.cc
flang/lib/semantics/tools.h

index d94be84a7523c5b61a64db10c98ffb2702ceb824..e6103a3641def1264dc9dbefd2fd6ff5e9528a06 100644 (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
-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.
index a34e8855adfd84579e383cac88043c90efe3ec37..621ee86c9202e428b5f6c4f0220fbd5b656226ba 100644 (file)
@@ -26,6 +26,7 @@ add_library(FortranParser
   provenance.cc
   source.cc
   token-sequence.cc
+  tools.cc
   unparse.cc
   user-state.cc
 )
index e5487ce5ba8611040752f9c5796cd8c23f1193fc..99503a04ea7f3385f6f760024af9deabf9f5c96f 100644 (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;
diff --git a/flang/lib/parser/tools.cc b/flang/lib/parser/tools.cc
new file mode 100644 (file)
index 0000000..dbb168b
--- /dev/null
@@ -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);
+}
+}
index 63dfb225a90eb538c1bd05adddbefaf0f3fd1745..8a01ab5662c5bc687c60871936c4412ac8ff3e2d 100644 (file)
 
 #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);
 }
 
 }
index 790440cd9e0c5fdd5b060e8c18eb49668e4d6b73..a59a57f991fb61a5766dc100fb8816366a2d0419 100644 (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
index 93cc266d62a61065c1ad0609fd43d7a5cd850b71..ccf6d23b44da95d00eaa899dfe2cc0c6cebece9e 100644 (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;
     }
index de7a83b5c073c9c9fd67ba3dddc9607e458964fe..0a28524101855aead611a6a43a235216a8fe210b 100644 (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();
       }
index b3eb1e2bdc136fd83c748062eed9dbda1f0d99c9..73bebb38d58df3d83bd94ae6a12f3ead3d25d993 100644 (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_