diff options
Diffstat (limited to 'flang/lib/Evaluate')
| -rw-r--r-- | flang/lib/Evaluate/check-expression.cpp | 96 | ||||
| -rw-r--r-- | flang/lib/Evaluate/common.cpp | 19 | ||||
| -rw-r--r-- | flang/lib/Evaluate/fold-implementation.h | 14 | ||||
| -rw-r--r-- | flang/lib/Evaluate/fold-real.cpp | 10 | ||||
| -rw-r--r-- | flang/lib/Evaluate/host.cpp | 4 | ||||
| -rw-r--r-- | flang/lib/Evaluate/intrinsics-library.cpp | 4 | ||||
| -rw-r--r-- | flang/lib/Evaluate/intrinsics.cpp | 41 | ||||
| -rw-r--r-- | flang/lib/Evaluate/tools.cpp | 20 | ||||
| -rw-r--r-- | flang/lib/Evaluate/variable.cpp | 13 |
9 files changed, 124 insertions, 97 deletions
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp index 839717d..e07076e 100644 --- a/flang/lib/Evaluate/check-expression.cpp +++ b/flang/lib/Evaluate/check-expression.cpp @@ -379,8 +379,11 @@ bool IsInitialProcedureTarget(const semantics::Symbol &symbol) { common::visitors{ [&](const semantics::SubprogramDetails &subp) { return !subp.isDummy() && !subp.stmtFunction() && - symbol.owner().kind() != semantics::Scope::Kind::MainProgram && - symbol.owner().kind() != semantics::Scope::Kind::Subprogram; + ((symbol.owner().kind() != + semantics::Scope::Kind::MainProgram && + symbol.owner().kind() != + semantics::Scope::Kind::Subprogram) || + ultimate.attrs().test(semantics::Attr::EXTERNAL)); }, [](const semantics::SubprogramNameDetails &x) { return x.kind() != semantics::SubprogramKind::Internal; @@ -1475,13 +1478,12 @@ public: const characteristics::DummyDataObject &dummyObj) : fc_{fc}, actual_{actual}, dummyObj_{dummyObj} {} - // Returns true, if actual and dummy have different contiguity requirements - bool HaveContiguityDifferences() const { - // Check actual contiguity, unless dummy doesn't care + // Returns true if dummy arg needs to be contiguous + bool DummyNeedsContiguity() const { + if (dummyObj_.ignoreTKR.test(common::IgnoreTKR::Contiguous)) { + return false; + } bool dummyTreatAsArray{dummyObj_.ignoreTKR.test(common::IgnoreTKR::Rank)}; - bool actualTreatAsContiguous{ - dummyObj_.ignoreTKR.test(common::IgnoreTKR::Contiguous) || - IsSimplyContiguous(actual_, fc_)}; bool dummyIsExplicitShape{dummyObj_.type.IsExplicitShape()}; bool dummyIsAssumedSize{dummyObj_.type.attrs().test( characteristics::TypeAndShape::Attr::AssumedSize)}; @@ -1498,32 +1500,17 @@ public: (dummyTreatAsArray && !dummyIsPolymorphic) || dummyIsVoidStar || dummyObj_.attrs.test( characteristics::DummyDataObject::Attr::Contiguous)}; - return !actualTreatAsContiguous && dummyNeedsContiguity; + return dummyNeedsContiguity; } - // Returns true, if actual and dummy have polymorphic differences bool HavePolymorphicDifferences() const { - bool dummyIsAssumedRank{dummyObj_.type.attrs().test( - characteristics::TypeAndShape::Attr::AssumedRank)}; - bool actualIsAssumedRank{semantics::IsAssumedRank(actual_)}; - bool dummyIsAssumedShape{dummyObj_.type.attrs().test( - characteristics::TypeAndShape::Attr::AssumedShape)}; - bool actualIsAssumedShape{semantics::IsAssumedShape(actual_)}; - if ((actualIsAssumedRank && dummyIsAssumedRank) || - (actualIsAssumedShape && dummyIsAssumedShape)) { - // Assumed-rank and assumed-shape arrays are represented by descriptors, - // so don't need to do polymorphic check. - } else if (!dummyObj_.ignoreTKR.test(common::IgnoreTKR::Type)) { - // flang supports limited cases of passing polymorphic to non-polimorphic. - // These cases require temporary of non-polymorphic type. (For example, - // the actual argument could be polymorphic array of child type, - // while the dummy argument could be non-polymorphic array of parent - // type.) + if (dummyObj_.ignoreTKR.test(common::IgnoreTKR::Type)) { + return false; + } + if (auto actualType{ + characteristics::TypeAndShape::Characterize(actual_, fc_)}) { + bool actualIsPolymorphic{actualType->type().IsPolymorphic()}; bool dummyIsPolymorphic{dummyObj_.type.type().IsPolymorphic()}; - auto actualType{ - characteristics::TypeAndShape::Characterize(actual_, fc_)}; - bool actualIsPolymorphic{ - actualType && actualType->type().IsPolymorphic()}; if (actualIsPolymorphic && !dummyIsPolymorphic) { return true; } @@ -1572,28 +1559,32 @@ private: // procedures with explicit interface, it's expected that "dummy" is not null. // For procedures with implicit interface dummy may be null. // +// Returns std::optional<bool> indicating whether the copy is known to be +// needed (true) or not needed (false); returns std::nullopt if the necessity +// of the copy is undetermined. +// // Note that these copy-in and copy-out checks are done from the caller's // perspective, meaning that for copy-in the caller need to do the copy // before calling the callee. Similarly, for copy-out the caller is expected // to do the copy after the callee returns. -bool MayNeedCopy(const ActualArgument *actual, +std::optional<bool> ActualArgNeedsCopy(const ActualArgument *actual, const characteristics::DummyArgument *dummy, FoldingContext &fc, bool forCopyOut) { if (!actual) { - return false; + return std::nullopt; } if (actual->isAlternateReturn()) { - return false; + return std::nullopt; } const auto *dummyObj{dummy ? std::get_if<characteristics::DummyDataObject>(&dummy->u) : nullptr}; - const bool forCopyIn = !forCopyOut; + const bool forCopyIn{!forCopyOut}; if (!evaluate::IsVariable(*actual)) { - // Actual argument expressions that aren’t variables are copy-in, but - // not copy-out. + // Expressions are copy-in, but not copy-out. return forCopyIn; } + auto maybeContigActual{IsContiguous(*actual, fc)}; if (dummyObj) { // Explict interface CopyInOutExplicitInterface check{fc, *actual, *dummyObj}; if (forCopyOut && check.HasIntentIn()) { @@ -1616,28 +1607,25 @@ bool MayNeedCopy(const ActualArgument *actual, if (!check.HaveArrayOrAssumedRankArgs()) { return false; } - if (check.HaveContiguityDifferences()) { - return true; - } - if (check.HavePolymorphicDifferences()) { - return true; + if (maybeContigActual.has_value()) { + // We know whether actual arg is contiguous or not + bool isContiguousActual{maybeContigActual.value()}; + bool actualArgNeedsCopy{ + (!isContiguousActual || check.HavePolymorphicDifferences()) && + check.DummyNeedsContiguity()}; + return actualArgNeedsCopy; + } else { + // We don't know whether actual arg is contiguous or not + return check.DummyNeedsContiguity(); } } else { // Implicit interface - if (ExtractCoarrayRef(*actual)) { - // Coindexed actual args may need copy-in and copy-out with implicit - // interface - return true; - } - if (!IsSimplyContiguous(*actual, fc)) { - // Copy-in: actual arguments that are variables are copy-in when - // non-contiguous. - // Copy-out: vector subscripts could refer to duplicate elements, can't - // copy out. - return !(forCopyOut && HasVectorSubscript(*actual)); + if (maybeContigActual.has_value()) { + // If known contiguous, don't copy in/out. + // If known non-contiguous, copy in/out. + return !*maybeContigActual; } } - // For everything else, no copy-in or copy-out - return false; + return std::nullopt; } } // namespace Fortran::evaluate diff --git a/flang/lib/Evaluate/common.cpp b/flang/lib/Evaluate/common.cpp index 46c75a5..119ea3c 100644 --- a/flang/lib/Evaluate/common.cpp +++ b/flang/lib/Evaluate/common.cpp @@ -13,24 +13,29 @@ using namespace Fortran::parser::literals; namespace Fortran::evaluate { -void RealFlagWarnings( - FoldingContext &context, const RealFlags &flags, const char *operation) { +void FoldingContext::RealFlagWarnings( + const RealFlags &flags, const char *operation) { static constexpr auto warning{common::UsageWarning::FoldingException}; + if (!realFlagWarningContext_.empty()) { + // Override 'operation' with a string like + // "compilation-time evaluation of a call to '...'" + operation = realFlagWarningContext_.c_str(); + } if (flags.test(RealFlag::Overflow)) { - context.Warn(warning, "overflow on %s"_warn_en_US, operation); + Warn(warning, "overflow on %s"_warn_en_US, operation); } if (flags.test(RealFlag::DivideByZero)) { if (std::strcmp(operation, "division") == 0) { - context.Warn(warning, "division by zero"_warn_en_US); + Warn(warning, "division by zero"_warn_en_US); } else { - context.Warn(warning, "division by zero on %s"_warn_en_US, operation); + Warn(warning, "division by zero on %s"_warn_en_US, operation); } } if (flags.test(RealFlag::InvalidArgument)) { - context.Warn(warning, "invalid argument on %s"_warn_en_US, operation); + Warn(warning, "invalid argument on %s"_warn_en_US, operation); } if (flags.test(RealFlag::Underflow)) { - context.Warn(warning, "underflow on %s"_warn_en_US, operation); + Warn(warning, "underflow on %s"_warn_en_US, operation); } } diff --git a/flang/lib/Evaluate/fold-implementation.h b/flang/lib/Evaluate/fold-implementation.h index 3fdf3a6..52ea627 100644 --- a/flang/lib/Evaluate/fold-implementation.h +++ b/flang/lib/Evaluate/fold-implementation.h @@ -1862,7 +1862,7 @@ Expr<TO> FoldOperation( std::snprintf(buffer, sizeof buffer, "INTEGER(%d) to REAL(%d) conversion", Operand::kind, TO::kind); - RealFlagWarnings(ctx, converted.flags, buffer); + ctx.RealFlagWarnings(converted.flags, buffer); } return ScalarConstantToExpr(std::move(converted.value)); } else if constexpr (FromCat == TypeCategory::Real) { @@ -1871,7 +1871,7 @@ Expr<TO> FoldOperation( if (!converted.flags.empty()) { std::snprintf(buffer, sizeof buffer, "REAL(%d) to REAL(%d) conversion", Operand::kind, TO::kind); - RealFlagWarnings(ctx, converted.flags, buffer); + ctx.RealFlagWarnings(converted.flags, buffer); } if (ctx.targetCharacteristics().areSubnormalsFlushedToZero()) { converted.value = converted.value.FlushSubnormalToZero(); @@ -2012,7 +2012,7 @@ Expr<T> FoldOperation(FoldingContext &context, Add<T> &&x) { } else { auto sum{folded->first.Add( folded->second, context.targetCharacteristics().roundingMode())}; - RealFlagWarnings(context, sum.flags, "addition"); + context.RealFlagWarnings(sum.flags, "addition"); if (context.targetCharacteristics().areSubnormalsFlushedToZero()) { sum.value = sum.value.FlushSubnormalToZero(); } @@ -2041,7 +2041,7 @@ Expr<T> FoldOperation(FoldingContext &context, Subtract<T> &&x) { } else { auto difference{folded->first.Subtract( folded->second, context.targetCharacteristics().roundingMode())}; - RealFlagWarnings(context, difference.flags, "subtraction"); + context.RealFlagWarnings(difference.flags, "subtraction"); if (context.targetCharacteristics().areSubnormalsFlushedToZero()) { difference.value = difference.value.FlushSubnormalToZero(); } @@ -2070,7 +2070,7 @@ Expr<T> FoldOperation(FoldingContext &context, Multiply<T> &&x) { } else { auto product{folded->first.Multiply( folded->second, context.targetCharacteristics().roundingMode())}; - RealFlagWarnings(context, product.flags, "multiplication"); + context.RealFlagWarnings(product.flags, "multiplication"); if (context.targetCharacteristics().areSubnormalsFlushedToZero()) { product.value = product.value.FlushSubnormalToZero(); } @@ -2141,7 +2141,7 @@ Expr<T> FoldOperation(FoldingContext &context, Divide<T> &&x) { } } if (!isCanonicalNaNOrInf) { - RealFlagWarnings(context, quotient.flags, "division"); + context.RealFlagWarnings(quotient.flags, "division"); } if (context.targetCharacteristics().areSubnormalsFlushedToZero()) { quotient.value = quotient.value.FlushSubnormalToZero(); @@ -2201,7 +2201,7 @@ Expr<T> FoldOperation(FoldingContext &context, RealToIntPower<T> &&x) { [&](auto &y) -> Expr<T> { if (auto folded{OperandsAreConstants(x.left(), y)}) { auto power{evaluate::IntPower(folded->first, folded->second)}; - RealFlagWarnings(context, power.flags, "power with INTEGER exponent"); + context.RealFlagWarnings(power.flags, "power with INTEGER exponent"); if (context.targetCharacteristics().areSubnormalsFlushedToZero()) { power.value = power.value.FlushSubnormalToZero(); } diff --git a/flang/lib/Evaluate/fold-real.cpp b/flang/lib/Evaluate/fold-real.cpp index 225e340..1ff9410 100644 --- a/flang/lib/Evaluate/fold-real.cpp +++ b/flang/lib/Evaluate/fold-real.cpp @@ -425,8 +425,14 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction( [](const Scalar<T> &x) -> Scalar<T> { return x.SPACING(); })); } else if (name == "sqrt") { return FoldElementalIntrinsic<T, T>(context, std::move(funcRef), - ScalarFunc<T, T>( - [](const Scalar<T> &x) -> Scalar<T> { return x.SQRT().value; })); + ScalarFunc<T, T>([&context](const Scalar<T> &x) -> Scalar<T> { + ValueWithRealFlags<Scalar<T>> result{x.SQRT()}; + if (result.flags.test(RealFlag::InvalidArgument)) { + context.Warn(common::UsageWarning::FoldingValueChecks, + "Invalid argument to SQRT()"_warn_en_US); + } + return result.value; + })); } else if (name == "sum") { return FoldSum<T>(context, std::move(funcRef)); } else if (name == "tiny") { diff --git a/flang/lib/Evaluate/host.cpp b/flang/lib/Evaluate/host.cpp index 25409ac..bf02496 100644 --- a/flang/lib/Evaluate/host.cpp +++ b/flang/lib/Evaluate/host.cpp @@ -140,8 +140,8 @@ void HostFloatingPointEnvironment::CheckAndRestoreFloatingPointEnvironment( } if (!flags_.empty()) { - RealFlagWarnings( - context, flags_, "evaluation of intrinsic function or operation"); + context.RealFlagWarnings( + flags_, "evaluation of intrinsic function or operation"); } errno = 0; if (fesetenv(&originalFenv_) != 0) { diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp index 9820aa3..54726ac5 100644 --- a/flang/lib/Evaluate/intrinsics-library.cpp +++ b/flang/lib/Evaluate/intrinsics-library.cpp @@ -1043,7 +1043,7 @@ std::optional<HostRuntimeWrapper> GetHostRuntimeWrapper(const std::string &name, if (const auto *hostFunction{ SearchHostRuntime(name, biggerResultType, biggerArgTypes)}) { auto hostFolderWithChecks{AddArgumentVerifierIfAny(name, *hostFunction)}; - return [hostFunction, resultType, hostFolderWithChecks]( + return [hostFunction, resultType, hostFolderWithChecks, name]( FoldingContext &context, std::vector<Expr<SomeType>> &&args) { auto nArgs{args.size()}; for (size_t i{0}; i < nArgs; ++i) { @@ -1051,6 +1051,8 @@ std::optional<HostRuntimeWrapper> GetHostRuntimeWrapper(const std::string &name, ConvertToType(hostFunction->argumentTypes[i], std::move(args[i])) .value()); } + auto restorer{context.SetRealFlagWarningContext( + "compilation-time evaluation of a call to '"s + name + "'"s)}; return Fold(context, ConvertToType( resultType, hostFolderWithChecks(context, std::move(args))) diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp index 1de5e6b..da39f19 100644 --- a/flang/lib/Evaluate/intrinsics.cpp +++ b/flang/lib/Evaluate/intrinsics.cpp @@ -654,6 +654,11 @@ static const IntrinsicInterface genericIntrinsicFunction[]{ {{"i", OperandUnsigned}, {"j", OperandUnsigned, Rank::elementalOrBOZ}}, OperandUnsigned}, {"ior", {{"i", BOZ}, {"j", SameIntOrUnsigned}}, SameIntOrUnsigned}, + {"irand", + {{"i", TypePattern{IntType, KindCode::exactKind, 4}, Rank::scalar, + Optionality::optional}}, + TypePattern{IntType, KindCode::exactKind, 4}, Rank::scalar, + IntrinsicClass::impureFunction}, {"ishft", {{"i", SameIntOrUnsigned}, {"shift", AnyInt}}, SameIntOrUnsigned}, {"ishftc", {{"i", SameIntOrUnsigned}, {"shift", AnyInt}, @@ -872,6 +877,11 @@ static const IntrinsicInterface genericIntrinsicFunction[]{ common::Intent::In, {ArgFlag::canBeMoldNull, ArgFlag::onlyConstantInquiry}}}, DefaultInt, Rank::scalar, IntrinsicClass::inquiryFunction}, + {"rand", + {{"i", TypePattern{IntType, KindCode::exactKind, 4}, Rank::scalar, + Optionality::optional}}, + TypePattern{RealType, KindCode::exactKind, 4}, Rank::scalar, + IntrinsicClass::impureFunction}, {"range", {{"x", AnyNumeric, Rank::anyOrAssumedRank, Optionality::required, common::Intent::In, @@ -1597,6 +1607,10 @@ static const IntrinsicInterface intrinsicSubroutine[]{ {"exit", {{"status", DefaultInt, Rank::scalar, Optionality::optional}}, {}, Rank::elemental, IntrinsicClass::impureSubroutine}, {"free", {{"ptr", Addressable}}, {}}, + {"flush", + {{"unit", AnyInt, Rank::scalar, Optionality::optional, + common::Intent::In}}, + {}, Rank::elemental, IntrinsicClass::impureSubroutine}, {"fseek", {{"unit", AnyInt, Rank::scalar}, {"offset", AnyInt, Rank::scalar}, {"whence", AnyInt, Rank::scalar}, @@ -1701,6 +1715,8 @@ static const IntrinsicInterface intrinsicSubroutine[]{ {}, Rank::scalar, IntrinsicClass::impureSubroutine}, {"second", {{"time", DefaultReal, Rank::scalar}}, {}, Rank::scalar, IntrinsicClass::impureSubroutine}, + {"__builtin_show_descriptor", {{"d", AnyData, Rank::anyOrAssumedRank}}, {}, + Rank::elemental, IntrinsicClass::impureSubroutine}, {"system", {{"command", DefaultChar, Rank::scalar}, {"exitstat", DefaultInt, Rank::scalar, Optionality::optional, @@ -2822,7 +2838,8 @@ std::optional<SpecificCall> IntrinsicInterface::Match( name, characteristics::Procedure{std::move(dummyArgs), attrs}}, std::move(rearranged)}; } else { - attrs.set(characteristics::Procedure::Attr::Pure); + if (intrinsicClass != IntrinsicClass::impureFunction /* RAND and IRAND */) + attrs.set(characteristics::Procedure::Attr::Pure); characteristics::TypeAndShape typeAndShape{resultType.value(), resultRank}; characteristics::FunctionResult funcResult{std::move(typeAndShape)}; characteristics::Procedure chars{ @@ -3139,28 +3156,6 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer( if (type->HasDeferredTypeParameter()) { context.messages().Say(at, "FPTR= argument to C_F_POINTER() may not have a deferred type parameter"_err_en_US); - } else if (type->category() == TypeCategory::Derived) { - if (type->IsUnlimitedPolymorphic()) { - context.Warn(common::UsageWarning::Interoperability, at, - "FPTR= argument to C_F_POINTER() should not be unlimited polymorphic"_warn_en_US); - } else if (!type->GetDerivedTypeSpec().typeSymbol().attrs().test( - semantics::Attr::BIND_C)) { - context.Warn(common::UsageWarning::Portability, at, - "FPTR= argument to C_F_POINTER() should not have a derived type that is not BIND(C)"_port_en_US); - } - } else if (!IsInteroperableIntrinsicType( - *type, &context.languageFeatures()) - .value_or(true)) { - if (type->category() == TypeCategory::Character && - type->kind() == 1) { - context.Warn(common::UsageWarning::CharacterInteroperability, at, - "FPTR= argument to C_F_POINTER() should not have the non-interoperable character length %s"_warn_en_US, - type->AsFortran()); - } else { - context.Warn(common::UsageWarning::Interoperability, at, - "FPTR= argument to C_F_POINTER() should not have the non-interoperable intrinsic type or kind %s"_warn_en_US, - type->AsFortran()); - } } if (ExtractCoarrayRef(*expr)) { context.messages().Say(at, diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp index bd06acc..a0035ae 100644 --- a/flang/lib/Evaluate/tools.cpp +++ b/flang/lib/Evaluate/tools.cpp @@ -63,7 +63,11 @@ Expr<SomeType> Parenthesize(Expr<SomeType> &&expr) { std::optional<DataRef> ExtractDataRef( const ActualArgument &arg, bool intoSubstring, bool intoComplexPart) { - return ExtractDataRef(arg.UnwrapExpr(), intoSubstring, intoComplexPart); + if (const Symbol *assumedType{arg.GetAssumedTypeDummy()}) { + return DataRef{*assumedType}; + } else { + return ExtractDataRef(arg.UnwrapExpr(), intoSubstring, intoComplexPart); + } } std::optional<DataRef> ExtractSubstringBase(const Substring &substring) { @@ -1210,6 +1214,20 @@ bool HasConstant(const Expr<SomeType> &expr) { return HasConstantHelper{}(expr); } +// HasStructureComponent() +struct HasStructureComponentHelper + : public AnyTraverse<HasStructureComponentHelper, bool, false> { + using Base = AnyTraverse<HasStructureComponentHelper, bool, false>; + HasStructureComponentHelper() : Base(*this) {} + using Base::operator(); + + bool operator()(const Component &) const { return true; } +}; + +bool HasStructureComponent(const Expr<SomeType> &expr) { + return HasStructureComponentHelper{}(expr); +} + parser::Message *AttachDeclaration( parser::Message &message, const Symbol &symbol) { const Symbol *unhosted{&symbol}; diff --git a/flang/lib/Evaluate/variable.cpp b/flang/lib/Evaluate/variable.cpp index b9b34d4..b257dad 100644 --- a/flang/lib/Evaluate/variable.cpp +++ b/flang/lib/Evaluate/variable.cpp @@ -89,6 +89,14 @@ std::optional<Expr<SomeType>> CoarrayRef::team() const { } } +std::optional<Expr<SomeType>> CoarrayRef::notify() const { + if (notify_) { + return notify_.value().value(); + } else { + return std::nullopt; + } +} + CoarrayRef &CoarrayRef::set_stat(Expr<SomeInteger> &&v) { CHECK(IsVariable(v)); stat_.emplace(std::move(v)); @@ -100,6 +108,11 @@ CoarrayRef &CoarrayRef::set_team(Expr<SomeType> &&v) { return *this; } +CoarrayRef &CoarrayRef::set_notify(Expr<SomeType> &&v) { + notify_.emplace(std::move(v)); + return *this; +} + const Symbol &CoarrayRef::GetFirstSymbol() const { return base().GetFirstSymbol(); } |
