[flang-commits] [flang] 8d0c3c0 - [flang] New implementation for checks for constraints C741 through C750
Pete Steinfeld via flang-commits
flang-commits at lists.llvm.org
Tue May 5 09:38:08 PDT 2020
Author: Pete Steinfeld
Date: 2020-05-05T09:37:39-07:00
New Revision: 8d0c3c05f2f4b9e827eff98b7a375d174a163570
URL: https://github.com/llvm/llvm-project/commit/8d0c3c05f2f4b9e827eff98b7a375d174a163570
DIFF: https://github.com/llvm/llvm-project/commit/8d0c3c05f2f4b9e827eff98b7a375d174a163570.diff
LOG: [flang] New implementation for checks for constraints C741 through C750
Summary:
Most of these checks were already implemented, and I just added references to
them to the code and tests. Also, much of this code was already
reviewed in the old flang/f18 GitHub repository, but I didn't get to
merge it before we switched repositories.
I implemented the check for C747 to not allow coarray components in derived
types that are of type C_PTR, C_FUNPTR, or type TEAM_TYPE.
I implemented the check for C748 that requires a data component whose type has
a coarray ultimate component to be a nonpointer, nonallocatable scalar and not
be a coarray.
I implemented the check for C750 that adds additional restrictions to the
bounds expressions of a derived type component that's an array.
These bounds expressions are sepcification expressions as defined in
10.1.11. There was already code in lib/Evaluate/check-expression.cpp to
check semantics for specification expressions, but it did not check for
the extra requirements of C750.
C750 prohibits specification functions, the intrinsic functions
ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT, and SAME_TYPE_AS. It
also requires every specification inquiry reference to be a constant
expression, and requires that the value of the bound not depend on the
value of a variable.
To implement these additional checks, I added code to the intrinsic proc
table to get the intrinsic class of a procedure. I also added an
enumeration to distinguish between specification expressions for
derived type component bounds versus for type parameters. I then
changed the code to pass an enumeration value to
"CheckSpecificationExpr()" to indicate that the expression was a bounds
expression and used this value to determine whether to emit an error
message when violations of C750 are found.
I changed the implementation of IsPureProcedure() to handle statement
functions and changed some references in the code that tested for the
PURE attribute to call IsPureProcedure().
I also fixed some unrelated tests that got new errors when I implemented these
new checks.
Reviewers: tskeith, DavidTruby, sscalpone
Subscribers: jfb, llvm-commits
Tags: #llvm, #flang
Differential Revision: https://reviews.llvm.org/D79263
Added:
flang/test/Semantics/resolve88.f90
flang/test/Semantics/resolve89.f90
Modified:
flang/include/flang/Evaluate/check-expression.h
flang/include/flang/Evaluate/intrinsics.h
flang/lib/Evaluate/check-expression.cpp
flang/lib/Evaluate/intrinsics.cpp
flang/lib/Semantics/check-declarations.cpp
flang/lib/Semantics/expression.cpp
flang/lib/Semantics/resolve-names.cpp
flang/lib/Semantics/tools.cpp
flang/test/Semantics/allocate11.f90
flang/test/Semantics/call12.f90
flang/test/Semantics/call14.f90
flang/test/Semantics/misc-declarations.f90
flang/test/Semantics/modfile24.f90
flang/test/Semantics/resolve33.f90
flang/test/Semantics/resolve44.f90
Removed:
################################################################################
diff --git a/flang/include/flang/Evaluate/check-expression.h b/flang/include/flang/Evaluate/check-expression.h
index a26f83b01bbb..b14a47838e3a 100644
--- a/flang/include/flang/Evaluate/check-expression.h
+++ b/flang/include/flang/Evaluate/check-expression.h
@@ -12,6 +12,7 @@
#define FORTRAN_EVALUATE_CHECK_EXPRESSION_H_
#include "expression.h"
+#include "intrinsics.h"
#include "type.h"
#include <optional>
@@ -41,24 +42,38 @@ bool IsInitialDataTarget(
// Check whether an expression is a specification expression
// (10.1.11(2), C1010). Constant expressions are always valid
// specification expressions.
+
+// There are two contexts where specification expressions appear -- array
+// bounds and type param expressions. We need to
diff erentiate them because
+// additional checks are required for array bounds expressions in declarations
+// of derived type components (see C750).
+ENUM_CLASS(SpecificationExprContext, TYPE_PARAM, BOUND)
+
template <typename A>
-void CheckSpecificationExpr(
- const A &, parser::ContextualMessages &, const semantics::Scope &);
+void CheckSpecificationExpr(const A &, parser::ContextualMessages &,
+ const semantics::Scope &, const IntrinsicProcTable &,
+ SpecificationExprContext);
extern template void CheckSpecificationExpr(const Expr<SomeType> &x,
- parser::ContextualMessages &, const semantics::Scope &);
+ parser::ContextualMessages &, const semantics::Scope &,
+ const IntrinsicProcTable &, SpecificationExprContext);
extern template void CheckSpecificationExpr(const Expr<SomeInteger> &x,
- parser::ContextualMessages &, const semantics::Scope &);
+ parser::ContextualMessages &, const semantics::Scope &,
+ const IntrinsicProcTable &, SpecificationExprContext);
extern template void CheckSpecificationExpr(const Expr<SubscriptInteger> &x,
- parser::ContextualMessages &, const semantics::Scope &);
+ parser::ContextualMessages &, const semantics::Scope &,
+ const IntrinsicProcTable &, SpecificationExprContext);
extern template void CheckSpecificationExpr(
const std::optional<Expr<SomeType>> &x, parser::ContextualMessages &,
- const semantics::Scope &);
+ const semantics::Scope &, const IntrinsicProcTable &,
+ SpecificationExprContext);
extern template void CheckSpecificationExpr(
const std::optional<Expr<SomeInteger>> &x, parser::ContextualMessages &,
- const semantics::Scope &);
+ const semantics::Scope &, const IntrinsicProcTable &,
+ SpecificationExprContext);
extern template void CheckSpecificationExpr(
const std::optional<Expr<SubscriptInteger>> &x,
- parser::ContextualMessages &, const semantics::Scope &);
+ parser::ContextualMessages &, const semantics::Scope &,
+ const IntrinsicProcTable &, SpecificationExprContext);
// Simple contiguity (9.5.4)
template <typename A>
diff --git a/flang/include/flang/Evaluate/intrinsics.h b/flang/include/flang/Evaluate/intrinsics.h
index fc7963818919..88d6a7af13eb 100644
--- a/flang/include/flang/Evaluate/intrinsics.h
+++ b/flang/include/flang/Evaluate/intrinsics.h
@@ -55,6 +55,11 @@ struct SpecificIntrinsicFunctionInterface : public characteristics::Procedure {
// All argument and result types are intrinsic types with default kinds.
};
+// Generic intrinsic classes from table 16.1
+ENUM_CLASS(IntrinsicClass, atomicSubroutine, collectiveSubroutine,
+ elementalFunction, elementalSubroutine, inquiryFunction, pureSubroutine,
+ impureSubroutine, transformationalFunction, noClass)
+
class IntrinsicProcTable {
private:
class Implementation;
@@ -68,6 +73,9 @@ class IntrinsicProcTable {
// statement.
bool IsIntrinsic(const std::string &) const;
+ // Inquiry intrinsics are defined in section 16.7, table 16.1
+ IntrinsicClass GetIntrinsicClass(const std::string &) const;
+
// Probe the intrinsics for a match against a specific call.
// On success, the actual arguments are transferred to the result
// in dummy argument order; on failure, the actual arguments remain
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 3f71cb6a1aea..43686815ab35 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -7,10 +7,13 @@
//===----------------------------------------------------------------------===//
#include "flang/Evaluate/check-expression.h"
+#include "flang/Evaluate/intrinsics.h"
#include "flang/Evaluate/traverse.h"
#include "flang/Evaluate/type.h"
#include "flang/Semantics/symbol.h"
#include "flang/Semantics/tools.h"
+#include <set>
+#include <string>
namespace Fortran::evaluate {
@@ -171,6 +174,7 @@ class IsInitialDataTargetHelper
return (*this)(x.left());
}
bool operator()(const Relational<SomeType> &) const { return false; }
+
private:
parser::ContextualMessages *messages_;
};
@@ -187,8 +191,10 @@ class CheckSpecificationExprHelper
public:
using Result = std::optional<std::string>;
using Base = AnyTraverse<CheckSpecificationExprHelper, Result>;
- explicit CheckSpecificationExprHelper(const semantics::Scope &s)
- : Base{*this}, scope_{s} {}
+ explicit CheckSpecificationExprHelper(const semantics::Scope &s,
+ const IntrinsicProcTable &table, SpecificationExprContext specExprContext)
+ : Base{*this}, scope_{s}, table_{table}, specExprContext_{
+ specExprContext} {}
using Base::operator();
Result operator()(const ProcedureDesignator &) const {
@@ -199,6 +205,10 @@ class CheckSpecificationExprHelper
Result operator()(const semantics::Symbol &symbol) const {
if (semantics::IsNamedConstant(symbol)) {
return std::nullopt;
+ } else if (scope_.IsDerivedType() && IsVariableName(symbol) &&
+ specExprContext_ == SpecificationExprContext::BOUND) { // C750
+ return "reference to variable '"s + symbol.name().ToString() +
+ "' not allowed for derived type components";
} else if (symbol.IsDummy()) {
if (symbol.attrs().test(semantics::Attr::OPTIONAL)) {
return "reference to OPTIONAL dummy argument '"s +
@@ -243,16 +253,51 @@ class CheckSpecificationExprHelper
return std::nullopt;
}
+ template <int KIND>
+ Result operator()(const TypeParamInquiry<KIND> &inq) const {
+ if (scope_.IsDerivedType() && !IsConstantExpr(inq) &&
+ inq.parameter().owner() != scope_ &&
+ specExprContext_ == SpecificationExprContext::BOUND) { // C750
+ return "non-constant reference to a type parameter inquiry "
+ "not allowed for derived type components";
+ }
+ return std::nullopt;
+ }
+
template <typename T> Result operator()(const FunctionRef<T> &x) const {
if (const auto *symbol{x.proc().GetSymbol()}) {
if (!semantics::IsPureProcedure(*symbol)) {
return "reference to impure function '"s + symbol->name().ToString() +
"'";
}
+ if (semantics::IsStmtFunction(*symbol)) {
+ return "reference to statement function '"s +
+ symbol->name().ToString() + "'";
+ }
+ if (scope_.IsDerivedType() &&
+ specExprContext_ == SpecificationExprContext::BOUND) { // C750
+ return "reference to function '"s + symbol->name().ToString() +
+ "' not allowed for derived type components";
+ }
// TODO: other checks for standard module procedures
} else {
const SpecificIntrinsic &intrin{DEREF(x.proc().GetSpecificIntrinsic())};
- if (intrin.name == "present") {
+ if (scope_.IsDerivedType() &&
+ specExprContext_ == SpecificationExprContext::BOUND) { // C750
+ if ((table_.IsIntrinsic(intrin.name) &&
+ badIntrinsicsForComponents_.find(intrin.name) !=
+ badIntrinsicsForComponents_.end()) ||
+ IsProhibitedFunction(intrin.name)) {
+ return "reference to intrinsic '"s + intrin.name +
+ "' not allowed for derived type components";
+ }
+ if (table_.GetIntrinsicClass(intrin.name) ==
+ IntrinsicClass::inquiryFunction &&
+ !IsConstantExpr(x)) {
+ return "non-constant reference to inquiry intrinsic '"s +
+ intrin.name + "' not allowed for derived type components";
+ }
+ } else if (intrin.name == "present") {
return std::nullopt; // no need to check argument(s)
}
if (IsConstantExpr(x)) {
@@ -265,29 +310,42 @@ class CheckSpecificationExprHelper
private:
const semantics::Scope &scope_;
+ const IntrinsicProcTable &table_;
+ const SpecificationExprContext specExprContext_;
+ const std::set<std::string> badIntrinsicsForComponents_{
+ "allocated", "associated", "extends_type_of", "present", "same_type_as"};
+ static bool IsProhibitedFunction(std::string name) { return false; }
};
template <typename A>
void CheckSpecificationExpr(const A &x, parser::ContextualMessages &messages,
- const semantics::Scope &scope) {
- if (auto why{CheckSpecificationExprHelper{scope}(x)}) {
+ const semantics::Scope &scope, const IntrinsicProcTable &table,
+ SpecificationExprContext specExprContext) {
+ if (auto why{
+ CheckSpecificationExprHelper{scope, table, specExprContext}(x)}) {
messages.Say("Invalid specification expression: %s"_err_en_US, *why);
}
}
template void CheckSpecificationExpr(const Expr<SomeType> &,
- parser::ContextualMessages &, const semantics::Scope &);
+ parser::ContextualMessages &, const semantics::Scope &,
+ const IntrinsicProcTable &, SpecificationExprContext);
template void CheckSpecificationExpr(const Expr<SomeInteger> &,
- parser::ContextualMessages &, const semantics::Scope &);
+ parser::ContextualMessages &, const semantics::Scope &,
+ const IntrinsicProcTable &, SpecificationExprContext);
template void CheckSpecificationExpr(const Expr<SubscriptInteger> &,
- parser::ContextualMessages &, const semantics::Scope &);
+ parser::ContextualMessages &, const semantics::Scope &,
+ const IntrinsicProcTable &, SpecificationExprContext);
template void CheckSpecificationExpr(const std::optional<Expr<SomeType>> &,
- parser::ContextualMessages &, const semantics::Scope &);
+ parser::ContextualMessages &, const semantics::Scope &,
+ const IntrinsicProcTable &, SpecificationExprContext);
template void CheckSpecificationExpr(const std::optional<Expr<SomeInteger>> &,
- parser::ContextualMessages &, const semantics::Scope &);
+ parser::ContextualMessages &, const semantics::Scope &,
+ const IntrinsicProcTable &, SpecificationExprContext);
template void CheckSpecificationExpr(
const std::optional<Expr<SubscriptInteger>> &, parser::ContextualMessages &,
- const semantics::Scope &);
+ const semantics::Scope &, const IntrinsicProcTable &,
+ SpecificationExprContext);
// IsSimplyContiguous() -- 9.5.4
class IsSimplyContiguousHelper
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index cbf082bd8ac5..605b100f42f3 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -229,6 +229,7 @@ struct IntrinsicInterface {
IntrinsicDummyArgument dummy[maxArguments];
TypePattern result;
Rank rank{Rank::elemental};
+ IntrinsicClass intrinsicClass{IntrinsicClass::elementalFunction};
std::optional<SpecificCall> Match(const CallCharacteristics &,
const common::IntrinsicTypeDefaultKinds &, ActualArguments &,
FoldingContext &context) const;
@@ -265,19 +266,21 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"aimag", {{"x", SameComplex}}, SameReal},
{"aint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal},
{"all", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
- Rank::dimReduced},
- {"allocated", {{"array", AnyData, Rank::array}}, DefaultLogical},
- {"allocated", {{"scalar", AnyData, Rank::scalar}}, DefaultLogical},
+ Rank::dimReduced, IntrinsicClass::transformationalFunction},
+ {"allocated", {{"array", AnyData, Rank::array}}, DefaultLogical,
+ Rank::elemental, IntrinsicClass::inquiryFunction},
+ {"allocated", {{"scalar", AnyData, Rank::scalar}}, DefaultLogical,
+ Rank::elemental, IntrinsicClass::inquiryFunction},
{"anint", {{"a", SameReal}, MatchingDefaultKIND}, KINDReal},
{"any", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
- Rank::dimReduced},
+ Rank::dimReduced, IntrinsicClass::transformationalFunction},
{"asin", {{"x", SameFloating}}, SameFloating},
{"asind", {{"x", SameFloating}}, SameFloating},
{"asinh", {{"x", SameFloating}}, SameFloating},
{"associated",
{{"pointer", Addressable, Rank::known},
{"target", Addressable, Rank::known, Optionality::optional}},
- DefaultLogical},
+ DefaultLogical, Rank::elemental, IntrinsicClass::inquiryFunction},
{"atan", {{"x", SameFloating}}, SameFloating},
{"atand", {{"x", SameFloating}}, SameFloating},
{"atan", {{"y", OperandReal}, {"x", OperandReal}}, OperandReal},
@@ -291,14 +294,14 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"bessel_jn",
{{"n1", AnyInt, Rank::scalar}, {"n2", AnyInt, Rank::scalar},
{"x", SameReal, Rank::scalar}},
- SameReal, Rank::vector},
+ SameReal, Rank::vector, IntrinsicClass::transformationalFunction},
{"bessel_y0", {{"x", SameReal}}, SameReal},
{"bessel_y1", {{"x", SameReal}}, SameReal},
{"bessel_yn", {{"n", AnyInt}, {"x", SameReal}}, SameReal},
{"bessel_yn",
{{"n1", AnyInt, Rank::scalar}, {"n2", AnyInt, Rank::scalar},
{"x", SameReal, Rank::scalar}},
- SameReal, Rank::vector},
+ SameReal, Rank::vector, IntrinsicClass::transformationalFunction},
{"bge",
{{"i", AnyInt, Rank::elementalOrBOZ},
{"j", AnyInt, Rank::elementalOrBOZ}},
@@ -308,7 +311,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"j", AnyInt, Rank::elementalOrBOZ}},
DefaultLogical},
{"bit_size", {{"i", SameInt, Rank::anyOrAssumedRank}}, SameInt,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::inquiryFunction},
{"ble",
{{"i", AnyInt, Rank::elementalOrBOZ},
{"j", AnyInt, Rank::elementalOrBOZ}},
@@ -327,34 +330,36 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"y", AnyIntOrReal, Rank::elementalOrBOZ, Optionality::optional},
DefaultingKIND},
KINDComplex},
- {"command_argument_count", {}, DefaultInt, Rank::scalar},
+ {"command_argument_count", {}, DefaultInt, Rank::scalar,
+ IntrinsicClass::transformationalFunction},
{"conjg", {{"z", SameComplex}}, SameComplex},
{"cos", {{"x", SameFloating}}, SameFloating},
{"cosd", {{"x", SameFloating}}, SameFloating},
{"cosh", {{"x", SameFloating}}, SameFloating},
{"count", {{"mask", AnyLogical, Rank::array}, OptionalDIM, DefaultingKIND},
- KINDInt, Rank::dimReduced},
+ KINDInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
{"cshift",
{{"array", SameType, Rank::array}, {"shift", AnyInt, Rank::dimRemoved},
OptionalDIM},
- SameType, Rank::conformable},
+ SameType, Rank::conformable, IntrinsicClass::transformationalFunction},
{"dble", {{"a", AnyNumeric, Rank::elementalOrBOZ}}, DoublePrecision},
{"digits", {{"x", AnyIntOrReal, Rank::anyOrAssumedRank}}, DefaultInt,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::inquiryFunction},
{"dim", {{"x", OperandIntOrReal}, {"y", OperandIntOrReal}},
OperandIntOrReal},
{"dot_product",
{{"vector_a", AnyLogical, Rank::vector},
{"vector_b", AnyLogical, Rank::vector}},
- ResultLogical, Rank::scalar},
+ ResultLogical, Rank::scalar, IntrinsicClass::transformationalFunction},
{"dot_product",
{{"vector_a", AnyComplex, Rank::vector},
{"vector_b", AnyNumeric, Rank::vector}},
- ResultNumeric, Rank::scalar}, // conjugates vector_a
+ ResultNumeric, Rank::scalar, // conjugates vector_a
+ IntrinsicClass::transformationalFunction},
{"dot_product",
{{"vector_a", AnyIntOrReal, Rank::vector},
{"vector_b", AnyNumeric, Rank::vector}},
- ResultNumeric, Rank::scalar},
+ ResultNumeric, Rank::scalar, IntrinsicClass::transformationalFunction},
{"dprod", {{"x", DefaultReal}, {"y", DefaultReal}}, DoublePrecision},
{"dshiftl",
{{"i", SameInt}, {"j", SameInt, Rank::elementalOrBOZ},
@@ -372,68 +377,72 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"boundary", SameIntrinsic, Rank::dimRemoved,
Optionality::optional},
OptionalDIM},
- SameIntrinsic, Rank::conformable},
+ SameIntrinsic, Rank::conformable,
+ IntrinsicClass::transformationalFunction},
{"eoshift",
{{"array", SameDerivedType, Rank::array},
{"shift", AnyInt, Rank::dimRemoved},
{"boundary", SameDerivedType, Rank::dimRemoved}, OptionalDIM},
- SameDerivedType, Rank::conformable},
+ SameDerivedType, Rank::conformable,
+ IntrinsicClass::transformationalFunction},
{"epsilon", {{"x", SameReal, Rank::anyOrAssumedRank}}, SameReal,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::inquiryFunction},
{"erf", {{"x", SameReal}}, SameReal},
{"erfc", {{"x", SameReal}}, SameReal},
{"erfc_scaled", {{"x", SameReal}}, SameReal},
{"exp", {{"x", SameFloating}}, SameFloating},
+ {"exp", {{"x", SameFloating}}, SameFloating},
{"exponent", {{"x", AnyReal}}, DefaultInt},
+ {"exp", {{"x", SameFloating}}, SameFloating},
{"extends_type_of",
{{"a", ExtensibleDerived, Rank::anyOrAssumedRank},
{"mold", ExtensibleDerived, Rank::anyOrAssumedRank}},
- DefaultLogical, Rank::scalar},
+ DefaultLogical, Rank::scalar, IntrinsicClass::inquiryFunction},
{"findloc",
{{"array", AnyNumeric, Rank::array},
{"value", AnyNumeric, Rank::scalar}, RequiredDIM, OptionalMASK,
SizeDefaultKIND,
{"back", AnyLogical, Rank::scalar, Optionality::optional}},
- KINDInt, Rank::dimRemoved},
+ KINDInt, Rank::dimRemoved, IntrinsicClass::transformationalFunction},
{"findloc",
{{"array", AnyNumeric, Rank::array},
{"value", AnyNumeric, Rank::scalar}, OptionalMASK, SizeDefaultKIND,
{"back", AnyLogical, Rank::scalar, Optionality::optional}},
- KINDInt, Rank::vector},
+ KINDInt, Rank::vector, IntrinsicClass::transformationalFunction},
{"findloc",
{{"array", SameChar, Rank::array}, {"value", SameChar, Rank::scalar},
RequiredDIM, OptionalMASK, SizeDefaultKIND,
{"back", AnyLogical, Rank::scalar, Optionality::optional}},
- KINDInt, Rank::dimRemoved},
+ KINDInt, Rank::dimRemoved, IntrinsicClass::transformationalFunction},
{"findloc",
{{"array", SameChar, Rank::array}, {"value", SameChar, Rank::scalar},
OptionalMASK, SizeDefaultKIND,
{"back", AnyLogical, Rank::scalar, Optionality::optional}},
- KINDInt, Rank::vector},
+ KINDInt, Rank::vector, IntrinsicClass::transformationalFunction},
{"findloc",
{{"array", AnyLogical, Rank::array},
{"value", AnyLogical, Rank::scalar}, RequiredDIM, OptionalMASK,
SizeDefaultKIND,
{"back", AnyLogical, Rank::scalar, Optionality::optional}},
- KINDInt, Rank::dimRemoved},
+ KINDInt, Rank::dimRemoved, IntrinsicClass::transformationalFunction},
{"findloc",
{{"array", AnyLogical, Rank::array},
{"value", AnyLogical, Rank::scalar}, OptionalMASK, SizeDefaultKIND,
{"back", AnyLogical, Rank::scalar, Optionality::optional}},
- KINDInt, Rank::vector},
+ KINDInt, Rank::vector, IntrinsicClass::transformationalFunction},
{"floor", {{"a", AnyReal}, DefaultingKIND}, KINDInt},
{"fraction", {{"x", SameReal}}, SameReal},
{"gamma", {{"x", SameReal}}, SameReal},
{"huge", {{"x", SameIntOrReal, Rank::anyOrAssumedRank}}, SameIntOrReal,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::inquiryFunction},
{"hypot", {{"x", OperandReal}, {"y", OperandReal}}, OperandReal},
{"iachar", {{"c", AnyChar}, DefaultingKIND}, KINDInt},
{"iall", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
- SameInt, Rank::dimReduced},
+ SameInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
{"iany", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
- SameInt, Rank::dimReduced},
+ SameInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
{"iparity", {{"array", SameInt, Rank::array}, OptionalDIM, OptionalMASK},
- SameInt, Rank::dimReduced},
+ SameInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
{"iand", {{"i", SameInt}, {"j", SameInt, Rank::elementalOrBOZ}}, SameInt},
{"iand", {{"i", BOZ}, {"j", SameInt}}, SameInt},
{"ibclr", {{"i", SameInt}, {"pos", AnyInt}}, SameInt},
@@ -461,19 +470,20 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"size", AnyInt, Rank::elemental, Optionality::optional}},
SameInt},
{"is_contiguous", {{"array", Addressable, Rank::anyOrAssumedRank}},
- DefaultLogical},
+ DefaultLogical, Rank::elemental, IntrinsicClass::inquiryFunction},
{"is_iostat_end", {{"i", AnyInt}}, DefaultLogical},
{"is_iostat_eor", {{"i", AnyInt}}, DefaultLogical},
- {"kind", {{"x", AnyIntrinsic}}, DefaultInt},
+ {"kind", {{"x", AnyIntrinsic}}, DefaultInt, Rank::elemental,
+ IntrinsicClass::inquiryFunction},
{"lbound",
{{"array", AnyData, Rank::anyOrAssumedRank}, RequiredDIM,
SizeDefaultKIND},
- KINDInt, Rank::scalar},
+ KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction},
{"lbound", {{"array", AnyData, Rank::anyOrAssumedRank}, SizeDefaultKIND},
- KINDInt, Rank::vector},
+ KINDInt, Rank::vector, IntrinsicClass::inquiryFunction},
{"leadz", {{"i", AnyInt}}, DefaultInt},
{"len", {{"string", AnyChar, Rank::anyOrAssumedRank}, DefaultingKIND},
- KINDInt, Rank::scalar},
+ KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction},
{"len_trim", {{"string", AnyChar}, DefaultingKIND}, KINDInt},
{"lge", {{"string_a", SameChar}, {"string_b", SameChar}}, DefaultLogical},
{"lgt", {{"string_a", SameChar}, {"string_b", SameChar}}, DefaultLogical},
@@ -488,27 +498,27 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"matmul",
{{"array_a", AnyLogical, Rank::vector},
{"array_b", AnyLogical, Rank::matrix}},
- ResultLogical, Rank::vector},
+ ResultLogical, Rank::vector, IntrinsicClass::transformationalFunction},
{"matmul",
{{"array_a", AnyLogical, Rank::matrix},
{"array_b", AnyLogical, Rank::vector}},
- ResultLogical, Rank::vector},
+ ResultLogical, Rank::vector, IntrinsicClass::transformationalFunction},
{"matmul",
{{"array_a", AnyLogical, Rank::matrix},
{"array_b", AnyLogical, Rank::matrix}},
- ResultLogical, Rank::matrix},
+ ResultLogical, Rank::matrix, IntrinsicClass::transformationalFunction},
{"matmul",
{{"array_a", AnyNumeric, Rank::vector},
{"array_b", AnyNumeric, Rank::matrix}},
- ResultNumeric, Rank::vector},
+ ResultNumeric, Rank::vector, IntrinsicClass::transformationalFunction},
{"matmul",
{{"array_a", AnyNumeric, Rank::matrix},
{"array_b", AnyNumeric, Rank::vector}},
- ResultNumeric, Rank::vector},
+ ResultNumeric, Rank::vector, IntrinsicClass::transformationalFunction},
{"matmul",
{{"array_a", AnyNumeric, Rank::matrix},
{"array_b", AnyNumeric, Rank::matrix}},
- ResultNumeric, Rank::matrix},
+ ResultNumeric, Rank::matrix, IntrinsicClass::transformationalFunction},
{"maskl", {{"i", AnyInt}, DefaultingKIND}, KINDInt},
{"maskr", {{"i", AnyInt}, DefaultingKIND}, KINDInt},
{"max",
@@ -520,15 +530,16 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"a3", SameChar, Rank::elemental, Optionality::repeats}},
SameChar},
{"maxexponent", {{"x", AnyReal, Rank::anyOrAssumedRank}}, DefaultInt,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::inquiryFunction},
{"maxloc",
{{"array", AnyRelatable, Rank::array}, OptionalDIM, OptionalMASK,
SizeDefaultKIND,
{"back", AnyLogical, Rank::scalar, Optionality::optional}},
- KINDInt, Rank::dimReduced},
+ KINDInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
{"maxval",
{{"array", SameRelatable, Rank::array}, OptionalDIM, OptionalMASK},
- SameRelatable, Rank::dimReduced},
+ SameRelatable, Rank::dimReduced,
+ IntrinsicClass::transformationalFunction},
{"merge",
{{"tsource", SameType}, {"fsource", SameType}, {"mask", AnyLogical}},
SameType},
@@ -548,25 +559,26 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"a3", SameChar, Rank::elemental, Optionality::repeats}},
SameChar},
{"minexponent", {{"x", AnyReal, Rank::anyOrAssumedRank}}, DefaultInt,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::inquiryFunction},
{"minloc",
{{"array", AnyRelatable, Rank::array}, OptionalDIM, OptionalMASK,
SizeDefaultKIND,
{"back", AnyLogical, Rank::scalar, Optionality::optional}},
- KINDInt, Rank::dimReduced},
+ KINDInt, Rank::dimReduced, IntrinsicClass::transformationalFunction},
{"minval",
{{"array", SameRelatable, Rank::array}, OptionalDIM, OptionalMASK},
- SameRelatable, Rank::dimReduced},
+ SameRelatable, Rank::dimReduced,
+ IntrinsicClass::transformationalFunction},
{"mod", {{"a", OperandIntOrReal}, {"p", OperandIntOrReal}},
OperandIntOrReal},
{"modulo", {{"a", OperandIntOrReal}, {"p", OperandIntOrReal}},
OperandIntOrReal},
{"nearest", {{"x", SameReal}, {"s", AnyReal}}, SameReal},
{"new_line", {{"x", SameChar, Rank::anyOrAssumedRank}}, SameChar,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::inquiryFunction},
{"nint", {{"a", AnyReal}, DefaultingKIND}, KINDInt},
{"norm2", {{"x", SameReal, Rank::array}, OptionalDIM}, SameReal,
- Rank::dimReduced},
+ Rank::dimReduced, IntrinsicClass::transformationalFunction},
{"not", {{"i", SameInt}}, SameInt},
// NULL() is a special case handled in Probe() below
{"out_of_range",
@@ -581,24 +593,25 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{{"array", SameType, Rank::array},
{"mask", AnyLogical, Rank::conformable},
{"vector", SameType, Rank::vector, Optionality::optional}},
- SameType, Rank::vector},
+ SameType, Rank::vector, IntrinsicClass::transformationalFunction},
{"parity", {{"mask", SameLogical, Rank::array}, OptionalDIM}, SameLogical,
- Rank::dimReduced},
+ Rank::dimReduced, IntrinsicClass::transformationalFunction},
{"popcnt", {{"i", AnyInt}}, DefaultInt},
{"poppar", {{"i", AnyInt}}, DefaultInt},
{"product",
{{"array", SameNumeric, Rank::array}, OptionalDIM, OptionalMASK},
- SameNumeric, Rank::dimReduced},
+ SameNumeric, Rank::dimReduced,
+ IntrinsicClass::transformationalFunction},
{"precision", {{"x", AnyFloating, Rank::anyOrAssumedRank}}, DefaultInt,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::inquiryFunction},
{"present", {{"a", Addressable, Rank::anyOrAssumedRank}}, DefaultLogical,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::inquiryFunction},
{"radix", {{"x", AnyIntOrReal, Rank::anyOrAssumedRank}}, DefaultInt,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::inquiryFunction},
{"range", {{"x", AnyNumeric, Rank::anyOrAssumedRank}}, DefaultInt,
- Rank::scalar},
- {"rank", {{"a", AnyData, Rank::anyOrAssumedRank}}, DefaultInt,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::inquiryFunction},
+ {"rank", {{"a", AnyData, Rank::anyOrAssumedRank}}, DefaultInt, Rank::scalar,
+ IntrinsicClass::inquiryFunction},
{"real", {{"a", SameComplex, Rank::elemental}},
SameReal}, // 16.9.160(4)(ii)
{"real", {{"a", AnyNumeric, Rank::elementalOrBOZ}, DefaultingKIND},
@@ -608,19 +621,19 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"operation", SameType, Rank::reduceOperation}, OptionalDIM,
OptionalMASK, {"identity", SameType, Rank::scalar},
{"ordered", AnyLogical, Rank::scalar, Optionality::optional}},
- SameType, Rank::dimReduced},
+ SameType, Rank::dimReduced, IntrinsicClass::transformationalFunction},
{"repeat", {{"string", SameChar, Rank::scalar}, {"ncopies", AnyInt}},
- SameChar, Rank::scalar},
+ SameChar, Rank::scalar, IntrinsicClass::transformationalFunction},
{"reshape",
{{"source", SameType, Rank::array}, {"shape", AnyInt, Rank::shape},
{"pad", SameType, Rank::array, Optionality::optional},
{"order", AnyInt, Rank::vector, Optionality::optional}},
- SameType, Rank::shaped},
+ SameType, Rank::shaped, IntrinsicClass::transformationalFunction},
{"rrspacing", {{"x", SameReal}}, SameReal},
{"same_type_as",
{{"a", ExtensibleDerived, Rank::anyOrAssumedRank},
{"b", ExtensibleDerived, Rank::anyOrAssumedRank}},
- DefaultLogical, Rank::scalar},
+ DefaultLogical, Rank::scalar, IntrinsicClass::inquiryFunction},
{"scale", {{"x", SameReal}, {"i", AnyInt}}, SameReal},
{"scan",
{{"string", SameChar}, {"set", SameChar},
@@ -628,27 +641,27 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
DefaultingKIND},
KINDInt},
{"selected_char_kind", {{"name", DefaultChar, Rank::scalar}}, DefaultInt,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::transformationalFunction},
{"selected_int_kind", {{"r", AnyInt, Rank::scalar}}, DefaultInt,
- Rank::scalar},
+ Rank::scalar, IntrinsicClass::transformationalFunction},
{"selected_real_kind",
{{"p", AnyInt, Rank::scalar},
{"r", AnyInt, Rank::scalar, Optionality::optional},
{"radix", AnyInt, Rank::scalar, Optionality::optional}},
- DefaultInt, Rank::scalar},
+ DefaultInt, Rank::scalar, IntrinsicClass::transformationalFunction},
{"selected_real_kind",
{{"p", AnyInt, Rank::scalar, Optionality::optional},
{"r", AnyInt, Rank::scalar},
{"radix", AnyInt, Rank::scalar, Optionality::optional}},
- DefaultInt, Rank::scalar},
+ DefaultInt, Rank::scalar, IntrinsicClass::transformationalFunction},
{"selected_real_kind",
{{"p", AnyInt, Rank::scalar, Optionality::optional},
{"r", AnyInt, Rank::scalar, Optionality::optional},
{"radix", AnyInt, Rank::scalar}},
- DefaultInt, Rank::scalar},
+ DefaultInt, Rank::scalar, IntrinsicClass::transformationalFunction},
{"set_exponent", {{"x", SameReal}, {"i", AnyInt}}, SameReal},
{"shape", {{"source", AnyData, Rank::anyOrAssumedRank}, SizeDefaultKIND},
- KINDInt, Rank::vector},
+ KINDInt, Rank::vector, IntrinsicClass::inquiryFunction},
{"shifta", {{"i", SameInt}, {"shift", AnyInt}}, SameInt},
{"shiftl", {{"i", SameInt}, {"shift", AnyInt}}, SameInt},
{"shiftr", {{"i", SameInt}, {"shift", AnyInt}}, SameInt},
@@ -659,45 +672,49 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{"size",
{{"array", AnyData, Rank::anyOrAssumedRank}, OptionalDIM,
SizeDefaultKIND},
- KINDInt, Rank::scalar},
+ KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction},
{"spacing", {{"x", SameReal}}, SameReal},
{"spread",
{{"source", SameType, Rank::known}, RequiredDIM,
{"ncopies", AnyInt, Rank::scalar}},
- SameType, Rank::rankPlus1},
+ SameType, Rank::rankPlus1, IntrinsicClass::transformationalFunction},
{"sqrt", {{"x", SameFloating}}, SameFloating},
{"storage_size", {{"a", AnyData, Rank::anyOrAssumedRank}, SizeDefaultKIND},
- KINDInt, Rank::scalar},
+ KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction},
{"sum", {{"array", SameNumeric, Rank::array}, OptionalDIM, OptionalMASK},
- SameNumeric, Rank::dimReduced},
+ SameNumeric, Rank::dimReduced,
+ IntrinsicClass::transformationalFunction},
{"tan", {{"x", SameFloating}}, SameFloating},
{"tand", {{"x", SameFloating}}, SameFloating},
{"tanh", {{"x", SameFloating}}, SameFloating},
- {"tiny", {{"x", SameReal, Rank::anyOrAssumedRank}}, SameReal, Rank::scalar},
+ {"tiny", {{"x", SameReal, Rank::anyOrAssumedRank}}, SameReal, Rank::scalar,
+ IntrinsicClass::inquiryFunction},
{"trailz", {{"i", AnyInt}}, DefaultInt},
{"transfer",
{{"source", AnyData, Rank::known}, {"mold", SameType, Rank::scalar}},
- SameType, Rank::scalar},
+ SameType, Rank::scalar, IntrinsicClass::transformationalFunction},
{"transfer",
{{"source", AnyData, Rank::known}, {"mold", SameType, Rank::array}},
- SameType, Rank::vector},
+ SameType, Rank::vector, IntrinsicClass::transformationalFunction},
{"transfer",
{{"source", AnyData, Rank::anyOrAssumedRank},
{"mold", SameType, Rank::anyOrAssumedRank},
{"size", AnyInt, Rank::scalar}},
- SameType, Rank::vector},
- {"transpose", {{"matrix", SameType, Rank::matrix}}, SameType, Rank::matrix},
- {"trim", {{"string", SameChar, Rank::scalar}}, SameChar, Rank::scalar},
+ SameType, Rank::vector, IntrinsicClass::transformationalFunction},
+ {"transpose", {{"matrix", SameType, Rank::matrix}}, SameType, Rank::matrix,
+ IntrinsicClass::transformationalFunction},
+ {"trim", {{"string", SameChar, Rank::scalar}}, SameChar, Rank::scalar,
+ IntrinsicClass::transformationalFunction},
{"ubound",
{{"array", AnyData, Rank::anyOrAssumedRank}, RequiredDIM,
SizeDefaultKIND},
- KINDInt, Rank::scalar},
+ KINDInt, Rank::scalar, IntrinsicClass::inquiryFunction},
{"ubound", {{"array", AnyData, Rank::anyOrAssumedRank}, SizeDefaultKIND},
- KINDInt, Rank::vector},
+ KINDInt, Rank::vector, IntrinsicClass::inquiryFunction},
{"unpack",
{{"vector", SameType, Rank::vector}, {"mask", AnyLogical, Rank::array},
{"field", SameType, Rank::conformable}},
- SameType, Rank::conformable},
+ SameType, Rank::conformable, IntrinsicClass::transformationalFunction},
{"verify",
{{"string", SameChar}, {"set", SameChar},
{"back", AnyLogical, Rank::elemental, Optionality::optional},
@@ -900,33 +917,34 @@ static const SpecificIntrinsicInterface specificIntrinsicFunction[]{
};
static const IntrinsicInterface intrinsicSubroutine[]{
- {"cpu_time", {{"time", AnyReal, Rank::scalar}}, {}},
+ {"cpu_time", {{"time", AnyReal, Rank::scalar}}, {}, Rank::elemental,
+ IntrinsicClass::impureSubroutine},
{"date_and_time",
{{"date", DefaultChar, Rank::scalar, Optionality::optional},
{"time", DefaultChar, Rank::scalar, Optionality::optional},
{"zone", DefaultChar, Rank::scalar, Optionality::optional},
{"values", AnyInt, Rank::vector, Optionality::optional}},
- {}},
+ {}, Rank::elemental, IntrinsicClass::impureSubroutine},
{"execute_command_line",
{{"command", DefaultChar, Rank::scalar},
{"wait", AnyLogical, Rank::scalar, Optionality::optional},
{"exitstat", AnyInt, Rank::scalar, Optionality::optional},
{"cmdstat", AnyInt, Rank::scalar, Optionality::optional},
{"cmdmsg", DefaultChar, Rank::scalar, Optionality::optional}},
- {}},
+ {}, Rank::elemental, IntrinsicClass::impureSubroutine},
{"get_command",
{{"command", DefaultChar, Rank::scalar, Optionality::optional},
{"length", AnyInt, Rank::scalar, Optionality::optional},
{"status", AnyInt, Rank::scalar, Optionality::optional},
{"errmsg", DefaultChar, Rank::scalar, Optionality::optional}},
- {}},
+ {}, Rank::elemental, IntrinsicClass::impureSubroutine},
{"get_command_argument",
{{"number", AnyInt, Rank::scalar},
{"value", DefaultChar, Rank::scalar, Optionality::optional},
{"length", AnyInt, Rank::scalar, Optionality::optional},
{"status", AnyInt, Rank::scalar, Optionality::optional},
{"errmsg", DefaultChar, Rank::scalar, Optionality::optional}},
- {}},
+ {}, Rank::elemental, IntrinsicClass::impureSubroutine},
{"get_environment_variable",
{{"name", DefaultChar, Rank::scalar},
{"value", DefaultChar, Rank::scalar, Optionality::optional},
@@ -934,31 +952,34 @@ static const IntrinsicInterface intrinsicSubroutine[]{
{"status", AnyInt, Rank::scalar, Optionality::optional},
{"trim_name", AnyLogical, Rank::scalar, Optionality::optional},
{"errmsg", DefaultChar, Rank::scalar, Optionality::optional}},
- {}},
+ {}, Rank::elemental, IntrinsicClass::impureSubroutine},
{"move_alloc",
{{"from", SameType, Rank::known}, {"to", SameType, Rank::known},
{"stat", AnyInt, Rank::scalar, Optionality::optional},
{"errmsg", DefaultChar, Rank::scalar, Optionality::optional}},
- {}},
+ {}, Rank::elemental, IntrinsicClass::pureSubroutine},
{"mvbits",
{{"from", SameInt}, {"frompos", AnyInt}, {"len", AnyInt},
{"to", SameInt}, {"topos", AnyInt}},
- {}}, // elemental
+ {}, Rank::elemental, IntrinsicClass::elementalSubroutine}, // elemental
{"random_init",
{{"repeatable", AnyLogical, Rank::scalar},
{"image_distinct", AnyLogical, Rank::scalar}},
- {}},
- {"random_number", {{"harvest", AnyReal, Rank::known}}, {}},
+ {}, Rank::elemental, IntrinsicClass::impureSubroutine},
+ {"random_number", {{"harvest", AnyReal, Rank::known}}, {}, Rank::elemental,
+ IntrinsicClass::impureSubroutine},
{"random_seed",
{{"size", DefaultInt, Rank::scalar, Optionality::optional},
{"put", DefaultInt, Rank::vector, Optionality::optional},
{"get", DefaultInt, Rank::vector, Optionality::optional}},
- {}}, // TODO: at most one argument can be present
+ {}, Rank::elemental,
+ IntrinsicClass::impureSubroutine}, // TODO: at most one argument can be
+ // present
{"system_clock",
{{"count", AnyInt, Rank::scalar, Optionality::optional},
{"count_rate", AnyIntOrReal, Rank::scalar, Optionality::optional},
{"count_max", AnyInt, Rank::scalar, Optionality::optional}},
- {}},
+ {}, Rank::elemental, IntrinsicClass::impureSubroutine},
};
// TODO: Intrinsic subroutine EVENT_QUERY
@@ -1532,6 +1553,8 @@ class IntrinsicProcTable::Implementation {
bool IsIntrinsic(const std::string &) const;
+ IntrinsicClass GetIntrinsicClass(const std::string &) const;
+
std::optional<SpecificCall> Probe(const CallCharacteristics &,
ActualArguments &, FoldingContext &, const IntrinsicProcTable &) const;
@@ -1571,6 +1594,23 @@ bool IntrinsicProcTable::Implementation::IsIntrinsic(
return name == "null" || name == "__builtin_c_f_pointer";
}
+IntrinsicClass IntrinsicProcTable::Implementation::GetIntrinsicClass(
+ const std::string &name) const {
+ auto specificIntrinsic{specificFuncs_.find(name)};
+ if (specificIntrinsic != specificFuncs_.end()) {
+ return specificIntrinsic->second->intrinsicClass;
+ }
+ auto genericIntrinsic{genericFuncs_.find(name)};
+ if (genericIntrinsic != genericFuncs_.end()) {
+ return genericIntrinsic->second->intrinsicClass;
+ }
+ auto subrIntrinsic{subroutines_.find(name)};
+ if (subrIntrinsic != subroutines_.end()) {
+ return subrIntrinsic->second->intrinsicClass;
+ }
+ return IntrinsicClass::noClass;
+}
+
bool CheckAndRearrangeArguments(ActualArguments &arguments,
parser::ContextualMessages &messages, const char *const dummyKeywords[],
std::size_t trailingOptionals) {
@@ -2014,6 +2054,11 @@ bool IntrinsicProcTable::IsIntrinsic(const std::string &name) const {
return DEREF(impl_).IsIntrinsic(name);
}
+IntrinsicClass IntrinsicProcTable::GetIntrinsicClass(
+ const std::string &name) const {
+ return DEREF(impl_).GetIntrinsicClass(name);
+}
+
std::optional<SpecificCall> IntrinsicProcTable::Probe(
const CallCharacteristics &call, ActualArguments &arguments,
FoldingContext &context) const {
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index da02b4fbe47f..edbd01d4eca0 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -33,7 +33,10 @@ class CheckHelper {
void Check() { Check(context_.globalScope()); }
void Check(const ParamValue &, bool canBeAssumed);
- void Check(const Bound &bound) { CheckSpecExpr(bound.GetExplicit()); }
+ void Check(const Bound &bound) {
+ CheckSpecExpr(
+ bound.GetExplicit(), evaluate::SpecificationExprContext::BOUND);
+ }
void Check(const ShapeSpec &spec) {
Check(spec.lbound());
Check(spec.ubound());
@@ -44,7 +47,9 @@ class CheckHelper {
void Check(const Scope &);
private:
- template <typename A> void CheckSpecExpr(const A &x) {
+ template <typename A>
+ void CheckSpecExpr(
+ const A &x, const evaluate::SpecificationExprContext specExprContext) {
if (symbolBeingChecked_ && IsSaved(*symbolBeingChecked_)) {
if (!evaluate::IsConstantExpr(x)) {
messages_.Say(
@@ -52,18 +57,23 @@ class CheckHelper {
symbolBeingChecked_->name());
}
} else {
- evaluate::CheckSpecificationExpr(x, messages_, DEREF(scope_));
+ evaluate::CheckSpecificationExpr(
+ x, messages_, DEREF(scope_), context_.intrinsics(), specExprContext);
}
}
- template <typename A> void CheckSpecExpr(const std::optional<A> &x) {
+ template <typename A>
+ void CheckSpecExpr(const std::optional<A> &x,
+ const evaluate::SpecificationExprContext specExprContext) {
if (x) {
- CheckSpecExpr(*x);
+ CheckSpecExpr(*x, specExprContext);
}
}
- template <typename A> void CheckSpecExpr(A &x) {
+ template <typename A>
+ void CheckSpecExpr(
+ A &x, const evaluate::SpecificationExprContext specExprContext) {
x = Fold(foldingContext_, std::move(x));
const A &constx{x};
- CheckSpecExpr(constx);
+ CheckSpecExpr(constx, specExprContext);
}
void CheckValue(const Symbol &, const DerivedTypeSpec *);
void CheckVolatile(
@@ -131,7 +141,8 @@ void CheckHelper::Check(const ParamValue &value, bool canBeAssumed) {
" external function result"_err_en_US);
}
} else {
- CheckSpecExpr(value.GetExplicit());
+ CheckSpecExpr(
+ value.GetExplicit(), evaluate::SpecificationExprContext::TYPE_PARAM);
}
}
@@ -384,15 +395,25 @@ void CheckHelper::CheckObjectEntity(
CheckAssumedTypeEntity(symbol, details);
symbolBeingChecked_ = nullptr;
if (!details.coshape().empty()) {
+ bool isDeferredShape{details.coshape().IsDeferredShape()};
if (IsAllocatable(symbol)) {
- if (!details.coshape().IsDeferredShape()) { // C827
- messages_.Say(
- "ALLOCATABLE coarray must have a deferred coshape"_err_en_US);
+ if (!isDeferredShape) { // C827
+ messages_.Say("'%s' is an ALLOCATABLE coarray and must have a deferred"
+ " coshape"_err_en_US,
+ symbol.name());
}
+ } else if (symbol.owner().IsDerivedType()) { // C746
+ std::string deferredMsg{
+ isDeferredShape ? "" : " and have a deferred coshape"};
+ messages_.Say("Component '%s' is a coarray and must have the ALLOCATABLE"
+ " attribute%s"_err_en_US,
+ symbol.name(), deferredMsg);
} else {
if (!details.coshape().IsAssumedSize()) { // C828
messages_.Say(
- "Non-ALLOCATABLE coarray must have an explicit coshape"_err_en_US);
+ "Component '%s' is a non-ALLOCATABLE coarray and must have"
+ " an explicit coshape"_err_en_US,
+ symbol.name());
}
}
}
@@ -409,7 +430,8 @@ void CheckHelper::CheckObjectEntity(
"An INTENT(OUT) dummy argument may not be, or contain, EVENT_TYPE or LOCK_TYPE"_err_en_US);
}
}
- if (InPure() && !IsPointer(symbol) && !IsIntentIn(symbol) &&
+ if (InPure() && !IsStmtFunction(DEREF(innermostSymbol_)) &&
+ !IsPointer(symbol) && !IsIntentIn(symbol) &&
!symbol.attrs().test(Attr::VALUE)) {
if (InFunction()) { // C1583
messages_.Say(
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 3431bc05392e..9306f702aabb 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -2092,13 +2092,14 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
}
semantics::CheckArguments(*chars, arguments, GetFoldingContext(),
context_.FindScope(callSite), treatExternalAsImplicit);
- if (!chars->attrs.test(characteristics::Procedure::Attr::Pure)) {
+ const Symbol *procSymbol{proc.GetSymbol()};
+ if (procSymbol && !IsPureProcedure(*procSymbol)) {
if (const semantics::Scope *
pure{semantics::FindPureProcedureContaining(
context_.FindScope(callSite))}) {
Say(callSite,
"Procedure '%s' referenced in pure subprogram '%s' must be pure too"_err_en_US,
- DEREF(proc.GetSymbol()).name(), DEREF(pure->symbol()).name());
+ procSymbol->name(), DEREF(pure->symbol()).name());
}
}
}
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 6d04c7f229ed..e51c33988d0d 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -3679,7 +3679,7 @@ bool DeclarationVisitor::Pre(const parser::DerivedTypeDef &x) {
if (symbol->has<TypeParamDetails>() && !paramNames.count(name)) {
SayDerivedType(name,
"'%s' is not a type parameter of this derived type"_err_en_US,
- currScope()); // C742
+ currScope()); // C741
}
}
Walk(std::get<std::list<parser::Statement<parser::PrivateOrSequence>>>(x.t));
@@ -3820,14 +3820,50 @@ void DeclarationVisitor::Post(const parser::ComponentDecl &x) {
!attrs.HasAny({Attr::PUBLIC, Attr::PRIVATE})) {
attrs.set(Attr::PRIVATE);
}
- if (!attrs.HasAny({Attr::POINTER, Attr::ALLOCATABLE})) {
- if (const auto *declType{GetDeclTypeSpec()}) {
- if (const auto *derived{declType->AsDerived()}) {
+ if (const auto *declType{GetDeclTypeSpec()}) {
+ if (const auto *derived{declType->AsDerived()}) {
+ if (!attrs.HasAny({Attr::POINTER, Attr::ALLOCATABLE})) {
if (derivedTypeInfo_.type == &derived->typeSymbol()) { // C744
Say("Recursive use of the derived type requires "
"POINTER or ALLOCATABLE"_err_en_US);
}
}
+ if (!coarraySpec().empty()) { // C747
+ if (IsTeamType(derived)) {
+ Say("A coarray component may not be of type TEAM_TYPE from "
+ "ISO_FORTRAN_ENV"_err_en_US);
+ } else {
+ if (IsIsoCType(derived)) {
+ Say("A coarray component may not be of type C_PTR or C_FUNPTR from "
+ "ISO_C_BINDING"_err_en_US);
+ }
+ }
+ }
+ if (auto it{FindCoarrayUltimateComponent(*derived)}) { // C748
+ std::string ultimateName{it.BuildResultDesignatorName()};
+ // Strip off the leading "%"
+ if (ultimateName.length() > 1) {
+ ultimateName.erase(0, 1);
+ if (attrs.HasAny({Attr::POINTER, Attr::ALLOCATABLE})) {
+ evaluate::AttachDeclaration(
+ Say(name.source,
+ "A component with a POINTER or ALLOCATABLE attribute may "
+ "not "
+ "be of a type with a coarray ultimate component (named "
+ "'%s')"_err_en_US,
+ ultimateName),
+ derived->typeSymbol());
+ }
+ if (!arraySpec().empty() || !coarraySpec().empty()) {
+ evaluate::AttachDeclaration(
+ Say(name.source,
+ "An array or coarray component may not be of a type with a "
+ "coarray ultimate component (named '%s')"_err_en_US,
+ ultimateName),
+ derived->typeSymbol());
+ }
+ }
+ }
}
}
if (OkToAddComponent(name)) {
@@ -4741,7 +4777,7 @@ Symbol *DeclarationVisitor::MakeTypeSymbol(
const SourceName &name, Details &&details) {
Scope &derivedType{currScope()};
CHECK(derivedType.IsDerivedType());
- if (auto *symbol{FindInScope(derivedType, name)}) {
+ if (auto *symbol{FindInScope(derivedType, name)}) { // C742
Say2(name,
"Type parameter, component, or procedure binding '%s'"
" already defined in this type"_err_en_US,
diff --git a/flang/lib/Semantics/tools.cpp b/flang/lib/Semantics/tools.cpp
index 249dcb27b65a..3b68beaa557f 100644
--- a/flang/lib/Semantics/tools.cpp
+++ b/flang/lib/Semantics/tools.cpp
@@ -270,6 +270,24 @@ bool IsPureProcedure(const Symbol &symbol) {
} else if (!IsProcedure(symbol)) {
return false;
}
+ if (IsStmtFunction(symbol)) {
+ // Section 15.7(1) states that a statement function is PURE if it does not
+ // reference an IMPURE procedure or a VOLATILE variable
+ const MaybeExpr &expr{symbol.get<SubprogramDetails>().stmtFunction()};
+ if (expr) {
+ for (const Symbol &refSymbol : evaluate::CollectSymbols(*expr)) {
+ if (IsFunction(refSymbol) && !IsPureProcedure(refSymbol)) {
+ return false;
+ }
+ if (const Symbol * root{GetAssociationRoot(refSymbol)}) {
+ if (root->attrs().test(Attr::VOLATILE)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true; // statement function was not found to be impure
+ }
return symbol.attrs().test(Attr::PURE) ||
(symbol.attrs().test(Attr::ELEMENTAL) &&
!symbol.attrs().test(Attr::IMPURE));
@@ -1356,4 +1374,5 @@ void LabelEnforce::SayWithConstruct(SemanticsContext &context,
context.Say(stmtLocation, message)
.Attach(constructLocation, GetEnclosingConstructMsg());
}
+
} // namespace Fortran::semantics
diff --git a/flang/test/Semantics/allocate11.f90 b/flang/test/Semantics/allocate11.f90
index 594bd1ded385..01b9944019ae 100644
--- a/flang/test/Semantics/allocate11.f90
+++ b/flang/test/Semantics/allocate11.f90
@@ -38,6 +38,7 @@ subroutine C937(var)
type B
type(A) y
+ !ERROR: A component with a POINTER or ALLOCATABLE attribute may not be of a type with a coarray ultimate component (named 'y%x')
type(B), pointer :: forward
real :: u
end type
@@ -47,6 +48,7 @@ subroutine C937(var)
end type
type D
+ !ERROR: A component with a POINTER or ALLOCATABLE attribute may not be of a type with a coarray ultimate component (named 'x')
type(A), pointer :: potential
end type
diff --git a/flang/test/Semantics/call12.f90 b/flang/test/Semantics/call12.f90
index e25a2608c441..65da46b067d6 100644
--- a/flang/test/Semantics/call12.f90
+++ b/flang/test/Semantics/call12.f90
@@ -15,7 +15,7 @@ module m
real, pointer :: p
end type
type :: hasCoarray
- real :: co[*]
+ real, allocatable :: co[:]
end type
contains
pure function test(ptr, in, hpd)
diff --git a/flang/test/Semantics/call14.f90 b/flang/test/Semantics/call14.f90
index b874e6b00912..ee5086511de3 100644
--- a/flang/test/Semantics/call14.f90
+++ b/flang/test/Semantics/call14.f90
@@ -3,7 +3,7 @@
module m
type :: hasCoarray
- real :: coarray[*]
+ real, allocatable :: coarray[:]
end type
contains
!ERROR: VALUE attribute may apply only to a dummy data object
diff --git a/flang/test/Semantics/misc-declarations.f90 b/flang/test/Semantics/misc-declarations.f90
index 7680eed793bc..f627836b3732 100644
--- a/flang/test/Semantics/misc-declarations.f90
+++ b/flang/test/Semantics/misc-declarations.f90
@@ -4,12 +4,12 @@
! - 8.5.19 constraints on the VOLATILE attribute
module m
- !ERROR: ALLOCATABLE coarray must have a deferred coshape
+ !ERROR: 'mustbedeferred' is an ALLOCATABLE coarray and must have a deferred coshape
real, allocatable :: mustBeDeferred[*] ! C827
- !ERROR: Non-ALLOCATABLE coarray must have an explicit coshape
+ !ERROR: Component 'mustbeexplicit' is a non-ALLOCATABLE coarray and must have an explicit coshape
real :: mustBeExplicit[:] ! C828
type :: hasCoarray
- real :: coarray[*]
+ real, allocatable :: coarray[:]
end type
real :: coarray[*]
type(hasCoarray) :: coarrayComponent
diff --git a/flang/test/Semantics/modfile24.f90 b/flang/test/Semantics/modfile24.f90
index ec446f9e8d3c..45f6c0545627 100644
--- a/flang/test/Semantics/modfile24.f90
+++ b/flang/test/Semantics/modfile24.f90
@@ -36,8 +36,8 @@ module m2
! coarray-spec in components and with non-constants bounds
module m3
type t
- real :: c[1:10,1:*]
- complex, codimension[5,*] :: d
+ real, allocatable :: c[:,:]
+ complex, allocatable, codimension[:,:] :: d
end type
real, allocatable :: e[:,:,:]
contains
@@ -50,8 +50,8 @@ subroutine s(a, b, n)
!Expect: m3.mod
!module m3
! type::t
-! real(4)::c[1_8:10_8,1_8:*]
-! complex(4)::d[1_8:5_8,1_8:*]
+! real(4),allocatable::c[:,:]
+! complex(4),allocatable::d[:,:]
! end type
! real(4),allocatable::e[:,:,:]
!contains
diff --git a/flang/test/Semantics/resolve33.f90 b/flang/test/Semantics/resolve33.f90
index 3fa6bec15f2c..7df5ba935ab0 100644
--- a/flang/test/Semantics/resolve33.f90
+++ b/flang/test/Semantics/resolve33.f90
@@ -2,6 +2,12 @@
! Derived type parameters
! C731 The same type-param-name shall not appear more than once in a given
! derived-type-stmt.
+! C741 A type-param-name in a type-param-def-stmt in a derived-type-def shall
+! be one of the type-paramnames in the derived-type-stmt of that
+! derived-type-def.
+! C742 Each type-param-name in the derived-type-stmt in a derived-type-def
+! shall appear exactly once as a type-param-name in a type-param-def-stmt
+! in that derived-type-def.
module m
!ERROR: Duplicate type parameter name: 'a'
diff --git a/flang/test/Semantics/resolve44.f90 b/flang/test/Semantics/resolve44.f90
index 2d8b70178753..41ab06ffb6c6 100644
--- a/flang/test/Semantics/resolve44.f90
+++ b/flang/test/Semantics/resolve44.f90
@@ -1,5 +1,8 @@
! RUN: %B/test/Semantics/test_errors.sh %s %flang %t
! Error tests for recursive use of derived types.
+! C744 If neither the POINTER nor the ALLOCATABLE attribute is specified, the
+! declaration-type-spec in the component-def-stmt shall specify an intrinsic
+! type or a previously defined derived type.
program main
type :: recursive1
diff --git a/flang/test/Semantics/resolve88.f90 b/flang/test/Semantics/resolve88.f90
new file mode 100644
index 000000000000..50135297241c
--- /dev/null
+++ b/flang/test/Semantics/resolve88.f90
@@ -0,0 +1,75 @@
+! RUN: %B/test/Semantics/test_errors.sh %s %flang %t
+! C746, C747, and C748
+module m
+ use ISO_FORTRAN_ENV
+ use ISO_C_BINDING
+
+ ! C746 If a coarray-spec appears, it shall be a deferred-coshape-spec-list and
+ ! the component shall have the ALLOCATABLE attribute.
+
+ type testCoArrayType
+ real, allocatable, codimension[:] :: allocatableField
+ !ERROR: Component 'deferredfield' is a coarray and must have the ALLOCATABLE attribute
+ real, codimension[:] :: deferredField
+ !ERROR: 'pointerfield' may not have the POINTER attribute because it is a coarray
+ !ERROR: Component 'pointerfield' is a coarray and must have the ALLOCATABLE attribute
+ real, pointer, codimension[:] :: pointerField
+ !ERROR: Component 'realfield' is a coarray and must have the ALLOCATABLE attribute and have a deferred coshape
+ real, codimension[*] :: realField
+ !ERROR: 'realfield2' is an ALLOCATABLE coarray and must have a deferred coshape
+ real, allocatable, codimension[*] :: realField2
+ end type testCoArrayType
+
+ ! C747 If a coarray-spec appears, the component shall not be of type C_PTR or
+ ! C_FUNPTR from the intrinsic module ISO_C_BINDING (18.2), or of type
+ ! TEAM_TYPE from the intrinsic module ISO_FORTRAN_ENV (16.10.2).
+
+ type goodCoarrayType
+ real, allocatable, codimension[:] :: field
+ end type goodCoarrayType
+
+ type goodTeam_typeCoarrayType
+ type(team_type), allocatable :: field
+ end type goodTeam_typeCoarrayType
+
+ type goodC_ptrCoarrayType
+ type(c_ptr), allocatable :: field
+ end type goodC_ptrCoarrayType
+
+ type goodC_funptrCoarrayType
+ type(c_funptr), allocatable :: field
+ end type goodC_funptrCoarrayType
+
+ type team_typeCoarrayType
+ !ERROR: A coarray component may not be of type TEAM_TYPE from ISO_FORTRAN_ENV
+ type(team_type), allocatable, codimension[:] :: field
+ end type team_typeCoarrayType
+
+ type c_ptrCoarrayType
+ !ERROR: A coarray component may not be of type C_PTR or C_FUNPTR from ISO_C_BINDING
+ type(c_ptr), allocatable, codimension[:] :: field
+ end type c_ptrCoarrayType
+
+ type c_funptrCoarrayType
+ !ERROR: A coarray component may not be of type C_PTR or C_FUNPTR from ISO_C_BINDING
+ type(c_funptr), allocatable, codimension[:] :: field
+ end type c_funptrCoarrayType
+
+! C748 A data component whose type has a coarray ultimate component shall be a
+! nonpointer nonallocatable scalar and shall not be a coarray.
+
+ type coarrayType
+ real, allocatable, codimension[:] :: goodCoarrayField
+ end type coarrayType
+
+ type testType
+ type(coarrayType) :: goodField
+ !ERROR: A component with a POINTER or ALLOCATABLE attribute may not be of a type with a coarray ultimate component (named 'goodcoarrayfield')
+ type(coarrayType), pointer :: pointerField
+ !ERROR: A component with a POINTER or ALLOCATABLE attribute may not be of a type with a coarray ultimate component (named 'goodcoarrayfield')
+ type(coarrayType), allocatable :: allocatableField
+ !ERROR: An array or coarray component may not be of a type with a coarray ultimate component (named 'goodcoarrayfield')
+ type(coarrayType), dimension(3) :: arrayField
+ end type testType
+
+end module m
diff --git a/flang/test/Semantics/resolve89.f90 b/flang/test/Semantics/resolve89.f90
new file mode 100644
index 000000000000..883970f30edf
--- /dev/null
+++ b/flang/test/Semantics/resolve89.f90
@@ -0,0 +1,110 @@
+! RUN: %B/test/Semantics/test_errors.sh %s %flang %t
+! C750 Each bound in the explicit-shape-spec shall be a specification
+! expression in which there are no references to specification functions or
+! the intrinsic functions ALLOCATED, ASSOCIATED, EXTENDS_- TYPE_OF, PRESENT,
+! or SAME_TYPE_AS, every specification inquiry reference is a constant
+! expression, and the value does not depend on the value of a variable.
+impure function impureFunc()
+ integer :: impureFunc
+
+ impureFunc = 3
+end function impureFunc
+
+pure function pureFunc()
+ integer :: pureFunc
+
+ pureFunc = 3
+end function pureFunc
+
+module m
+ real, allocatable :: mVar
+end module m
+
+subroutine s(iArg, allocArg, pointerArg, arrayArg, ioArg, optionalArg)
+ use m
+ implicit logical(l)
+ integer, intent(in) :: iArg
+ real, allocatable, intent(in) :: allocArg
+ real, pointer, intent(in) :: pointerArg
+ integer, dimension(:), intent(in) :: arrayArg
+ integer, intent(inout) :: ioArg
+ real, optional, intent(in) :: optionalArg
+
+ ! These declarations are OK since they're not in a derived type
+ real :: realVar
+ real, volatile :: volatileVar
+ real, dimension(merge(1, 2, allocated(allocArg))) :: realVar1
+ real, dimension(merge(1, 2, associated(pointerArg))) :: realVar2
+ real, dimension(merge(1, 2, is_contiguous(arrayArg))) :: realVar3
+ real, dimension(ioArg) :: realVar4
+ real, dimension(merge(1, 2, present(optionalArg))) :: realVar5
+
+ ! statement functions referenced below
+ iVolatileStmtFunc() = 3 * volatileVar
+ iImpureStmtFunc() = 3 * impureFunc()
+ iPureStmtFunc() = 3 * pureFunc()
+
+ ! This is OK
+ real, dimension(merge(1, 2, allocated(mVar))) :: rVar
+
+
+ integer :: var = 3
+ !ERROR: Invalid specification expression: reference to impure function 'ivolatilestmtfunc'
+ real, dimension(iVolatileStmtFunc()) :: arrayVarWithVolatile
+ !ERROR: Invalid specification expression: reference to impure function 'iimpurestmtfunc'
+ real, dimension(iImpureStmtFunc()) :: arrayVarWithImpureFunction
+ !ERROR: Invalid specification expression: reference to statement function 'ipurestmtfunc'
+ real, dimension(iPureStmtFunc()) :: arrayVarWithPureFunction
+ real, dimension(iabs(iArg)) :: arrayVarWithIntrinsic
+
+ type arrayType
+ !ERROR: Invalid specification expression: reference to variable 'var' not allowed for derived type components
+ real, dimension(var) :: varField
+ !ERROR: Invalid specification expression: reference to impure function 'ivolatilestmtfunc'
+ real, dimension(iVolatileStmtFunc()) :: arrayFieldWithVolatile
+ !ERROR: Invalid specification expression: reference to impure function 'iimpurestmtfunc'
+ real, dimension(iImpureStmtFunc()) :: arrayFieldWithImpureFunction
+ !ERROR: Invalid specification expression: reference to statement function 'ipurestmtfunc'
+ real, dimension(iPureStmtFunc()) :: arrayFieldWithPureFunction
+ !ERROR: Invalid specification expression: reference to variable 'iarg' not allowed for derived type components
+ real, dimension(iabs(iArg)) :: arrayFieldWithIntrinsic
+ !ERROR: Invalid specification expression: reference to intrinsic 'allocated' not allowed for derived type components
+ real, dimension(merge(1, 2, allocated(allocArg))) :: realField1
+ !ERROR: Invalid specification expression: reference to intrinsic 'associated' not allowed for derived type components
+ real, dimension(merge(1, 2, associated(pointerArg))) :: realField2
+ !ERROR: Invalid specification expression: non-constant reference to inquiry intrinsic 'is_contiguous' not allowed for derived type components
+ real, dimension(merge(1, 2, is_contiguous(arrayArg))) :: realField3
+ !ERROR: Invalid specification expression: reference to variable 'ioarg' not allowed for derived type components
+ real, dimension(ioArg) :: realField4
+ !ERROR: Invalid specification expression: reference to intrinsic 'present' not allowed for derived type components
+ real, dimension(merge(1, 2, present(optionalArg))) :: realField5
+ end type arrayType
+
+end subroutine s
+
+subroutine s1()
+ ! C750, check for a constant specification inquiry that's a type parameter
+ ! inquiry which are defined in 9.4.5
+ type derived(kindParam, lenParam)
+ integer, kind :: kindParam = 3
+ integer, len :: lenParam = 3
+ end type
+
+ contains
+ subroutine inner (derivedArg)
+ type(derived), intent(in), dimension(3) :: derivedArg
+ integer :: localInt
+
+ type(derived), parameter :: localderived = derived()
+
+ type localDerivedType
+ ! OK because the specification inquiry is a constant
+ integer, dimension(localDerived%kindParam) :: goodField
+ !ERROR: Invalid specification expression: non-constant reference to a type parameter inquiry not allowed for derived type components
+ integer, dimension(derivedArg%lenParam) :: badField
+ end type localDerivedType
+
+ ! OK because we're not defining a component
+ integer, dimension(derivedArg%kindParam) :: localVar
+ end subroutine inner
+end subroutine s1
More information about the flang-commits
mailing list