[flang] Use LOC() in iso_c_binding for C_LOC and C_FUNLOC
authorpeter klausler <pklausler@nvidia.com>
Mon, 1 Jul 2019 23:54:53 +0000 (16:54 -0700)
committerpeter klausler <pklausler@nvidia.com>
Mon, 1 Jul 2019 23:54:53 +0000 (16:54 -0700)
Original-commit: flang-compiler/f18@da02305d1baed2e4862568e00810495e7d5dd65b
Reviewed-on: https://github.com/flang-compiler/f18/pull/538
Tree-same-pre-rewrite: false

flang/lib/evaluate/formatting.cc
flang/lib/evaluate/intrinsics.cc
flang/lib/evaluate/type.cc
flang/lib/evaluate/type.h
flang/lib/semantics/expression.cc
flang/lib/semantics/expression.h
flang/lib/semantics/resolve-names.cc
flang/module/iso_c_binding.f90

index f69cfd8..d8ada73 100644 (file)
@@ -397,7 +397,6 @@ std::string DynamicType::AsFortran() const {
   if (derived_ != nullptr) {
     CHECK(category_ == TypeCategory::Derived);
     return DerivedTypeSpecAsFortran(*derived_);
-    // TODO pmk: how to indicate polymorphism?  can't use TYPE() vs CLASS()
   } else if (charLength_ != nullptr) {
     std::string result{"CHARACTER(KIND="s + std::to_string(kind_) + ",LEN="};
     if (charLength_->isAssumed()) {
@@ -410,8 +409,10 @@ std::string DynamicType::AsFortran() const {
       result += ss.str();
     }
     return result + ')';
-  } else if (isPolymorphic_) {
-    return "CLASS(*)";  // not valid, just for debugging
+  } else if (IsUnlimitedPolymorphic()) {
+    return "CLASS(*)";
+  } else if (IsAssumedType()) {
+    return "TYPE(*)";
   } else if (kind_ == 0) {
     return "(typeless intrinsic function argument)";
   } else {
index 64ec571..23371d8 100644 (file)
@@ -957,8 +957,10 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
         }
       } else {
         // NULL(), pointer to subroutine, &c.
-        messages.Say("Typeless item not allowed for '%s=' argument"_err_en_US,
-            d.keyword);
+        if ("loc"s != name) {
+          messages.Say("Typeless item not allowed for '%s=' argument"_err_en_US,
+              d.keyword);
+        }
       }
       return std::nullopt;
     } else if (!d.typePattern.categorySet.test(type->category())) {
@@ -1278,23 +1280,25 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
   for (std::size_t j{0}; j < dummies; ++j) {
     const IntrinsicDummyArgument &d{dummy[std::min(j, dummyArgPatterns - 1)]};
     if (const auto &arg{rearranged[j]}) {
-      const Expr<SomeType> *expr{arg->UnwrapExpr()};
-      CHECK(expr != nullptr);
-      std::optional<characteristics::TypeAndShape> typeAndShape;
-      if (auto type{expr->GetType()}) {
-        if (auto shape{GetShape(context, *expr)}) {
-          typeAndShape.emplace(*type, std::move(*shape));
+      if (const Expr<SomeType> *expr{arg->UnwrapExpr()}) {
+        std::optional<characteristics::TypeAndShape> typeAndShape;
+        if (auto type{expr->GetType()}) {
+          if (auto shape{GetShape(context, *expr)}) {
+            typeAndShape.emplace(*type, std::move(*shape));
+          } else {
+            typeAndShape.emplace(*type);
+          }
         } else {
-          typeAndShape.emplace(*type);
+          typeAndShape.emplace(DynamicType::TypelessIntrinsicArgument());
+        }
+        dummyArgs.emplace_back(
+            characteristics::DummyDataObject{std::move(typeAndShape.value())});
+        if (d.typePattern.kindCode == KindCode::same &&
+            !sameDummyArg.has_value()) {
+          sameDummyArg = j;
         }
       } else {
-        typeAndShape.emplace(DynamicType::TypelessIntrinsicArgument());
-      }
-      dummyArgs.emplace_back(
-          characteristics::DummyDataObject{std::move(typeAndShape.value())});
-      if (d.typePattern.kindCode == KindCode::same &&
-          !sameDummyArg.has_value()) {
-        sameDummyArg = j;
+        CHECK(arg->GetAssumedTypeDummy() != nullptr);
       }
     } else {
       // optional argument is absent
@@ -1465,7 +1469,8 @@ static bool ApplySpecificChecks(
     }
   } else if (name == "loc") {
     if (const auto &arg{call.arguments[0]}) {
-      ok = GetLastSymbol(arg->UnwrapExpr()) != nullptr;
+      ok = arg->GetAssumedTypeDummy() != nullptr ||
+          GetLastSymbol(arg->UnwrapExpr()) != nullptr;
     }
     if (!ok) {
       messages.Say(
index b3d47c8..cf08b91 100644 (file)
@@ -100,8 +100,7 @@ template<typename A> inline bool PointeeComparison(const A *x, const A *y) {
 bool DynamicType::operator==(const DynamicType &that) const {
   return category_ == that.category_ && kind_ == that.kind_ &&
       PointeeComparison(charLength_, that.charLength_) &&
-      PointeeComparison(derived_, that.derived_) &&
-      isPolymorphic_ == that.isPolymorphic_;
+      PointeeComparison(derived_, that.derived_);
 }
 
 bool DynamicType::IsAssumedLengthCharacter() const {
@@ -143,7 +142,8 @@ static const bool IsAncestorTypeOf(const semantics::DerivedTypeSpec *ancestor,
 
 bool DynamicType::IsTypeCompatibleWith(const DynamicType &that) const {
   return *this == that || IsUnlimitedPolymorphic() ||
-      (isPolymorphic_ && IsAncestorTypeOf(derived_, that.derived_));
+      (IsPolymorphic() && derived_ != nullptr &&
+          IsAncestorTypeOf(derived_, that.derived_));
 }
 
 std::optional<DynamicType> DynamicType::From(
@@ -165,8 +165,10 @@ std::optional<DynamicType> DynamicType::From(
         *derived, type.category() == semantics::DeclTypeSpec::ClassDerived};
   } else if (type.category() == semantics::DeclTypeSpec::ClassStar) {
     return DynamicType::UnlimitedPolymorphic();
+  } else if (type.category() == semantics::DeclTypeSpec::TypeStar) {
+    return DynamicType::AssumedType();
   } else {
-    // Assumed-type dummy arguments (TYPE(*)) do not have dynamic types.
+    common::die("DynamicType::From(DeclTypeSpec): failed");
   }
   return std::nullopt;
 }
index 23dc00f..5dc6d23 100644 (file)
@@ -96,7 +96,7 @@ public:
   }
   explicit constexpr DynamicType(
       const semantics::DerivedTypeSpec &dt, bool poly = false)
-    : category_{TypeCategory::Derived}, derived_{&dt}, isPolymorphic_{poly} {}
+    : category_{TypeCategory::Derived}, derived_{&dt} {}
 
   // A rare use case used for representing the characteristics of an
   // intrinsic function like REAL() that accepts a typeless BOZ literal
@@ -110,10 +110,16 @@ public:
 
   static constexpr DynamicType UnlimitedPolymorphic() {
     DynamicType result;
-    result.isPolymorphic_ = true;
+    result.kind_ = 1;
     return result;  // CLASS(*)
   }
 
+  static constexpr DynamicType AssumedType() {
+    DynamicType result;
+    result.kind_ = 2;
+    return result;  // TYPE(*)
+  }
+
   // Comparison is deep -- type parameters are compared independently.
   bool operator==(const DynamicType &) const;
   bool operator!=(const DynamicType &that) const { return !(*this == that); }
@@ -123,15 +129,22 @@ public:
   constexpr const semantics::ParamValue *charLength() const {
     return charLength_;
   }
-  constexpr bool isPolymorphic() const { return isPolymorphic_; }
 
   std::string AsFortran() const;
   std::string AsFortran(std::string &&charLenExpr) const;
   DynamicType ResultTypeForMultiply(const DynamicType &) const;
 
   bool IsAssumedLengthCharacter() const;
+  constexpr bool IsPolymorphic() const {
+    return category_ == TypeCategory::Derived && kind_ > 0;
+  }
   constexpr bool IsUnlimitedPolymorphic() const {
-    return isPolymorphic_ && derived_ == nullptr;
+    return category_ == TypeCategory::Derived && derived_ == nullptr &&
+        kind_ == 1;
+  }
+  constexpr bool IsAssumedType() const {
+    return category_ == TypeCategory::Derived && derived_ == nullptr &&
+        kind_ == 2;
   }
   constexpr const semantics::DerivedTypeSpec &GetDerivedTypeSpec() const {
     CHECK(derived_ != nullptr);
@@ -172,10 +185,9 @@ private:
   constexpr DynamicType() {}
 
   TypeCategory category_{TypeCategory::Derived};  // overridable default
-  int kind_{0};  // set only for intrinsic types
+  int kind_{0};  // for Derived, encodes 1->CLASS(T or *), 2->TYPE(*)
   const semantics::ParamValue *charLength_{nullptr};
   const semantics::DerivedTypeSpec *derived_{nullptr};  // TYPE(T), CLASS(T)
-  bool isPolymorphic_{false};  // CLASS(T), CLASS(*)
 };
 
 std::string DerivedTypeSpecAsFortran(const semantics::DerivedTypeSpec &);
index 9b8bb4c..dd61ecb 100644 (file)
@@ -145,12 +145,6 @@ MaybeExpr ExpressionAnalyzer::Designate(DataRef &&ref) {
     }
   } else if (auto dyType{DynamicType::From(symbol)}) {
     return TypedWrapper<Designator, DataRef>(*dyType, std::move(ref));
-  } else if (const auto *declTypeSpec{symbol.GetType()}) {
-    if (declTypeSpec->category() == semantics::DeclTypeSpec::TypeStar) {
-      Say("TYPE(*) assumed-type dummy argument '%s' may not be "
-          "used except as an actual argument"_err_en_US,
-          symbol.name());
-    }
   }
   return std::nullopt;
 }
@@ -1488,7 +1482,7 @@ auto ExpressionAnalyzer::Procedure(const parser::ProcedureDesignator &pd,
       pd.u);
 }
 
-static const Symbol *AssumedTypeDummy(const parser::Expr &x) {
+template<typename A> static const Symbol *AssumedTypeDummy(const A &x) {
   if (const auto *designator{
           std::get_if<common::Indirection<parser::Designator>>(&x.u)}) {
     if (const auto *dataRef{
@@ -1507,6 +1501,28 @@ static const Symbol *AssumedTypeDummy(const parser::Expr &x) {
   return nullptr;
 }
 
+std::optional<ActualArgument> ExpressionAnalyzer::AnalyzeActualArgument(
+    const parser::Expr &expr) {
+  if (const Symbol * assumedTypeDummy{AssumedTypeDummy(expr)}) {
+    return ActualArgument{ActualArgument::AssumedType{*assumedTypeDummy}};
+  } else if (MaybeExpr argExpr{Analyze(expr)}) {
+    return ActualArgument{Fold(GetFoldingContext(), std::move(*argExpr))};
+  } else {
+    return std::nullopt;
+  }
+}
+
+std::optional<ActualArgument> ExpressionAnalyzer::AnalyzeActualArgument(
+    const parser::Variable &var) {
+  if (const Symbol * assumedTypeDummy{AssumedTypeDummy(var)}) {
+    return ActualArgument{ActualArgument::AssumedType{*assumedTypeDummy}};
+  } else if (MaybeExpr argExpr{Analyze(var)}) {
+    return ActualArgument{std::move(*argExpr)};
+  } else {
+    return std::nullopt;
+  }
+}
+
 MaybeExpr ExpressionAnalyzer::Analyze(
     const parser::FunctionReference &funcRef) {
   // TODO: C1002: Allow a whole assumed-size array to appear if the dummy
@@ -1519,16 +1535,13 @@ MaybeExpr ExpressionAnalyzer::Analyze(
   ActualArguments arguments;
   for (const auto &arg :
       std::get<std::list<parser::ActualArgSpec>>(funcRef.v.t)) {
-    MaybeExpr actualArgExpr;
-    const Symbol *assumedTypeDummy{nullptr};
+    std::optional<ActualArgument> actual;
     std::visit(
         common::visitors{
             [&](const common::Indirection<parser::Expr> &x) {
               // TODO: Distinguish & handle procedure name and
               // proc-component-ref
-              if (!(assumedTypeDummy = AssumedTypeDummy(x.value()))) {
-                actualArgExpr = Analyze(x.value());
-              }
+              actual = AnalyzeActualArgument(x.value());
             },
             [&](const parser::AltReturnSpec &) {
               Say("alternate return specification may not appear on function reference"_err_en_US);
@@ -1541,12 +1554,8 @@ MaybeExpr ExpressionAnalyzer::Analyze(
             },
         },
         std::get<parser::ActualArg>(arg.t).u);
-    if (assumedTypeDummy != nullptr) {
-      arguments.emplace_back(
-          std::make_optional(ActualArgument::AssumedType{*assumedTypeDummy}));
-    } else if (actualArgExpr.has_value()) {
-      arguments.emplace_back(std::make_optional(
-          Fold(GetFoldingContext(), std::move(*actualArgExpr))));
+    if (actual.has_value()) {
+      arguments.emplace_back(std::move(actual));
       if (const auto &argKW{std::get<std::optional<parser::Keyword>>(arg.t)}) {
         arguments.back()->keyword = argKW->v.source;
       }
@@ -1650,15 +1659,15 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::PercentLoc &x) {
   // Represent %LOC() exactly as if it had been a call to the LOC() extension
   // intrinsic function.
   // Use the actual source for the name of the call for error reporting.
-  if (MaybeExpr arg{Analyze(x.v.value())}) {
+  if (std::optional<ActualArgument> arg{AnalyzeActualArgument(x.v.value())}) {
     parser::CharBlock at{GetContextualMessages().at()};
     CHECK(at.size() >= 4);
     parser::CharBlock loc{at.begin() + 1, 3};
     CHECK(loc == "loc");
-    return MakeFunctionRef(
-        loc, ActualArguments{ActualArgument{std::move(*arg)}});
+    return MakeFunctionRef(loc, ActualArguments{std::move(*arg)});
+  } else {
+    return std::nullopt;
   }
-  return std::nullopt;
 }
 
 MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedUnary &) {
index 5cc6fb5..5547eca 100644 (file)
@@ -308,9 +308,10 @@ private:
   MaybeExpr TopLevelChecks(DataRef &&);
   std::optional<Expr<SubscriptInteger>> GetSubstringBound(
       const std::optional<parser::ScalarIntExpr> &);
-
   std::optional<ProcedureDesignator> AnalyzeProcedureComponentRef(
       const parser::ProcComponentRef &);
+  std::optional<ActualArgument> AnalyzeActualArgument(const parser::Expr &);
+  std::optional<ActualArgument> AnalyzeActualArgument(const parser::Variable &);
 
   struct CalleeAndArguments {
     ProcedureDesignator procedureDesignator;
index 2c03f9b..5db1799 100644 (file)
@@ -4272,10 +4272,16 @@ const DeclTypeSpec &ConstructVisitor::ToDeclTypeSpec(
   case common::TypeCategory::Logical:
     return context().MakeLogicalType(type.kind());
   case common::TypeCategory::Derived:
-    return currScope().MakeDerivedType(type.isPolymorphic()
-            ? DeclTypeSpec::ClassDerived
-            : DeclTypeSpec::TypeDerived,
-        DerivedTypeSpec{type.GetDerivedTypeSpec()});
+    if (type.IsAssumedType()) {
+      return currScope().MakeTypeStarType();
+    } else if (type.IsUnlimitedPolymorphic()) {
+      return currScope().MakeClassStarType();
+    } else {
+      return currScope().MakeDerivedType(type.IsPolymorphic()
+              ? DeclTypeSpec::ClassDerived
+              : DeclTypeSpec::TypeDerived,
+          DerivedTypeSpec{type.GetDerivedTypeSpec()});
+    }
   case common::TypeCategory::Character:
   default: CRASH_NO_CASE;
   }
index 479ddcb..5a9dfe3 100644 (file)
@@ -72,7 +72,7 @@ module iso_c_binding
     c_long_double_complex = c_long_double
 
   integer, parameter :: c_bool = 1 ! TODO: or default LOGICAL?
-  integer, parameter :: c_char = 1 ! TODO: Kanji mode
+  integer, parameter :: c_char = 1
 
  contains
 
@@ -96,9 +96,19 @@ module iso_c_binding
     ! TODO: Define, or write in C and change this to an interface
   end subroutine c_f_pointer
 
+  function c_loc(x)
+    type(c_ptr) :: c_loc
+    type(*), intent(in) :: x
+    c_loc = c_ptr(loc(x))
+  end function c_loc
+
+  function c_funloc(x)
+    type(c_funptr) :: c_funloc
+    external :: x
+    c_funloc = c_funptr(loc(x))
+  end function c_funloc
+
   ! TODO c_f_procpointer
-  ! TODO c_funcloc
-  ! TODO c_loc
   ! TODO c_sizeof
 
 end module iso_c_binding