66 changes: 36 additions & 30 deletions flang/lib/Evaluate/check-expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ std::optional<Expr<SomeType>> NonPointerInitializationExpr(const Symbol &symbol,
symbol.owner().context().ShouldWarn(
common::LanguageFeature::LogicalIntegerAssignment)) {
context.messages().Say(
common::LanguageFeature::LogicalIntegerAssignment,
"nonstandard usage: initialization of %s with %s"_port_en_US,
symTS->type().AsFortran(), x.GetType().value().AsFortran());
}
Expand Down Expand Up @@ -565,7 +566,7 @@ class CheckSpecificationExprHelper
if (!scope_.IsModuleFile() &&
context_.languageFeatures().ShouldWarn(
common::LanguageFeature::SavedLocalInSpecExpr)) {
context_.messages().Say(
context_.messages().Say(common::LanguageFeature::SavedLocalInSpecExpr,
"specification expression refers to local object '%s' (initialized and saved)"_port_en_US,
ultimate.name().ToString());
}
Expand Down Expand Up @@ -1102,44 +1103,53 @@ class StmtFunctionChecker
public:
using Result = std::optional<parser::Message>;
using Base = AnyTraverse<StmtFunctionChecker, Result>;

static constexpr auto feature{
common::LanguageFeature::StatementFunctionExtensions};

StmtFunctionChecker(const Symbol &sf, FoldingContext &context)
: Base{*this}, sf_{sf}, context_{context} {
if (!context_.languageFeatures().IsEnabled(
common::LanguageFeature::StatementFunctionExtensions)) {
if (!context_.languageFeatures().IsEnabled(feature)) {
severity_ = parser::Severity::Error;
} else if (context_.languageFeatures().ShouldWarn(
common::LanguageFeature::StatementFunctionExtensions)) {
} else if (context_.languageFeatures().ShouldWarn(feature)) {
severity_ = parser::Severity::Portability;
}
}
using Base::operator();

template <typename T> Result operator()(const ArrayConstructor<T> &) const {
Result Return(parser::Message &&msg) const {
if (severity_) {
auto msg{
"Statement function '%s' should not contain an array constructor"_port_en_US};
msg.set_severity(*severity_);
return parser::Message{sf_.name(), std::move(msg), sf_.name()};
if (*severity_ != parser::Severity::Error) {
msg.set_languageFeature(feature);
}
}
return std::move(msg);
}

template <typename T> Result operator()(const ArrayConstructor<T> &) const {
if (severity_) {
return Return(parser::Message{sf_.name(),
"Statement function '%s' should not contain an array constructor"_port_en_US,
sf_.name()});
} else {
return std::nullopt;
}
}
Result operator()(const StructureConstructor &) const {
if (severity_) {
auto msg{
"Statement function '%s' should not contain a structure constructor"_port_en_US};
msg.set_severity(*severity_);
return parser::Message{sf_.name(), std::move(msg), sf_.name()};
return Return(parser::Message{sf_.name(),
"Statement function '%s' should not contain a structure constructor"_port_en_US,
sf_.name()});
} else {
return std::nullopt;
}
}
Result operator()(const TypeParamInquiry &) const {
if (severity_) {
auto msg{
"Statement function '%s' should not contain a type parameter inquiry"_port_en_US};
msg.set_severity(*severity_);
return parser::Message{sf_.name(), std::move(msg), sf_.name()};
return Return(parser::Message{sf_.name(),
"Statement function '%s' should not contain a type parameter inquiry"_port_en_US,
sf_.name()});
} else {
return std::nullopt;
}
Expand All @@ -1161,21 +1171,18 @@ class StmtFunctionChecker
proc, context_, /*emitError=*/true)}) {
if (!chars->CanBeCalledViaImplicitInterface()) {
if (severity_) {
auto msg{
"Statement function '%s' should not reference function '%s' that requires an explicit interface"_port_en_US};
msg.set_severity(*severity_);
return parser::Message{
sf_.name(), std::move(msg), sf_.name(), symbol->name()};
return Return(parser::Message{sf_.name(),
"Statement function '%s' should not reference function '%s' that requires an explicit interface"_port_en_US,
sf_.name(), symbol->name()});
}
}
}
}
if (proc.Rank() > 0) {
if (severity_) {
auto msg{
"Statement function '%s' should not reference a function that returns an array"_port_en_US};
msg.set_severity(*severity_);
return parser::Message{sf_.name(), std::move(msg), sf_.name()};
return Return(parser::Message{sf_.name(),
"Statement function '%s' should not reference a function that returns an array"_port_en_US,
sf_.name()});
}
}
return std::nullopt;
Expand All @@ -1187,10 +1194,9 @@ class StmtFunctionChecker
}
if (expr->Rank() > 0 && !UnwrapWholeSymbolOrComponentDataRef(*expr)) {
if (severity_) {
auto msg{
"Statement function '%s' should not pass an array argument that is not a whole array"_port_en_US};
msg.set_severity(*severity_);
return parser::Message{sf_.name(), std::move(msg), sf_.name()};
return Return(parser::Message{sf_.name(),
"Statement function '%s' should not pass an array argument that is not a whole array"_port_en_US,
sf_.name()});
}
}
}
Expand Down
16 changes: 9 additions & 7 deletions flang/lib/Evaluate/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,25 @@ namespace Fortran::evaluate {

void RealFlagWarnings(
FoldingContext &context, const RealFlags &flags, const char *operation) {
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
static constexpr auto warning{common::UsageWarning::FoldingException};
if (context.languageFeatures().ShouldWarn(warning)) {
if (flags.test(RealFlag::Overflow)) {
context.messages().Say("overflow on %s"_warn_en_US, operation);
context.messages().Say(warning, "overflow on %s"_warn_en_US, operation);
}
if (flags.test(RealFlag::DivideByZero)) {
if (std::strcmp(operation, "division") == 0) {
context.messages().Say("division by zero"_warn_en_US);
context.messages().Say(warning, "division by zero"_warn_en_US);
} else {
context.messages().Say("division by zero on %s"_warn_en_US, operation);
context.messages().Say(
warning, "division by zero on %s"_warn_en_US, operation);
}
}
if (flags.test(RealFlag::InvalidArgument)) {
context.messages().Say("invalid argument on %s"_warn_en_US, operation);
context.messages().Say(
warning, "invalid argument on %s"_warn_en_US, operation);
}
if (flags.test(RealFlag::Underflow)) {
context.messages().Say("underflow on %s"_warn_en_US, operation);
context.messages().Say(warning, "underflow on %s"_warn_en_US, operation);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions flang/lib/Evaluate/fold-character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
if (i.IsNegative() || i.BGE(Scalar<IntT>{0}.IBSET(8 * KIND))) {
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingValueChecks)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingValueChecks,
"%s(I=%jd) is out of range for CHARACTER(KIND=%d)"_warn_en_US,
parser::ToUpperCaseLetters(name),
static_cast<std::intmax_t>(i.ToInt64()), KIND);
Expand Down Expand Up @@ -108,7 +108,7 @@ Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
(1 << 20)) { // sanity limit of 1MiB
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingLimit)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingLimit,
"Result of REPEAT() is too large to compute at compilation time (%g characters)"_port_en_US,
static_cast<double>(n) * str.size());
}
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Evaluate/fold-complex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Expr<Type<TypeCategory::Complex, KIND>> FoldIntrinsicFunction(
context, std::move(funcRef), *callable);
} else if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingFailure)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingFailure,
"%s(complex(kind=%d)) cannot be folded on host"_warn_en_US, name,
KIND);
}
Expand Down
26 changes: 13 additions & 13 deletions flang/lib/Evaluate/fold-implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -1735,7 +1735,7 @@ Expr<TO> FoldOperation(
if (converted.overflow &&
msvcWorkaround.context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
ctx.messages().Say(
ctx.messages().Say(common::UsageWarning::FoldingException,
"conversion of %s_%d to INTEGER(%d) overflowed; result is %s"_warn_en_US,
value->SignedDecimal(), Operand::kind, TO::kind,
converted.value.SignedDecimal());
Expand All @@ -1746,7 +1746,7 @@ Expr<TO> FoldOperation(
if (msvcWorkaround.context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
if (converted.flags.test(RealFlag::InvalidArgument)) {
ctx.messages().Say(
ctx.messages().Say(common::UsageWarning::FoldingException,
"REAL(%d) to INTEGER(%d) conversion: invalid argument"_warn_en_US,
Operand::kind, TO::kind);
} else if (converted.flags.test(RealFlag::Overflow)) {
Expand Down Expand Up @@ -1865,7 +1865,7 @@ Expr<T> FoldOperation(FoldingContext &context, Negate<T> &&x) {
if (negated.overflow &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"INTEGER(%d) negation overflowed"_warn_en_US, T::kind);
}
return Expr<T>{Constant<T>{std::move(negated.value)}};
Expand Down Expand Up @@ -1907,7 +1907,7 @@ Expr<T> FoldOperation(FoldingContext &context, Add<T> &&x) {
if (sum.overflow &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"INTEGER(%d) addition overflowed"_warn_en_US, T::kind);
}
return Expr<T>{Constant<T>{sum.value}};
Expand Down Expand Up @@ -1935,7 +1935,7 @@ Expr<T> FoldOperation(FoldingContext &context, Subtract<T> &&x) {
if (difference.overflow &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"INTEGER(%d) subtraction overflowed"_warn_en_US, T::kind);
}
return Expr<T>{Constant<T>{difference.value}};
Expand Down Expand Up @@ -1963,7 +1963,7 @@ Expr<T> FoldOperation(FoldingContext &context, Multiply<T> &&x) {
if (product.SignedMultiplicationOverflowed() &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"INTEGER(%d) multiplication overflowed"_warn_en_US, T::kind);
}
return Expr<T>{Constant<T>{product.lower}};
Expand Down Expand Up @@ -2009,15 +2009,15 @@ Expr<T> FoldOperation(FoldingContext &context, Divide<T> &&x) {
if (quotAndRem.divisionByZero) {
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"INTEGER(%d) division by zero"_warn_en_US, T::kind);
}
return Expr<T>{std::move(x)};
}
if (quotAndRem.overflow &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"INTEGER(%d) division overflowed"_warn_en_US, T::kind);
}
return Expr<T>{Constant<T>{quotAndRem.quotient}};
Expand Down Expand Up @@ -2060,13 +2060,13 @@ Expr<T> FoldOperation(FoldingContext &context, Power<T> &&x) {
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
if (power.divisionByZero) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"INTEGER(%d) zero to negative power"_warn_en_US, T::kind);
} else if (power.overflow) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"INTEGER(%d) power overflowed"_warn_en_US, T::kind);
} else if (power.zeroToZero) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"INTEGER(%d) 0**0 is not defined"_warn_en_US, T::kind);
}
}
Expand All @@ -2077,7 +2077,7 @@ Expr<T> FoldOperation(FoldingContext &context, Power<T> &&x) {
Constant<T>{(*callable)(context, folded->first, folded->second)}};
} else if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingFailure)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingFailure,
"Power for %s cannot be folded on host"_warn_en_US,
T{}.AsFortran());
}
Expand Down Expand Up @@ -2163,7 +2163,7 @@ Expr<Type<TypeCategory::Real, KIND>> ToReal(
if (original != converted &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingValueChecks)) { // C1601
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingValueChecks,
"Nonzero bits truncated from BOZ literal constant in REAL intrinsic"_warn_en_US);
}
} else if constexpr (IsNumericCategoryExpr<From>()) {
Expand Down
34 changes: 22 additions & 12 deletions flang/lib/Evaluate/fold-integer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ static Expr<T> FoldCount(FoldingContext &context, FunctionRef<T> &&ref) {
if (accumulator.overflow() &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"Result of intrinsic function COUNT overflows its result type"_warn_en_US);
}
return Expr<T>{std::move(result)};
Expand Down Expand Up @@ -562,7 +562,7 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
if (result.ToInt64() != n &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"Result of intrinsic function '%s' (%jd) overflows its result type"_warn_en_US,
name, std::intmax_t{n});
}
Expand All @@ -575,7 +575,7 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
if (j.overflow &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"abs(integer(kind=%d)) folding overflowed"_warn_en_US, KIND);
}
return j.value;
Expand All @@ -598,6 +598,7 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
common::UsageWarning::FoldingException,
"%s intrinsic folding overflow"_warn_en_US, name);
}
return y.value;
Expand Down Expand Up @@ -646,7 +647,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
if (result.overflow &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say("DIM intrinsic folding overflow"_warn_en_US);
context.messages().Say(common::UsageWarning::FoldingException,
"DIM intrinsic folding overflow"_warn_en_US);
}
return result.value;
}));
Expand Down Expand Up @@ -708,7 +710,7 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
context.languageFeatures().ShouldWarn(
common::UsageWarning::Portability)) {
// Do not die, this was not checked before
context.messages().Say(
context.messages().Say(common::UsageWarning::Portability,
"Character in intrinsic function %s should have length one"_port_en_US,
name);
} else {
Expand Down Expand Up @@ -1127,7 +1129,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
pConst->IsZero() &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
context.messages().Say("MOD: P argument is zero"_warn_en_US);
context.messages().Say(common::UsageWarning::FoldingAvoidsRuntimeCrash,
"MOD: P argument is zero"_warn_en_US);
badPConst = true;
}
}
Expand All @@ -1139,9 +1142,13 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
if (!badPConst && quotRem.divisionByZero) {
context.messages().Say("mod() by zero"_warn_en_US);
context.messages().Say(
common::UsageWarning::FoldingAvoidsRuntimeCrash,
"mod() by zero"_warn_en_US);
} else if (quotRem.overflow) {
context.messages().Say("mod() folding overflowed"_warn_en_US);
context.messages().Say(
common::UsageWarning::FoldingAvoidsRuntimeCrash,
"mod() folding overflowed"_warn_en_US);
}
}
return quotRem.remainder;
Expand All @@ -1154,7 +1161,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
pConst->IsZero() &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
context.messages().Say("MODULO: P argument is zero"_warn_en_US);
context.messages().Say(common::UsageWarning::FoldingAvoidsRuntimeCrash,
"MODULO: P argument is zero"_warn_en_US);
badPConst = true;
}
}
Expand All @@ -1166,7 +1174,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
if (!badPConst && result.overflow &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say("modulo() folding overflowed"_warn_en_US);
context.messages().Say(common::UsageWarning::FoldingException,
"modulo() folding overflowed"_warn_en_US);
}
return result.value;
}));
Expand Down Expand Up @@ -1303,7 +1312,7 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
if (result.overflow &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"sign(integer(kind=%d)) folding overflowed"_warn_en_US, KIND);
}
return result.value;
Expand Down Expand Up @@ -1363,7 +1372,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
if (intBytes != realBytes &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingValueChecks)) {
context.messages().Say(*context.moduleFileName(),
context.messages().Say(common::UsageWarning::FoldingValueChecks,
*context.moduleFileName(),
"NUMERIC_STORAGE_SIZE from ISO_FORTRAN_ENV is not well-defined when default INTEGER and REAL are not consistent due to compiler options"_warn_en_US);
}
return Expr<T>{8 * std::min(intBytes, realBytes)};
Expand Down
3 changes: 2 additions & 1 deletion flang/lib/Evaluate/fold-logical.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,8 @@ static Expr<Type<TypeCategory::Logical, KIND>> RewriteOutOfRange(
context.languageFeatures().ShouldWarn(
common::UsageWarning::OptionalMustBePresent)) {
if (auto source{args[2]->sourceLocation()}) {
context.messages().Say(*source,
context.messages().Say(
common::UsageWarning::OptionalMustBePresent, *source,
"ROUND= argument to OUT_OF_RANGE() is an optional dummy argument that must be present at execution"_warn_en_US);
}
}
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Evaluate/fold-matmul.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ static Expr<T> FoldMatmul(FoldingContext &context, FunctionRef<T> &&funcRef) {
if (overflow &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"MATMUL of %s data overflowed during computation"_warn_en_US,
T::AsFortran());
}
Expand Down
36 changes: 23 additions & 13 deletions flang/lib/Evaluate/fold-real.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ static Expr<T> FoldTransformationalBessel(
std::move(results), ConstantSubscripts{std::max(n2 - n1 + 1, 0)}}};
} else if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingFailure)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingFailure,
"%s(integer(kind=4), real(kind=%d)) cannot be folded on host"_warn_en_US,
name, T::kind);
}
Expand Down Expand Up @@ -134,7 +134,7 @@ static Expr<Type<TypeCategory::Real, KIND>> FoldNorm2(FoldingContext &context,
if (norm2Accumulator.overflow() &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"NORM2() of REAL(%d) data overflowed"_warn_en_US, KIND);
}
return Expr<T>{std::move(result)};
Expand Down Expand Up @@ -167,7 +167,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
context, std::move(funcRef), *callable);
} else if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingFailure)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingFailure,
"%s(real(kind=%d)) cannot be folded on host"_warn_en_US, name, KIND);
}
} else if (name == "amax0" || name == "amin0" || name == "amin1" ||
Expand All @@ -181,7 +181,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
context, std::move(funcRef), *callable);
} else if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingFailure)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingFailure,
"%s(real(kind=%d), real(kind%d)) cannot be folded on host"_warn_en_US,
name, KIND, KIND);
}
Expand All @@ -193,7 +193,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
context, std::move(funcRef), *callable);
} else if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingFailure)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingFailure,
"%s(integer(kind=4), real(kind=%d)) cannot be folded on host"_warn_en_US,
name, KIND);
}
Expand All @@ -213,7 +213,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
if (y.flags.test(RealFlag::Overflow) &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"complex ABS intrinsic folding overflow"_warn_en_US, name);
}
return y.value;
Expand All @@ -237,7 +237,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
if (y.flags.test(RealFlag::Overflow) &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"%s intrinsic folding overflow"_warn_en_US, name);
}
return y.value;
Expand All @@ -250,7 +250,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
if (result.flags.test(RealFlag::Overflow) &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say("DIM intrinsic folding overflow"_warn_en_US);
context.messages().Say(common::UsageWarning::FoldingException,
"DIM intrinsic folding overflow"_warn_en_US);
}
return result.value;
}));
Expand Down Expand Up @@ -284,7 +285,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
if (result.flags.test(RealFlag::Overflow) &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"HYPOT intrinsic folding overflow"_warn_en_US);
}
return result.value;
Expand All @@ -310,7 +311,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
pConst->IsZero() &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
context.messages().Say("MOD: P argument is zero"_warn_en_US);
context.messages().Say(common::UsageWarning::FoldingAvoidsRuntimeCrash,
"MOD: P argument is zero"_warn_en_US);
badPConst = true;
}
}
Expand All @@ -322,6 +324,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
context.messages().Say(
common::UsageWarning::FoldingAvoidsRuntimeCrash,
"second argument to MOD must not be zero"_warn_en_US);
}
return result.value;
Expand All @@ -335,7 +338,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
pConst->IsZero() &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
context.messages().Say("MODULO: P argument is zero"_warn_en_US);
context.messages().Say(common::UsageWarning::FoldingAvoidsRuntimeCrash,
"MODULO: P argument is zero"_warn_en_US);
badPConst = true;
}
}
Expand All @@ -347,6 +351,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
context.messages().Say(
common::UsageWarning::FoldingAvoidsRuntimeCrash,
"second argument to MODULO must not be zero"_warn_en_US);
}
return result.value;
Expand All @@ -362,7 +367,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
(sConst->IsZero() || sConst->IsNotANumber()) &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingValueChecks)) {
context.messages().Say("NEAREST: S argument is %s"_warn_en_US,
context.messages().Say(common::UsageWarning::FoldingValueChecks,
"NEAREST: S argument is %s"_warn_en_US,
sConst->IsZero() ? "zero" : "NaN");
badSConst = true;
}
Expand All @@ -373,6 +379,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingValueChecks)) {
context.messages().Say(
common::UsageWarning::FoldingValueChecks,
"NEAREST: S argument is %s"_warn_en_US,
s.IsZero() ? "zero" : "NaN");
}
Expand All @@ -381,6 +388,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
common::UsageWarning::FoldingException)) {
if (result.flags.test(RealFlag::InvalidArgument)) {
context.messages().Say(
common::UsageWarning::FoldingException,
"NEAREST intrinsic folding: bad argument"_warn_en_US);
}
}
Expand Down Expand Up @@ -423,6 +431,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
common::UsageWarning::FoldingException,
"SCALE intrinsic folding overflow"_warn_en_US);
}
return result.value;
Expand Down Expand Up @@ -475,6 +484,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingValueChecks)) {
context.messages().Say(
common::UsageWarning::FoldingValueChecks,
"IEEE_NEXT_AFTER intrinsic folding: arguments are unordered"_warn_en_US);
}
return x.NotANumber();
Expand All @@ -500,7 +510,7 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
if (result.flags.test(RealFlag::InvalidArgument)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"%s intrinsic folding: argument is NaN"_warn_en_US, iName);
}
}
Expand Down
6 changes: 3 additions & 3 deletions flang/lib/Evaluate/fold-reduction.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ static Expr<T> FoldDotProduct(
if (overflow &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"DOT_PRODUCT of %s data overflowed during computation"_warn_en_US,
T::AsFortran());
}
Expand Down Expand Up @@ -326,7 +326,7 @@ static Expr<T> FoldProduct(
if (accumulator.overflow() &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"PRODUCT() of %s data overflowed"_warn_en_US, T::AsFortran());
}
return result;
Expand Down Expand Up @@ -394,7 +394,7 @@ static Expr<T> FoldSum(FoldingContext &context, FunctionRef<T> &&ref) {
if (accumulator.overflow() &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingException,
"SUM() of %s data overflowed"_warn_en_US, T::AsFortran());
}
return result;
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Evaluate/host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ void HostFloatingPointEnvironment::SetUpHostFloatingPointEnvironment(
fesetround(FE_TONEAREST);
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingFailure)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::FoldingFailure,
"TiesAwayFromZero rounding mode is not available when folding "
"constants"
" with host runtime; using TiesToEven instead"_warn_en_US);
Expand Down
17 changes: 11 additions & 6 deletions flang/lib/Evaluate/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,9 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
{{"c", DefaultChar, Rank::scalar, Optionality::required,
common::Intent::Out}},
TypePattern{IntType, KindCode::greaterOrEqualToKind, 4}},
{"getgid", {}, DefaultInt},
{"getpid", {}, DefaultInt},
{"getuid", {}, DefaultInt},
{"huge",
{{"x", SameIntOrReal, Rank::anyOrAssumedRank, Optionality::required,
common::Intent::In, {ArgFlag::canBeMoldNull}}},
Expand Down Expand Up @@ -2373,10 +2375,10 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::OptionalMustBePresent)) {
if (rank == Rank::scalarIfDim || arrayRank.value_or(-1) == 1) {
messages.Say(
messages.Say(common::UsageWarning::OptionalMustBePresent,
"The actual argument for DIM= is optional, pointer, or allocatable, and it is assumed to be present and equal to 1 at execution time"_warn_en_US);
} else {
messages.Say(
messages.Say(common::UsageWarning::OptionalMustBePresent,
"The actual argument for DIM= is optional, pointer, or allocatable, and may not be absent during execution; parenthesize to silence this warning"_warn_en_US);
}
}
Expand Down Expand Up @@ -2849,11 +2851,11 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::Interoperability)) {
if (type->IsUnlimitedPolymorphic()) {
context.messages().Say(at,
context.messages().Say(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.messages().Say(at,
context.messages().Say(common::UsageWarning::Interoperability, at,
"FPTR= argument to C_F_POINTER() should not have a derived type that is not BIND(C)"_warn_en_US);
}
}
Expand All @@ -2862,7 +2864,7 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
.value_or(true) &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::Interoperability)) {
context.messages().Say(at,
context.messages().Say(common::UsageWarning::Interoperability, at,
"FPTR= argument to C_F_POINTER() should not have the non-interoperable intrinsic type %s"_warn_en_US,
type->AsFortran());
}
Expand Down Expand Up @@ -2964,7 +2966,8 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::HandleC_Loc(
!IsInteroperableIntrinsicType(typeAndShape->type()).value_or(true) &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::Interoperability)) {
context.messages().Say(arguments[0]->sourceLocation(),
context.messages().Say(common::UsageWarning::Interoperability,
arguments[0]->sourceLocation(),
"C_LOC() argument has non-interoperable intrinsic type, kind, or length"_warn_en_US);
}

Expand Down Expand Up @@ -3309,6 +3312,8 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
common::LanguageFeature::
UseGenericIntrinsicWhenSpecificDoesntMatch)) {
context.messages().Say(
common::LanguageFeature::
UseGenericIntrinsicWhenSpecificDoesntMatch,
"Argument types do not match specific intrinsic '%s' requirements; using '%s' generic instead and converting the result to %s if needed"_port_en_US,
call.name, genericName, newType.AsFortran());
}
Expand Down
4 changes: 2 additions & 2 deletions flang/lib/Evaluate/variable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ std::optional<Expr<SomeCharacter>> Substring::Fold(FoldingContext &context) {
if (!result) { // error cases
if (*lbi < 1) {
if (context.languageFeatures().ShouldWarn(common::UsageWarning::Bounds)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::Bounds,
"Lower bound (%jd) on substring is less than one"_warn_en_US,
static_cast<std::intmax_t>(*lbi));
}
Expand All @@ -224,7 +224,7 @@ std::optional<Expr<SomeCharacter>> Substring::Fold(FoldingContext &context) {
}
if (length && *ubi > *length) {
if (context.languageFeatures().ShouldWarn(common::UsageWarning::Bounds)) {
context.messages().Say(
context.messages().Say(common::UsageWarning::Bounds,
"Upper bound (%jd) on substring is greater than character length (%jd)"_warn_en_US,
static_cast<std::intmax_t>(*ubi),
static_cast<std::intmax_t>(*length));
Expand Down
19 changes: 16 additions & 3 deletions flang/lib/Lower/OpenMP/Clauses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,9 +783,22 @@ IsDevicePtr make(const parser::OmpClause::IsDevicePtr &inp,

Lastprivate make(const parser::OmpClause::Lastprivate &inp,
semantics::SemanticsContext &semaCtx) {
// inp.v -> parser::OmpObjectList
return Lastprivate{{/*LastprivateModifier=*/std::nullopt,
/*List=*/makeObjects(inp.v, semaCtx)}};
// inp.v -> parser::OmpLastprivateClause
using wrapped = parser::OmpLastprivateClause;

CLAUSET_ENUM_CONVERT( //
convert, parser::OmpLastprivateClause::LastprivateModifier,
Lastprivate::LastprivateModifier,
// clang-format off
MS(Conditional, Conditional)
// clang-format on
);

auto &t0 = std::get<std::optional<wrapped::LastprivateModifier>>(inp.v.t);
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);

return Lastprivate{{/*LastprivateModifier=*/maybeApply(convert, t0),
/*List=*/makeObjects(t1, semaCtx)}};
}

Linear make(const parser::OmpClause::Linear &inp,
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ void DataSharingProcessor::collectSymbolsForPrivatization() {
explicitlyPrivatizedSymbols);
} else if (const auto &lastPrivateClause =
std::get_if<omp::clause::Lastprivate>(&clause.u)) {
lastprivateModifierNotSupported(*lastPrivateClause,
converter.getCurrentLocation());
const ObjectList &objects = std::get<ObjectList>(lastPrivateClause->t);
collectOmpObjectListSymbol(objects, explicitlyPrivatizedSymbols);
}
Expand Down
4 changes: 3 additions & 1 deletion flang/lib/Lower/OpenMP/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1563,7 +1563,9 @@ genSectionsOp(lower::AbstractConverter &converter, lower::SymMap &symTable,

for (const Clause &clause : item->clauses) {
if (clause.id == llvm::omp::Clause::OMPC_lastprivate) {
lastprivates.push_back(&std::get<clause::Lastprivate>(clause.u));
auto &lastp = std::get<clause::Lastprivate>(clause.u);
lastprivateModifierNotSupported(lastp, converter.getCurrentLocation());
lastprivates.push_back(&lastp);
} else {
switch (clause.id) {
case llvm::omp::Clause::OMPC_firstprivate:
Expand Down
13 changes: 13 additions & 0 deletions flang/lib/Lower/OpenMP/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <flang/Lower/ConvertType.h>
#include <flang/Lower/PFTBuilder.h>
#include <flang/Optimizer/Builder/FIRBuilder.h>
#include <flang/Optimizer/Builder/Todo.h>
#include <flang/Parser/parse-tree.h>
#include <flang/Parser/tools.h>
#include <flang/Semantics/tools.h>
Expand Down Expand Up @@ -356,6 +357,18 @@ semantics::Symbol *getOmpObjectSymbol(const parser::OmpObject &ompObject) {
return sym;
}

void lastprivateModifierNotSupported(const omp::clause::Lastprivate &lastp,
mlir::Location loc) {
using Lastprivate = omp::clause::Lastprivate;
auto &maybeMod =
std::get<std::optional<Lastprivate::LastprivateModifier>>(lastp.t);
if (maybeMod) {
assert(*maybeMod == Lastprivate::LastprivateModifier::Conditional &&
"Unexpected lastprivate modifier");
TODO(loc, "lastprivate clause with CONDITIONAL modifier");
}
}

} // namespace omp
} // namespace lower
} // namespace Fortran
3 changes: 3 additions & 0 deletions flang/lib/Lower/OpenMP/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ void genObjectList(const ObjectList &objects,
lower::AbstractConverter &converter,
llvm::SmallVectorImpl<mlir::Value> &operands);

void lastprivateModifierNotSupported(const omp::clause::Lastprivate &lastp,
mlir::Location loc);

} // namespace omp
} // namespace lower
} // namespace Fortran
Expand Down
18 changes: 18 additions & 0 deletions flang/lib/Optimizer/Builder/IntrinsicCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,9 @@ static constexpr IntrinsicHandler handlers[]{
&I::genGetCwd,
{{{"c", asBox}, {"status", asAddr, handleDynamicOptional}}},
/*isElemental=*/false},
{"getgid", &I::genGetGID},
{"getpid", &I::genGetPID},
{"getuid", &I::genGetUID},
{"iachar", &I::genIchar},
{"iall",
&I::genIall,
Expand Down Expand Up @@ -3664,6 +3666,14 @@ void IntrinsicLibrary::genGetCommand(llvm::ArrayRef<fir::ExtendedValue> args) {
}
}

// GETGID
mlir::Value IntrinsicLibrary::genGetGID(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 0 && "getgid takes no input");
return builder.createConvert(loc, resultType,
fir::runtime::genGetGID(builder, loc));
}

// GETPID
mlir::Value IntrinsicLibrary::genGetPID(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
Expand All @@ -3672,6 +3682,14 @@ mlir::Value IntrinsicLibrary::genGetPID(mlir::Type resultType,
fir::runtime::genGetPID(builder, loc));
}

// GETUID
mlir::Value IntrinsicLibrary::genGetUID(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 0 && "getgid takes no input");
return builder.createConvert(loc, resultType,
fir::runtime::genGetUID(builder, loc));
}

// GET_COMMAND_ARGUMENT
void IntrinsicLibrary::genGetCommandArgument(
llvm::ArrayRef<fir::ExtendedValue> args) {
Expand Down
16 changes: 16 additions & 0 deletions flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,22 @@ void fir::runtime::genFree(fir::FirOpBuilder &builder, mlir::Location loc,
builder.createConvert(loc, intPtrTy, ptr));
}

mlir::Value fir::runtime::genGetGID(fir::FirOpBuilder &builder,
mlir::Location loc) {
auto runtimeFunc =
fir::runtime::getRuntimeFunc<mkRTKey(GetGID)>(loc, builder);

return builder.create<fir::CallOp>(loc, runtimeFunc).getResult(0);
}

mlir::Value fir::runtime::genGetUID(fir::FirOpBuilder &builder,
mlir::Location loc) {
auto runtimeFunc =
fir::runtime::getRuntimeFunc<mkRTKey(GetUID)>(loc, builder);

return builder.create<fir::CallOp>(loc, runtimeFunc).getResult(0);
}

mlir::Value fir::runtime::genMalloc(fir::FirOpBuilder &builder,
mlir::Location loc, mlir::Value size) {
auto runtimeFunc =
Expand Down
39 changes: 6 additions & 33 deletions flang/lib/Optimizer/CodeGen/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,33 +637,6 @@ struct CmpcOpConversion : public fir::FIROpConversion<fir::CmpcOp> {
}
};

/// Lower complex constants
struct ConstcOpConversion : public fir::FIROpConversion<fir::ConstcOp> {
using FIROpConversion::FIROpConversion;

llvm::LogicalResult
matchAndRewrite(fir::ConstcOp conc, OpAdaptor,
mlir::ConversionPatternRewriter &rewriter) const override {
mlir::Location loc = conc.getLoc();
mlir::Type ty = convertType(conc.getType());
mlir::Type ety = convertType(getComplexEleTy(conc.getType()));
auto realPart = rewriter.create<mlir::LLVM::ConstantOp>(
loc, ety, getValue(conc.getReal()));
auto imPart = rewriter.create<mlir::LLVM::ConstantOp>(
loc, ety, getValue(conc.getImaginary()));
auto undef = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
auto setReal =
rewriter.create<mlir::LLVM::InsertValueOp>(loc, undef, realPart, 0);
rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(conc, setReal,
imPart, 1);
return mlir::success();
}

inline llvm::APFloat getValue(mlir::Attribute attr) const {
return mlir::cast<fir::RealAttr>(attr).getValue();
}
};

/// convert value of from-type to value of to-type
struct ConvertOpConversion : public fir::FIROpConversion<fir::ConvertOp> {
using FIROpConversion::FIROpConversion;
Expand Down Expand Up @@ -3861,12 +3834,12 @@ void fir::populateFIRToLLVMConversionPatterns(
BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
BoxOffsetOpConversion, BoxProcHostOpConversion, BoxRankOpConversion,
BoxTypeCodeOpConversion, BoxTypeDescOpConversion, CallOpConversion,
CmpcOpConversion, ConstcOpConversion, ConvertOpConversion,
CoordinateOpConversion, DTEntryOpConversion, DeclareOpConversion,
DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion,
EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion,
FirEndOpConversion, FreeMemOpConversion, GlobalLenOpConversion,
GlobalOpConversion, InsertOnRangeOpConversion, IsPresentOpConversion,
CmpcOpConversion, ConvertOpConversion, CoordinateOpConversion,
DTEntryOpConversion, DeclareOpConversion, DivcOpConversion,
EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion,
ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion,
FreeMemOpConversion, GlobalLenOpConversion, GlobalOpConversion,
InsertOnRangeOpConversion, IsPresentOpConversion,
LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion,
NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion,
SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
Expand Down
34 changes: 0 additions & 34 deletions flang/lib/Optimizer/Dialect/FIROps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1304,40 +1304,6 @@ mlir::ParseResult fir::CmpcOp::parse(mlir::OpAsmParser &parser,
return parseCmpOp<fir::CmpcOp>(parser, result);
}

//===----------------------------------------------------------------------===//
// ConstcOp
//===----------------------------------------------------------------------===//

mlir::ParseResult fir::ConstcOp::parse(mlir::OpAsmParser &parser,
mlir::OperationState &result) {
fir::RealAttr realp;
fir::RealAttr imagp;
mlir::Type type;
if (parser.parseLParen() ||
parser.parseAttribute(realp, fir::ConstcOp::getRealAttrName(),
result.attributes) ||
parser.parseComma() ||
parser.parseAttribute(imagp, fir::ConstcOp::getImagAttrName(),
result.attributes) ||
parser.parseRParen() || parser.parseColonType(type) ||
parser.addTypesToList(type, result.types))
return mlir::failure();
return mlir::success();
}

void fir::ConstcOp::print(mlir::OpAsmPrinter &p) {
p << '(';
p << getOperation()->getAttr(fir::ConstcOp::getRealAttrName()) << ", ";
p << getOperation()->getAttr(fir::ConstcOp::getImagAttrName()) << ") : ";
p.printType(getType());
}

llvm::LogicalResult fir::ConstcOp::verify() {
if (!mlir::isa<fir::ComplexType>(getType()))
return emitOpError("must be a !fir.complex type");
return mlir::success();
}

//===----------------------------------------------------------------------===//
// ConvertOp
//===----------------------------------------------------------------------===//
Expand Down
18 changes: 18 additions & 0 deletions flang/lib/Parser/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,24 @@ Message &Message::set_severity(Severity severity) {
return *this;
}

std::optional<common::LanguageFeature> Message::languageFeature() const {
return languageFeature_;
}

Message &Message::set_languageFeature(common::LanguageFeature feature) {
languageFeature_ = feature;
return *this;
}

std::optional<common::UsageWarning> Message::usageWarning() const {
return usageWarning_;
}

Message &Message::set_usageWarning(common::UsageWarning warning) {
usageWarning_ = warning;
return *this;
}

std::string Message::ToString() const {
return common::visit(
common::visitors{
Expand Down
8 changes: 7 additions & 1 deletion flang/lib/Parser/openmp-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,12 @@ TYPE_PARSER(construct<OmpOrderClause>(
TYPE_PARSER(
construct<OmpObject>(designator) || construct<OmpObject>("/" >> name / "/"))

// OMP 5.0 2.19.4.5 LASTPRIVATE ([lastprivate-modifier :] list)
TYPE_PARSER(construct<OmpLastprivateClause>(
maybe("CONDITIONAL" >>
pure(OmpLastprivateClause::LastprivateModifier::Conditional) / ":"),
Parser<OmpObjectList>{}))

TYPE_PARSER(
"ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
"ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
Expand Down Expand Up @@ -289,7 +295,7 @@ TYPE_PARSER(
"IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>(
parenthesized(Parser<OmpObjectList>{}))) ||
"LASTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Lastprivate>(
parenthesized(Parser<OmpObjectList>{}))) ||
parenthesized(Parser<OmpLastprivateClause>{}))) ||
"LINEAR" >> construct<OmpClause>(construct<OmpClause::Linear>(
parenthesized(Parser<OmpLinearClause>{}))) ||
"LINK" >> construct<OmpClause>(construct<OmpClause::Link>(
Expand Down
18 changes: 12 additions & 6 deletions flang/lib/Parser/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,8 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
if (dir.IsAnythingLeft(++j)) {
if (prescanner.features().ShouldWarn(
common::UsageWarning::Portability)) {
prescanner.Say(dir.GetIntervalProvenanceRange(j, tokens - j),
prescanner.Say(common::UsageWarning::Portability,
dir.GetIntervalProvenanceRange(j, tokens - j),
"#undef: excess tokens at end of directive"_port_en_US);
}
} else {
Expand All @@ -627,7 +628,8 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
if (dir.IsAnythingLeft(++j)) {
if (prescanner.features().ShouldWarn(
common::UsageWarning::Portability)) {
prescanner.Say(dir.GetIntervalProvenanceRange(j, tokens - j),
prescanner.Say(common::UsageWarning::Portability,
dir.GetIntervalProvenanceRange(j, tokens - j),
"#%s: excess tokens at end of directive"_port_en_US, dirName);
}
}
Expand All @@ -649,7 +651,8 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
} else if (dirName == "else") {
if (dir.IsAnythingLeft(j)) {
if (prescanner.features().ShouldWarn(common::UsageWarning::Portability)) {
prescanner.Say(dir.GetIntervalProvenanceRange(j, tokens - j),
prescanner.Say(common::UsageWarning::Portability,
dir.GetIntervalProvenanceRange(j, tokens - j),
"#else: excess tokens at end of directive"_port_en_US);
}
} else if (ifStack_.empty()) {
Expand Down Expand Up @@ -678,7 +681,8 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
} else if (dirName == "endif") {
if (dir.IsAnythingLeft(j)) {
if (prescanner.features().ShouldWarn(common::UsageWarning::Portability)) {
prescanner.Say(dir.GetIntervalProvenanceRange(j, tokens - j),
prescanner.Say(common::UsageWarning::Portability,
dir.GetIntervalProvenanceRange(j, tokens - j),
"#endif: excess tokens at end of directive"_port_en_US);
}
} else if (ifStack_.empty()) {
Expand Down Expand Up @@ -729,7 +733,8 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
if (k >= pathTokens) {
if (prescanner.features().ShouldWarn(
common::UsageWarning::Portability)) {
prescanner.Say(dir.GetIntervalProvenanceRange(j, tokens - j),
prescanner.Say(common::UsageWarning::Portability,
dir.GetIntervalProvenanceRange(j, tokens - j),
"#include: expected '>' at end of included file"_port_en_US);
}
}
Expand Down Expand Up @@ -758,7 +763,8 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
k = path.SkipBlanks(k + 1);
if (k < pathTokens && path.TokenAt(k).ToString() != "!") {
if (prescanner.features().ShouldWarn(common::UsageWarning::Portability)) {
prescanner.Say(dir.GetIntervalProvenanceRange(j, tokens - j),
prescanner.Say(common::UsageWarning::Portability,
dir.GetIntervalProvenanceRange(j, tokens - j),
"#include: extra stuff ignored after file name"_port_en_US);
}
}
Expand Down
28 changes: 17 additions & 11 deletions flang/lib/Parser/prescan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@ void Prescanner::Statement() {
}
if (continuationLines_ > 255) {
if (features_.ShouldWarn(common::LanguageFeature::MiscSourceExtensions)) {
Say(GetProvenance(statementStart),
Say(common::LanguageFeature::MiscSourceExtensions,
GetProvenance(statementStart),
"%d continuation lines is more than the Fortran standard allows"_port_en_US,
continuationLines_);
}
Expand All @@ -265,7 +266,8 @@ void Prescanner::Statement() {
case LineClassification::Kind::DefinitionDirective:
case LineClassification::Kind::PreprocessorDirective:
if (features_.ShouldWarn(common::UsageWarning::Preprocessing)) {
Say(preprocessed->GetProvenanceRange(),
Say(common::UsageWarning::Preprocessing,
preprocessed->GetProvenanceRange(),
"Preprocessed line resembles a preprocessor directive"_warn_en_US);
}
CheckAndEmitLine(preprocessed->ToLowerCase(), newlineProvenance);
Expand Down Expand Up @@ -400,7 +402,7 @@ void Prescanner::LabelField(TokenSequence &token) {
// CookedSource::Marshal().
cooked_.MarkPossibleFixedFormContinuation();
} else if (features_.ShouldWarn(common::UsageWarning::Scanning)) {
Say(GetProvenance(start + *badColumn - 1),
Say(common::UsageWarning::Scanning, GetProvenance(start + *badColumn - 1),
*badColumn == 6
? "Statement should not begin with a continuation line"_warn_en_US
: "Character in fixed-form label field must be a digit"_warn_en_US);
Expand All @@ -424,7 +426,7 @@ void Prescanner::LabelField(TokenSequence &token) {
SkipToNextSignificantCharacter();
if (IsDecimalDigit(*at_)) {
if (features_.ShouldWarn(common::LanguageFeature::MiscSourceExtensions)) {
Say(GetCurrentProvenance(),
Say(common::LanguageFeature::MiscSourceExtensions, GetCurrentProvenance(),
"Label digit is not in fixed-form label field"_port_en_US);
}
}
Expand Down Expand Up @@ -627,7 +629,7 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
// Recognize and skip over classic C style /*comments*/ when
// outside a character literal.
if (features_.ShouldWarn(LanguageFeature::ClassicCComments)) {
Say(GetCurrentProvenance(),
Say(LanguageFeature::ClassicCComments, GetCurrentProvenance(),
"nonstandard usage: C-style comment"_port_en_US);
}
SkipCComments();
Expand Down Expand Up @@ -795,7 +797,8 @@ bool Prescanner::NextToken(TokenSequence &tokens) {
if (IsDecimalDigit(*at_)) {
if (features_.ShouldWarn(
common::LanguageFeature::MiscSourceExtensions)) {
Say(GetProvenanceRange(at_, at_ + 1),
Say(common::LanguageFeature::MiscSourceExtensions,
GetProvenanceRange(at_, at_ + 1),
"Label should be in the label field"_port_en_US);
}
}
Expand Down Expand Up @@ -923,7 +926,7 @@ void Prescanner::Hollerith(
if (PadOutCharacterLiteral(tokens)) {
} else if (*at_ == '\n') {
if (features_.ShouldWarn(common::UsageWarning::Scanning)) {
Say(GetProvenanceRange(start, at_),
Say(common::UsageWarning::Scanning, GetProvenanceRange(start, at_),
"Possible truncated Hollerith literal"_warn_en_US);
}
break;
Expand Down Expand Up @@ -1087,7 +1090,7 @@ void Prescanner::FortranInclude(const char *firstQuote) {
for (; *p != '\n' && *p != '!'; ++p) {
}
if (features_.ShouldWarn(common::UsageWarning::Scanning)) {
Say(GetProvenanceRange(garbage, p),
Say(common::UsageWarning::Scanning, GetProvenanceRange(garbage, p),
"excess characters after path name"_warn_en_US);
}
}
Expand Down Expand Up @@ -1228,7 +1231,8 @@ const char *Prescanner::FixedFormContinuationLine(bool mightNeedSpace) {
// Extension: '&' as continuation marker
if (features_.ShouldWarn(
LanguageFeature::FixedFormContinuationWithColumn1Ampersand)) {
Say(GetProvenance(nextLine_), "nonstandard usage"_port_en_US);
Say(LanguageFeature::FixedFormContinuationWithColumn1Ampersand,
GetProvenance(nextLine_), "nonstandard usage"_port_en_US);
}
return nextLine_ + 1;
}
Expand Down Expand Up @@ -1294,7 +1298,8 @@ const char *Prescanner::FreeFormContinuationLine(bool ampersand) {
// 'b'
if (features_.ShouldWarn(
common::LanguageFeature::MiscSourceExtensions)) {
Say(GetProvenanceRange(p, p + 1),
Say(common::LanguageFeature::MiscSourceExtensions,
GetProvenanceRange(p, p + 1),
"Character literal continuation line should have been preceded by '&'"_port_en_US);
}
} else if (p > nextLine_) {
Expand Down Expand Up @@ -1339,7 +1344,8 @@ bool Prescanner::FreeFormContinuation() {
} else if (ampersand && isPossibleMacroCall_ && (*p == ',' || *p == ')')) {
return false; // allow & at end of a macro argument
} else if (features_.ShouldWarn(LanguageFeature::CruftAfterAmpersand)) {
Say(GetProvenance(p), "missing ! before comment after &"_warn_en_US);
Say(LanguageFeature::CruftAfterAmpersand, GetProvenance(p),
"missing ! before comment after &"_warn_en_US);
}
}
do {
Expand Down
8 changes: 8 additions & 0 deletions flang/lib/Parser/unparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2067,6 +2067,12 @@ class UnparseVisitor {
},
x.u);
}
void Unparse(const OmpLastprivateClause &x) {
Walk(
std::get<std::optional<OmpLastprivateClause::LastprivateModifier>>(x.t),
":");
Walk(std::get<OmpObjectList>(x.t));
}
void Unparse(const OmpMapType::Always &) { Word("ALWAYS,"); }
void Unparse(const OmpMapClause &x) {
Walk(std::get<std::optional<OmpMapType>>(x.t), ":");
Expand Down Expand Up @@ -2764,6 +2770,8 @@ class UnparseVisitor {
WALK_NESTED_ENUM(OmpDefaultClause, Type) // OMP DEFAULT
WALK_NESTED_ENUM(OmpDefaultmapClause, ImplicitBehavior) // OMP DEFAULTMAP
WALK_NESTED_ENUM(OmpDefaultmapClause, VariableCategory) // OMP DEFAULTMAP
WALK_NESTED_ENUM(
OmpLastprivateClause, LastprivateModifier) // OMP lastprivate-modifier
WALK_NESTED_ENUM(OmpScheduleModifierType, ModType) // OMP schedule-modifier
WALK_NESTED_ENUM(OmpLinearModifier, Type) // OMP linear-modifier
WALK_NESTED_ENUM(OmpDependenceType, Type) // OMP dependence-type
Expand Down
28 changes: 10 additions & 18 deletions flang/lib/Semantics/check-acc-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,16 +409,12 @@ void AccStructureChecker::CheckMultipleOccurrenceInDeclare(
if (const auto *name = getDesignatorNameIfDataRef(designator)) {
if (declareSymbols.contains(&name->symbol->GetUltimate())) {
if (declareSymbols[&name->symbol->GetUltimate()] == clause) {
if (context_.languageFeatures().ShouldWarn(
common::UsageWarning::OpenAccUsage)) {
context_.Say(GetContext().clauseSource,
"'%s' in the %s clause is already present in the "
"same "
"clause in this module"_warn_en_US,
name->symbol->name(),
parser::ToUpperCaseLetters(
llvm::acc::getOpenACCClauseName(clause).str()));
}
context_.Warn(common::UsageWarning::OpenAccUsage,
GetContext().clauseSource,
"'%s' in the %s clause is already present in the same clause in this module"_warn_en_US,
name->symbol->name(),
parser::ToUpperCaseLetters(
llvm::acc::getOpenACCClauseName(clause).str()));
} else {
context_.Say(GetContext().clauseSource,
"'%s' in the %s clause is already present in another "
Expand Down Expand Up @@ -770,10 +766,8 @@ void AccStructureChecker::Enter(const parser::AccClause::Link &x) {
}

void AccStructureChecker::Enter(const parser::AccClause::Shortloop &x) {
if (CheckAllowed(llvm::acc::Clause::ACCC_shortloop) &&
context_.languageFeatures().ShouldWarn(
common::UsageWarning::OpenAccUsage)) {
context_.Say(GetContext().clauseSource,
if (CheckAllowed(llvm::acc::Clause::ACCC_shortloop)) {
context_.Warn(common::UsageWarning::OpenAccUsage, GetContext().clauseSource,
"Non-standard shortloop clause ignored"_warn_en_US);
}
}
Expand All @@ -793,10 +787,8 @@ void AccStructureChecker::Enter(const parser::AccClause::If &x) {
}

void AccStructureChecker::Enter(const parser::OpenACCEndConstruct &x) {
if (context_.languageFeatures().ShouldWarn(
common::UsageWarning::OpenAccUsage)) {
context_.Say(x.source, "Misplaced OpenACC end directive"_warn_en_US);
}
context_.Warn(common::UsageWarning::OpenAccUsage, x.source,
"Misplaced OpenACC end directive"_warn_en_US);
}

void AccStructureChecker::Enter(const parser::Module &) {
Expand Down
6 changes: 2 additions & 4 deletions flang/lib/Semantics/check-allocate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,10 +531,8 @@ bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) {
// Character length distinction is allowed, with a warning
if (!HaveCompatibleLengths(
*type_, allocateInfo_.sourceExprType.value())) { // F'2023 C950
if (context.ShouldWarn(common::LanguageFeature::AllocateToOtherLength)) {
context.Say(name_.source,
"Character length of allocatable object in ALLOCATE should be the same as the SOURCE or MOLD"_port_en_US);
}
context.Warn(common::LanguageFeature::AllocateToOtherLength, name_.source,
"Character length of allocatable object in ALLOCATE should be the same as the SOURCE or MOLD"_port_en_US);
return false;
}
}
Expand Down
215 changes: 123 additions & 92 deletions flang/lib/Semantics/check-call.cpp

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions flang/lib/Semantics/check-call.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ bool CheckArguments(const evaluate::characteristics::Procedure &,
bool CheckPPCIntrinsic(const Symbol &generic, const Symbol &specific,
const evaluate::ActualArguments &actuals,
evaluate::FoldingContext &context);
bool CheckWindowsIntrinsic(
const Symbol &intrinsic, evaluate::FoldingContext &context);
bool CheckArgumentIsConstantExprInRange(
const evaluate::ActualArguments &actuals, int index, int lowerBound,
int upperBound, parser::ContextualMessages &messages);
Expand Down
14 changes: 5 additions & 9 deletions flang/lib/Semantics/check-case.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,8 @@ template <typename T> class CaseValues {
for (const auto &range : ranges) {
auto pair{ComputeBounds(range)};
if (pair.first && pair.second && *pair.first > *pair.second) {
if (context_.ShouldWarn(common::UsageWarning::EmptyCase)) {
context_.Say(stmt.source,
"CASE has lower bound greater than upper bound"_warn_en_US);
}
context_.Warn(common::UsageWarning::EmptyCase, stmt.source,
"CASE has lower bound greater than upper bound"_warn_en_US);
} else {
if constexpr (T::category == TypeCategory::Logical) { // C1148
if ((pair.first || pair.second) &&
Expand Down Expand Up @@ -95,11 +93,9 @@ template <typename T> class CaseValues {
x->v = converted;
return value;
} else {
if (context_.ShouldWarn(common::UsageWarning::CaseOverflow)) {
context_.Say(expr.source,
"CASE value (%s) overflows type (%s) of SELECT CASE expression"_warn_en_US,
folded.AsFortran(), caseExprType_.AsFortran());
}
context_.Warn(common::UsageWarning::CaseOverflow, expr.source,
"CASE value (%s) overflows type (%s) of SELECT CASE expression"_warn_en_US,
folded.AsFortran(), caseExprType_.AsFortran());
hasErrors_ = true;
return std::nullopt;
}
Expand Down
6 changes: 2 additions & 4 deletions flang/lib/Semantics/check-cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,8 @@ template <bool IsCUFKernelDo> class DeviceContextChecker {
return false;
}
void WarnOnIoStmt(const parser::CharBlock &source) {
if (context_.ShouldWarn(common::UsageWarning::CUDAUsage)) {
context_.Say(
source, "I/O statement might not be supported on device"_warn_en_US);
}
context_.Warn(common::UsageWarning::CUDAUsage, source,
"I/O statement might not be supported on device"_warn_en_US);
}
template <typename A>
void WarnIfNotInternal(const A &stmt, const parser::CharBlock &source) {
Expand Down
10 changes: 4 additions & 6 deletions flang/lib/Semantics/check-data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,8 @@ class DataVarChecker : public evaluate::AllTraverse<DataVarChecker, true> {
"Procedure pointer '%s' may not appear in a DATA statement"_err_en_US,
symbol.name());
return false;
} else if (context_.ShouldWarn(
common::LanguageFeature::DataStmtExtensions)) {
context_.Say(source_,
} else {
context_.Warn(common::LanguageFeature::DataStmtExtensions, source_,
"Procedure pointer '%s' in a DATA statement is not standard"_port_en_US,
symbol.name());
}
Expand All @@ -102,9 +101,8 @@ class DataVarChecker : public evaluate::AllTraverse<DataVarChecker, true> {
"Blank COMMON object '%s' may not appear in a DATA statement"_err_en_US,
symbol.name());
return false;
} else if (context_.ShouldWarn(
common::LanguageFeature::DataStmtExtensions)) {
context_.Say(source_,
} else {
context_.Warn(common::LanguageFeature::DataStmtExtensions, source_,
"Blank COMMON object '%s' in a DATA statement is not standard"_port_en_US,
symbol.name());
}
Expand Down
359 changes: 155 additions & 204 deletions flang/lib/Semantics/check-declarations.cpp

Large diffs are not rendered by default.

23 changes: 10 additions & 13 deletions flang/lib/Semantics/check-directive-structure.h
Original file line number Diff line number Diff line change
Expand Up @@ -463,12 +463,11 @@ void DirectiveStructureChecker<D, C, PC,
}
// No clause matched in the actual clauses list
if (warnInsteadOfError) {
if (context_.ShouldWarn(common::UsageWarning::Portability)) {
context_.Say(GetContext().directiveSource,
"At least one of %s clause should appear on the %s directive"_port_en_US,
ClauseSetToString(GetContext().requiredClauses),
ContextDirectiveAsFortran());
}
context_.Warn(common::UsageWarning::Portability,
GetContext().directiveSource,
"At least one of %s clause should appear on the %s directive"_port_en_US,
ClauseSetToString(GetContext().requiredClauses),
ContextDirectiveAsFortran());
} else {
context_.Say(GetContext().directiveSource,
"At least one of %s clause must appear on the %s directive"_err_en_US,
Expand All @@ -493,13 +492,11 @@ bool DirectiveStructureChecker<D, C, PC, ClauseEnumSize>::CheckAllowed(
!GetContext().allowedExclusiveClauses.test(clause) &&
!GetContext().requiredClauses.test(clause)) {
if (warnInsteadOfError) {
if (context_.ShouldWarn(common::UsageWarning::Portability)) {
context_.Say(GetContext().clauseSource,
"%s clause is not allowed on the %s directive and will be ignored"_port_en_US,
parser::ToUpperCaseLetters(getClauseName(clause).str()),
parser::ToUpperCaseLetters(
GetContext().directiveSource.ToString()));
}
context_.Warn(common::UsageWarning::Portability,
GetContext().clauseSource,
"%s clause is not allowed on the %s directive and will be ignored"_port_en_US,
parser::ToUpperCaseLetters(getClauseName(clause).str()),
parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
} else {
context_.Say(GetContext().clauseSource,
"%s clause is not allowed on the %s directive"_err_en_US,
Expand Down
26 changes: 11 additions & 15 deletions flang/lib/Semantics/check-do-forall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,10 +495,8 @@ class DoContext {

void CheckDoControl(const parser::CharBlock &sourceLocation, bool isReal) {
if (isReal) {
if (context_.ShouldWarn(common::LanguageFeature::RealDoControls)) {
context_.Say(
sourceLocation, "DO controls should be INTEGER"_port_en_US);
}
context_.Warn(common::LanguageFeature::RealDoControls, sourceLocation,
"DO controls should be INTEGER"_port_en_US);
} else {
SayBadDoControl(sourceLocation);
}
Expand Down Expand Up @@ -552,9 +550,9 @@ class DoContext {
CheckDoExpression(bounds.upper);
if (bounds.step) {
CheckDoExpression(*bounds.step);
if (IsZero(*bounds.step) &&
context_.ShouldWarn(common::UsageWarning::ZeroDoStep)) {
context_.Say(bounds.step->thing.value().source,
if (IsZero(*bounds.step)) {
context_.Warn(common::UsageWarning::ZeroDoStep,
bounds.step->thing.value().source,
"DO step expression should not be zero"_warn_en_US);
}
}
Expand Down Expand Up @@ -679,10 +677,9 @@ class DoContext {
if (std::holds_alternative<parser::LocalitySpec::DefaultNone>(ls.u)) {
if (hasDefaultNone) {
// F'2023 C1129, you can only have one DEFAULT(NONE)
if (context_.ShouldWarn(common::LanguageFeature::BenignRedundancy)) {
context_.Say(currentStatementSourcePosition_,
"Only one DEFAULT(NONE) may appear"_port_en_US);
}
context_.Warn(common::LanguageFeature::BenignRedundancy,
currentStatementSourcePosition_,
"Only one DEFAULT(NONE) may appear"_port_en_US);
break;
}
hasDefaultNone = true;
Expand Down Expand Up @@ -890,10 +887,9 @@ class DoContext {
},
assignment.u);
for (const Symbol &index : indexVars) {
if (symbols.count(index) == 0 &&
context_.ShouldWarn(common::UsageWarning::UnusedForallIndex)) {
context_.Say("FORALL index variable '%s' not used on left-hand side"
" of assignment"_warn_en_US,
if (symbols.count(index) == 0) {
context_.Warn(common::UsageWarning::UnusedForallIndex,
"FORALL index variable '%s' not used on left-hand side of assignment"_warn_en_US,
index.name());
}
}
Expand Down
19 changes: 7 additions & 12 deletions flang/lib/Semantics/check-io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ void IoChecker::Enter(const parser::Format &spec) {
if (!IsVariable(*expr)) {
context_.Say(format.source,
"Assigned format label must be a scalar variable"_err_en_US);
} else if (context_.ShouldWarn(common::LanguageFeature::Assign)) {
context_.Say(format.source,
} else {
context_.Warn(common::LanguageFeature::Assign, format.source,
"Assigned format labels are deprecated"_port_en_US);
}
return;
Expand All @@ -245,11 +245,9 @@ void IoChecker::Enter(const parser::Format &spec) {
common::LanguageFeature::NonCharacterFormat)) {
// Legacy extension: using non-character variables, typically
// DATA-initialized with Hollerith, as format expressions.
if (context_.ShouldWarn(
common::LanguageFeature::NonCharacterFormat)) {
context_.Say(format.source,
"Non-character format expression is not standard"_port_en_US);
}
context_.Warn(common::LanguageFeature::NonCharacterFormat,
format.source,
"Non-character format expression is not standard"_port_en_US);
} else if (!type ||
type->kind() !=
context_.defaultKinds().GetDefaultKind(type->category())) {
Expand Down Expand Up @@ -936,11 +934,8 @@ void IoChecker::CheckStringValue(IoSpecKind specKind, const std::string &value,
auto upper{Normalize(value)};
if (specValues.at(specKind).count(upper) == 0) {
if (specKind == IoSpecKind::Access && upper == "APPEND") {
if (context_.ShouldWarn(common::LanguageFeature::OpenAccessAppend)) {
context_.Say(source,
"ACCESS='%s' interpreted as POSITION='%s'"_port_en_US, value,
upper);
}
context_.Warn(common::LanguageFeature::OpenAccessAppend, source,
"ACCESS='%s' interpreted as POSITION='%s'"_port_en_US, value, upper);
} else {
context_.Say(source, "Invalid %s value '%s'"_err_en_US,
parser::ToUpperCaseLetters(common::EnumToString(specKind)), value);
Expand Down
99 changes: 53 additions & 46 deletions flang/lib/Semantics/check-omp-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,11 +666,10 @@ void OmpStructureChecker::CheckTargetNest(const parser::OpenMPConstruct &c) {
[&](const auto &c) {},
},
c.u);
if (!eligibleTarget &&
context_.ShouldWarn(common::UsageWarning::Portability)) {
context_.Say(parser::FindSourceLocation(c),
"If %s directive is nested inside TARGET region, the behaviour "
"is unspecified"_port_en_US,
if (!eligibleTarget) {
context_.Warn(common::UsageWarning::Portability,
parser::FindSourceLocation(c),
"If %s directive is nested inside TARGET region, the behaviour is unspecified"_port_en_US,
parser::ToUpperCaseLetters(
getDirectiveName(ineligibleTargetDir).str()));
}
Expand Down Expand Up @@ -1077,12 +1076,10 @@ void OmpStructureChecker::CheckThreadprivateOrDeclareTargetVar(
ContextDirectiveAsFortran());
else if (GetContext().directive ==
llvm::omp::Directive::OMPD_declare_target)
if (context_.ShouldWarn(
common::UsageWarning::OpenMPUsage)) {
context_.Say(name->source,
"The entity with PARAMETER attribute is used in a %s directive"_warn_en_US,
ContextDirectiveAsFortran());
}
context_.Warn(common::UsageWarning::OpenMPUsage,
name->source,
"The entity with PARAMETER attribute is used in a %s directive"_warn_en_US,
ContextDirectiveAsFortran());
} else if (FindCommonBlockContaining(*name->symbol)) {
context_.Say(name->source,
"A variable in a %s directive cannot be an element of a "
Expand Down Expand Up @@ -1249,8 +1246,8 @@ void OmpStructureChecker::Leave(const parser::OmpDeclareTargetWithClause &x) {
context_.Say(x.source,
"If the DECLARE TARGET directive has a clause, it must contain at least one ENTER clause or LINK clause"_err_en_US);
}
if (toClause && context_.ShouldWarn(common::UsageWarning::OpenMPUsage)) {
context_.Say(toClause->source,
if (toClause) {
context_.Warn(common::UsageWarning::OpenMPUsage, toClause->source,
"The usage of TO clause on DECLARE TARGET directive has been deprecated. Use ENTER clause instead."_warn_en_US);
}
}
Expand Down Expand Up @@ -3143,9 +3140,8 @@ void OmpStructureChecker::CheckCopyingPolymorphicAllocatable(
const auto *symbol{it->first};
const auto source{it->second};
if (IsPolymorphicAllocatable(*symbol)) {
context_.Say(source,
"If a polymorphic variable with allocatable attribute '%s' is in "
"%s clause, the behavior is unspecified"_port_en_US,
context_.Warn(common::UsageWarning::Portability, source,
"If a polymorphic variable with allocatable attribute '%s' is in %s clause, the behavior is unspecified"_port_en_US,
symbol->name(),
parser::ToUpperCaseLetters(getClauseName(clause).str()));
}
Expand Down Expand Up @@ -3174,11 +3170,13 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) {
void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_lastprivate);

CheckIsVarPartOfAnotherVar(GetContext().clauseSource, x.v, "LASTPRIVATE");
const auto &objectList{std::get<parser::OmpObjectList>(x.v.t)};
CheckIsVarPartOfAnotherVar(
GetContext().clauseSource, objectList, "LASTPRIVATE");

DirectivesClauseTriple dirClauseTriple;
SymbolSourceMap currSymbols;
GetSymbolsInObjectList(x.v, currSymbols);
GetSymbolsInObjectList(objectList, currSymbols);
CheckDefinableObjects(currSymbols, GetClauseKindForParserClass(x));
CheckCopyingPolymorphicAllocatable(
currSymbols, llvm::omp::Clause::OMPC_lastprivate);
Expand All @@ -3193,6 +3191,21 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) {

CheckPrivateSymbolsInOuterCxt(
currSymbols, dirClauseTriple, GetClauseKindForParserClass(x));

using LastprivateModifier = parser::OmpLastprivateClause::LastprivateModifier;
const auto &maybeMod{std::get<std::optional<LastprivateModifier>>(x.v.t)};
if (maybeMod) {
unsigned version{context_.langOptions().OpenMPVersion};
unsigned allowedInVersion = 50;
if (version < allowedInVersion) {
std::string thisVersion{
std::to_string(version / 10) + "." + std::to_string(version % 10)};
context_.Say(GetContext().clauseSource,
"LASTPRIVATE clause with CONDITIONAL modifier is not "
"allowed in OpenMP v%s, try -fopenmp-version=%d"_err_en_US,
thisVersion, allowedInVersion);
}
}
}

void OmpStructureChecker::Enter(const parser::OmpClause::Copyin &x) {
Expand Down Expand Up @@ -3246,11 +3259,10 @@ void OmpStructureChecker::Enter(const parser::OmpClause::UseDevicePtr &x) {
if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
if (name->symbol) {
if (!(IsBuiltinCPtr(*(name->symbol)))) {
if (context_.ShouldWarn(common::UsageWarning::OpenMPUsage)) {
context_.Say(itr->second->source,
"Use of non-C_PTR type '%s' in USE_DEVICE_PTR is deprecated, use USE_DEVICE_ADDR instead"_warn_en_US,
name->ToString());
}
context_.Warn(common::UsageWarning::OpenMPUsage,
itr->second->source,
"Use of non-C_PTR type '%s' in USE_DEVICE_PTR is deprecated, use USE_DEVICE_ADDR instead"_warn_en_US,
name->ToString());
} else {
useDevicePtrNameList.push_back(*name);
}
Expand Down Expand Up @@ -3307,20 +3319,16 @@ void OmpStructureChecker::Enter(const parser::OmpClause::IsDevicePtr &x) {
"Variable '%s' in IS_DEVICE_PTR clause must be of type C_PTR"_err_en_US,
source.ToString());
} else if (!(IsDummy(*symbol))) {
if (context_.ShouldWarn(common::UsageWarning::OpenMPUsage)) {
context_.Say(itr->second->source,
"Variable '%s' in IS_DEVICE_PTR clause must be a dummy argument. "
"This semantic check is deprecated from OpenMP 5.2 and later."_warn_en_US,
source.ToString());
}
context_.Warn(common::UsageWarning::OpenMPUsage, itr->second->source,
"Variable '%s' in IS_DEVICE_PTR clause must be a dummy argument. "
"This semantic check is deprecated from OpenMP 5.2 and later."_warn_en_US,
source.ToString());
} else if (IsAllocatableOrPointer(*symbol) || IsValue(*symbol)) {
if (context_.ShouldWarn(common::UsageWarning::OpenMPUsage)) {
context_.Say(itr->second->source,
"Variable '%s' in IS_DEVICE_PTR clause must be a dummy argument "
"that does not have the ALLOCATABLE, POINTER or VALUE attribute. "
"This semantic check is deprecated from OpenMP 5.2 and later."_warn_en_US,
source.ToString());
}
context_.Warn(common::UsageWarning::OpenMPUsage, itr->second->source,
"Variable '%s' in IS_DEVICE_PTR clause must be a dummy argument "
"that does not have the ALLOCATABLE, POINTER or VALUE attribute. "
"This semantic check is deprecated from OpenMP 5.2 and later."_warn_en_US,
source.ToString());
}
}
}
Expand Down Expand Up @@ -3617,18 +3625,17 @@ const parser::OmpObjectList *OmpStructureChecker::GetOmpObjectList(
const parser::OmpClause &clause) {

// Clauses with OmpObjectList as its data member
using MemberObjectListClauses =
std::tuple<parser::OmpClause::Copyprivate, parser::OmpClause::Copyin,
parser::OmpClause::Firstprivate, parser::OmpClause::From,
parser::OmpClause::Lastprivate, parser::OmpClause::Link,
parser::OmpClause::Private, parser::OmpClause::Shared,
parser::OmpClause::To, parser::OmpClause::Enter,
parser::OmpClause::UseDevicePtr, parser::OmpClause::UseDeviceAddr>;
using MemberObjectListClauses = std::tuple<parser::OmpClause::Copyprivate,
parser::OmpClause::Copyin, parser::OmpClause::Firstprivate,
parser::OmpClause::From, parser::OmpClause::Link,
parser::OmpClause::Private, parser::OmpClause::Shared,
parser::OmpClause::To, parser::OmpClause::Enter,
parser::OmpClause::UseDevicePtr, parser::OmpClause::UseDeviceAddr>;

// Clauses with OmpObjectList in the tuple
using TupleObjectListClauses =
std::tuple<parser::OmpClause::Allocate, parser::OmpClause::Map,
parser::OmpClause::Reduction, parser::OmpClause::Aligned>;
using TupleObjectListClauses = std::tuple<parser::OmpClause::Allocate,
parser::OmpClause::Lastprivate, parser::OmpClause::Map,
parser::OmpClause::Reduction, parser::OmpClause::Aligned>;

// TODO:: Generate the tuples using TableGen.
// Handle other constructs with OmpObjectList such as OpenMPThreadprivate.
Expand Down
6 changes: 3 additions & 3 deletions flang/lib/Semantics/check-return.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ void ReturnStmtChecker::Leave(const parser::ReturnStmt &returnStmt) {
IsFunction(*subprogramScope->GetSymbol()))) {
context_.Say(
"RETURN with expression is only allowed in SUBROUTINE subprogram"_err_en_US);
} else if (subprogramScope->kind() == Scope::Kind::MainProgram &&
context_.ShouldWarn(common::LanguageFeature::ProgramReturn)) {
context_.Say("RETURN should not appear in a main program"_port_en_US);
} else if (subprogramScope->kind() == Scope::Kind::MainProgram) {
context_.Warn(common::LanguageFeature::ProgramReturn,
"RETURN should not appear in a main program"_port_en_US);
}
}
}
Expand Down
8 changes: 3 additions & 5 deletions flang/lib/Semantics/compute-offsets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,9 @@ void ComputeOffsetsHelper::DoCommonBlock(Symbol &commonBlock) {
auto errorSite{
commonBlock.name().empty() ? symbol.name() : commonBlock.name()};
if (std::size_t padding{DoSymbol(symbol.GetUltimate())}) {
if (context_.ShouldWarn(common::UsageWarning::CommonBlockPadding)) {
context_.Say(errorSite,
"COMMON block /%s/ requires %zd bytes of padding before '%s' for alignment"_port_en_US,
commonBlock.name(), padding, symbol.name());
}
context_.Warn(common::UsageWarning::CommonBlockPadding, errorSite,
"COMMON block /%s/ requires %zd bytes of padding before '%s' for alignment"_port_en_US,
commonBlock.name(), padding, symbol.name());
}
previous.emplace(symbol);
auto eqIter{equivalenceBlock_.end()};
Expand Down
34 changes: 12 additions & 22 deletions flang/lib/Semantics/data-to-inits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,12 +298,10 @@ DataInitializationCompiler<DSV>::ConvertElement(
if (context.IsEnabled(common::LanguageFeature::LogicalIntegerAssignment)) {
if (MaybeExpr converted{evaluate::DataConstantConversionExtension(
exprAnalyzer_.GetFoldingContext(), type, expr)}) {
if (context.ShouldWarn(
common::LanguageFeature::LogicalIntegerAssignment)) {
context.Say(
"nonstandard usage: initialization of %s with %s"_port_en_US,
type.AsFortran(), expr.GetType().value().AsFortran());
}
context.Warn(common::LanguageFeature::LogicalIntegerAssignment,
exprAnalyzer_.GetFoldingContext().messages().at(),
"nonstandard usage: initialization of %s with %s"_port_en_US,
type.AsFortran(), expr.GetType().value().AsFortran());
return {std::make_pair(std::move(*converted), false)};
}
}
Expand Down Expand Up @@ -434,16 +432,11 @@ bool DataInitializationCompiler<DSV>::InitElement(
// value non-pointer initialization
if (IsBOZLiteral(*expr) &&
designatorType->category() != TypeCategory::Integer) { // 8.6.7(11)
if (exprAnalyzer_.context().ShouldWarn(
common::LanguageFeature::DataStmtExtensions)) {
exprAnalyzer_.Say(
"BOZ literal should appear in a DATA statement only as a value for an integer object, but '%s' is '%s'"_port_en_US,
DescribeElement(), designatorType->AsFortran());
}
} else if (converted->second &&
exprAnalyzer_.context().ShouldWarn(
common::LanguageFeature::DataStmtExtensions)) {
exprAnalyzer_.context().Say(
exprAnalyzer_.Warn(common::LanguageFeature::DataStmtExtensions,
"BOZ literal should appear in a DATA statement only as a value for an integer object, but '%s' is '%s'"_port_en_US,
DescribeElement(), designatorType->AsFortran());
} else if (converted->second) {
exprAnalyzer_.Warn(common::LanguageFeature::DataStmtExtensions,
"DATA statement value initializes '%s' of type '%s' with CHARACTER"_port_en_US,
DescribeElement(), designatorType->AsFortran());
}
Expand All @@ -462,12 +455,9 @@ bool DataInitializationCompiler<DSV>::InitElement(
} else if (status == evaluate::InitialImage::OutOfRange) {
OutOfRangeError();
} else if (status == evaluate::InitialImage::LengthMismatch) {
if (exprAnalyzer_.context().ShouldWarn(
common::UsageWarning::DataLength)) {
exprAnalyzer_.Say(
"DATA statement value '%s' for '%s' has the wrong length"_warn_en_US,
folded.AsFortran(), DescribeElement());
}
exprAnalyzer_.Warn(common::UsageWarning::DataLength,
"DATA statement value '%s' for '%s' has the wrong length"_warn_en_US,
folded.AsFortran(), DescribeElement());
return true;
} else if (status == evaluate::InitialImage::TooManyElems) {
exprAnalyzer_.Say("DATA statement has too many elements"_err_en_US);
Expand Down
3 changes: 2 additions & 1 deletion flang/lib/Semantics/definable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,8 @@ std::optional<parser::Message> WhyNotDefinable(parser::CharBlock at,
if (!portabilityWarning &&
scope.context().languageFeatures().ShouldWarn(
common::UsageWarning::VectorSubscriptFinalization)) {
portabilityWarning = parser::Message{at,
portabilityWarning = parser::Message{
common::UsageWarning::VectorSubscriptFinalization, at,
"Variable '%s' has a vector subscript and will be finalized by non-elemental subroutine '%s'"_port_en_US,
expr.AsFortran(), anyRankMatch->name()};
}
Expand Down
150 changes: 62 additions & 88 deletions flang/lib/Semantics/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,10 +663,8 @@ struct IntTypeVisitor {
auto unsignedNum{Int::Read(p, 10, false /*unsigned*/)};
num.value = unsignedNum.value.Negate().value;
num.overflow = unsignedNum.overflow || num.value > Int{0};
if (!num.overflow && num.value.Negate().overflow &&
analyzer.context().ShouldWarn(LanguageFeature::BigIntLiterals) &&
!analyzer.context().IsInModuleFile(digits)) {
analyzer.Say(digits,
if (!num.overflow && num.value.Negate().overflow) {
analyzer.Warn(LanguageFeature::BigIntLiterals, digits,
"negated maximum INTEGER(KIND=%d) literal"_port_en_US, T::kind);
}
} else {
Expand All @@ -677,9 +675,8 @@ struct IntTypeVisitor {
if (!isDefaultKind ||
!analyzer.context().IsEnabled(LanguageFeature::BigIntLiterals)) {
return std::nullopt;
} else if (analyzer.context().ShouldWarn(
LanguageFeature::BigIntLiterals)) {
analyzer.Say(digits,
} else {
analyzer.Warn(LanguageFeature::BigIntLiterals, digits,
"Integer literal is too large for default INTEGER(KIND=%d); "
"assuming INTEGER(KIND=%d)"_port_en_US,
kind, T::kind);
Expand Down Expand Up @@ -809,16 +806,12 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::RealLiteralConstant &x) {
auto kind{AnalyzeKindParam(x.kind, defaultKind)};
if (letterKind && expoLetter != 'e') {
if (kind != *letterKind) {
if (context_.ShouldWarn(
common::LanguageFeature::ExponentMatchingKindParam)) {
Say("Explicit kind parameter on real constant disagrees with exponent letter '%c'"_warn_en_US,
expoLetter);
}
} else if (x.kind &&
context_.ShouldWarn(
common::LanguageFeature::ExponentMatchingKindParam)) {
Say("Explicit kind parameter together with non-'E' exponent letter "
"is not standard"_port_en_US);
Warn(common::LanguageFeature::ExponentMatchingKindParam,
"Explicit kind parameter on real constant disagrees with exponent letter '%c'"_warn_en_US,
expoLetter);
} else if (x.kind) {
Warn(common::LanguageFeature::ExponentMatchingKindParam,
"Explicit kind parameter together with non-'E' exponent letter is not standard"_port_en_US);
}
}
auto result{common::SearchTypes(
Expand Down Expand Up @@ -1657,11 +1650,8 @@ void ArrayConstructorContext::Push(MaybeExpr &&x) {
if (!type_) {
if (auto *boz{std::get_if<BOZLiteralConstant>(&x->u)}) {
// Treat an array constructor of BOZ as if default integer.
if (exprAnalyzer_.context().ShouldWarn(
common::LanguageFeature::BOZAsDefaultInteger)) {
exprAnalyzer_.Say(
"BOZ literal in array constructor without explicit type is assumed to be default INTEGER"_port_en_US);
}
exprAnalyzer_.Warn(common::LanguageFeature::BOZAsDefaultInteger,
"BOZ literal in array constructor without explicit type is assumed to be default INTEGER"_port_en_US);
x = AsGenericExpr(ConvertToKind<TypeCategory::Integer>(
exprAnalyzer_.GetDefaultKind(TypeCategory::Integer),
std::move(*boz)));
Expand All @@ -1672,11 +1662,8 @@ void ArrayConstructorContext::Push(MaybeExpr &&x) {
if (auto *boz{std::get_if<BOZLiteralConstant>(&x->u)}) {
if (!type_) {
// Treat an array constructor of BOZ as if default integer.
if (exprAnalyzer_.context().ShouldWarn(
common::LanguageFeature::BOZAsDefaultInteger)) {
exprAnalyzer_.Say(
"BOZ literal in array constructor without explicit type is assumed to be default INTEGER"_port_en_US);
}
exprAnalyzer_.Warn(common::LanguageFeature::BOZAsDefaultInteger,
"BOZ literal in array constructor without explicit type is assumed to be default INTEGER"_port_en_US);
x = AsGenericExpr(ConvertToKind<TypeCategory::Integer>(
exprAnalyzer_.GetDefaultKind(TypeCategory::Integer),
std::move(*boz)));
Expand Down Expand Up @@ -1740,15 +1727,12 @@ void ArrayConstructorContext::Push(MaybeExpr &&x) {
auto xLen{xType.LEN()};
if (auto thisLen{ToInt64(xLen)}) {
if (constantLength_) {
if (exprAnalyzer_.context().ShouldWarn(
common::LanguageFeature::DistinctArrayConstructorLengths) &&
*thisLen != *constantLength_) {
if (!(messageDisplayedSet_ & 1)) {
exprAnalyzer_.Say(
"Character literal in array constructor without explicit "
"type has different length than earlier elements"_port_en_US);
messageDisplayedSet_ |= 1;
}
if (*thisLen != *constantLength_ && !(messageDisplayedSet_ & 1)) {
exprAnalyzer_.Warn(
common::LanguageFeature::DistinctArrayConstructorLengths,
"Character literal in array constructor without explicit "
"type has different length than earlier elements"_port_en_US);
messageDisplayedSet_ |= 1;
}
if (*thisLen > *constantLength_) {
// Language extension: use the longest literal to determine the
Expand Down Expand Up @@ -2091,11 +2075,9 @@ MaybeExpr ExpressionAnalyzer::Analyze(
valueType->IsEquivalentTo(*parentType)) {
symbol = &*parent;
nextAnonymous = ++parent;
if (context().ShouldWarn(LanguageFeature::AnonymousParents)) {
Say(source,
"Whole parent component '%s' in structure constructor should not be anonymous"_port_en_US,
symbol->name());
}
Warn(LanguageFeature::AnonymousParents, source,
"Whole parent component '%s' in structure constructor should not be anonymous"_port_en_US,
symbol->name());
break;
}
}
Expand Down Expand Up @@ -2166,14 +2148,13 @@ MaybeExpr ExpressionAnalyzer::Analyze(
continue;
}
if (IsNullObjectPointer(*value)) {
if (context().ShouldWarn(common::LanguageFeature::
NullMoldAllocatableComponentValue)) {
AttachDeclaration(
Say(expr.source,
"NULL() with arguments is not standard conforming as the value for allocatable component '%s'"_port_en_US,
symbol->name()),
*symbol);
}
AttachDeclaration(
Warn(common::LanguageFeature::
NullMoldAllocatableComponentValue,
expr.source,
"NULL() with arguments is not standard conforming as the value for allocatable component '%s'"_port_en_US,
symbol->name()),
*symbol);
// proceed to check type & shape
} else {
AttachDeclaration(
Expand Down Expand Up @@ -2459,13 +2440,11 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
sym->attrs().test(semantics::Attr::NOPASS)) {
// F'2023 C1529 seems unnecessary and most compilers don't
// enforce it.
if (context().ShouldWarn(
common::LanguageFeature::NopassScalarBase)) {
AttachDeclaration(
Say(sc.component.source,
"Base of NOPASS type-bound procedure reference should be scalar"_port_en_US),
*sym);
}
AttachDeclaration(
Warn(common::LanguageFeature::NopassScalarBase,
sc.component.source,
"Base of NOPASS type-bound procedure reference should be scalar"_port_en_US),
*sym);
} else if (IsProcedurePointer(*sym)) { // C919
Say(sc.component.source,
"Base of procedure component reference must be scalar"_err_en_US);
Expand Down Expand Up @@ -2916,6 +2895,9 @@ auto ExpressionAnalyzer::GetCalleeAndArguments(const parser::Name &name,
} else {
resolution = symbol;
}
if (resolution && context_.targetCharacteristics().isOSWindows()) {
semantics::CheckWindowsIntrinsic(*resolution, GetFoldingContext());
}
if (!resolution || resolution->attrs().test(semantics::Attr::INTRINSIC)) {
auto name{resolution ? resolution->name() : ultimate.name()};
if (std::optional<SpecificCall> specificCall{context_.intrinsics().Probe(
Expand Down Expand Up @@ -2967,10 +2949,9 @@ void ExpressionAnalyzer::CheckBadExplicitType(
if (const auto *typeAndShape{result->GetTypeAndShape()}) {
if (auto declared{
typeAndShape->Characterize(intrinsic, GetFoldingContext())}) {
if (!declared->type().IsTkCompatibleWith(typeAndShape->type()) &&
context_.ShouldWarn(
common::UsageWarning::IgnoredIntrinsicFunctionType)) {
if (auto *msg{Say(
if (!declared->type().IsTkCompatibleWith(typeAndShape->type())) {
if (auto *msg{Warn(
common::UsageWarning::IgnoredIntrinsicFunctionType,
"The result type '%s' of the intrinsic function '%s' is not the explicit declared type '%s'"_warn_en_US,
typeAndShape->AsFortran(), intrinsic.name(),
declared->AsFortran())}) {
Expand Down Expand Up @@ -3342,10 +3323,10 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
iter != implicitInterfaces_.end()) {
std::string whyNot;
if (!chars->IsCompatibleWith(iter->second.second,
/*ignoreImplicitVsExplicit=*/false, &whyNot) &&
context_.ShouldWarn(
common::UsageWarning::IncompatibleImplicitInterfaces)) {
if (auto *msg{Say(callSite,
/*ignoreImplicitVsExplicit=*/false, &whyNot)) {
if (auto *msg{Warn(
common::UsageWarning::IncompatibleImplicitInterfaces,
callSite,
"Reference to the procedure '%s' has an implicit interface that is distinct from another reference: %s"_warn_en_US,
name, whyNot)}) {
msg->Attach(
Expand Down Expand Up @@ -3555,10 +3536,8 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Subtract &x) {

MaybeExpr ExpressionAnalyzer::Analyze(
const parser::Expr::ComplexConstructor &z) {
if (context_.ShouldWarn(common::LanguageFeature::ComplexConstructor)) {
context_.Say(
"nonstandard usage: generalized COMPLEX constructor"_port_en_US);
}
Warn(common::LanguageFeature::ComplexConstructor,
"nonstandard usage: generalized COMPLEX constructor"_port_en_US);
return AnalyzeComplex(Analyze(std::get<0>(z.t).value()),
Analyze(std::get<1>(z.t).value()), "complex constructor");
}
Expand Down Expand Up @@ -4037,11 +4016,9 @@ bool ExpressionAnalyzer::CheckIntrinsicKind(
return true;
} else if (foldingContext_.targetCharacteristics().CanSupportType(
category, kind)) {
if (context_.ShouldWarn(common::UsageWarning::BadTypeForTarget) &&
!context_.IsInModuleFile(GetContextualMessages().at())) {
Say("%s(KIND=%jd) is not an enabled type for this target"_warn_en_US,
ToUpperCase(EnumToString(category)), kind);
}
Warn(common::UsageWarning::BadTypeForTarget,
"%s(KIND=%jd) is not an enabled type for this target"_warn_en_US,
ToUpperCase(EnumToString(category)), kind);
return true;
} else {
Say("%s(KIND=%jd) is not a supported type"_err_en_US,
Expand All @@ -4067,10 +4044,9 @@ bool ExpressionAnalyzer::CheckIntrinsicSize(
return true;
} else if (foldingContext_.targetCharacteristics().CanSupportType(
category, kind)) {
if (context_.ShouldWarn(common::UsageWarning::BadTypeForTarget)) {
Say("%s*%jd is not an enabled type for this target"_warn_en_US,
ToUpperCase(EnumToString(category)), size);
}
Warn(common::UsageWarning::BadTypeForTarget,
"%s*%jd is not an enabled type for this target"_warn_en_US,
ToUpperCase(EnumToString(category)), size);
return true;
} else {
Say("%s*%jd is not a supported type"_err_en_US,
Expand Down Expand Up @@ -4174,13 +4150,13 @@ MaybeExpr ExpressionAnalyzer::MakeFunctionRef(

MaybeExpr ExpressionAnalyzer::AnalyzeComplex(
MaybeExpr &&re, MaybeExpr &&im, const char *what) {
if (context().ShouldWarn(common::LanguageFeature::ComplexConstructor)) {
if (re && re->Rank() > 0) {
Say("Real part of %s is not scalar"_port_en_US, what);
}
if (im && im->Rank() > 0) {
Say("Imaginary part of %s is not scalar"_port_en_US, what);
}
if (re && re->Rank() > 0) {
Warn(common::LanguageFeature::ComplexConstructor,
"Real part of %s is not scalar"_port_en_US, what);
}
if (im && im->Rank() > 0) {
Warn(common::LanguageFeature::ComplexConstructor,
"Imaginary part of %s is not scalar"_port_en_US, what);
}
if (re && im) {
ConformabilityCheck(GetContextualMessages(), *re, *im);
Expand Down Expand Up @@ -4591,10 +4567,8 @@ bool ArgumentAnalyzer::OkLogicalIntegerAssignment(
} else {
return false;
}
if (context_.context().ShouldWarn(
common::LanguageFeature::LogicalIntegerAssignment)) {
context_.Say(std::move(*msg));
}
context_.Warn(
common::LanguageFeature::LogicalIntegerAssignment, std::move(*msg));
return true;
}

Expand Down
6 changes: 4 additions & 2 deletions flang/lib/Semantics/mod-file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1482,14 +1482,16 @@ Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic,
if (!checkSum) {
if (context_.ShouldWarn(common::UsageWarning::ModuleFile)) {
Say(name, ancestorName, "File has invalid checksum: %s"_warn_en_US,
sourceFile->path());
sourceFile->path())
.set_usageWarning(common::UsageWarning::ModuleFile);
}
return nullptr;
} else if (requiredHash && *requiredHash != *checkSum) {
if (context_.ShouldWarn(common::UsageWarning::ModuleFile)) {
Say(name, ancestorName,
"File is not the right module file for %s"_warn_en_US,
"'"s + name.ToString() + "': "s + sourceFile->path());
"'"s + name.ToString() + "': "s + sourceFile->path())
.set_usageWarning(common::UsageWarning::ModuleFile);
}
return nullptr;
}
Expand Down
Loading