@@ -2891,7 +2891,8 @@ static bool CheckSymbolSupportsType(const Scope &scope,
2891
2891
2892
2892
static bool IsReductionAllowedForType (
2893
2893
const parser::OmpReductionIdentifier &ident, const DeclTypeSpec &type,
2894
- const Scope &scope, SemanticsContext &context) {
2894
+ bool cannotBeBuiltinReduction, const Scope &scope,
2895
+ SemanticsContext &context) {
2895
2896
auto isLogical{[](const DeclTypeSpec &type) -> bool {
2896
2897
return type.category () == DeclTypeSpec::Logical;
2897
2898
}};
@@ -2902,6 +2903,10 @@ static bool IsReductionAllowedForType(
2902
2903
auto checkOperator{[&](const parser::DefinedOperator &dOpr) {
2903
2904
if (const auto *intrinsicOp{
2904
2905
std::get_if<parser::DefinedOperator::IntrinsicOperator>(&dOpr.u )}) {
2906
+ if (cannotBeBuiltinReduction) {
2907
+ return false ;
2908
+ }
2909
+
2905
2910
// OMP5.2: The type [...] of a list item that appears in a
2906
2911
// reduction clause must be valid for the combiner expression
2907
2912
// See F2023: Table 10.2
@@ -2953,16 +2958,18 @@ static bool IsReductionAllowedForType(
2953
2958
// IAND: arguments must be integers: F2023 16.9.100
2954
2959
// IEOR: arguments must be integers: F2023 16.9.106
2955
2960
// IOR: arguments must be integers: F2023 16.9.111
2956
- if (type.IsNumeric (TypeCategory::Integer)) {
2961
+ if (type.IsNumeric (TypeCategory::Integer) &&
2962
+ !cannotBeBuiltinReduction) {
2957
2963
return true ;
2958
2964
}
2959
2965
} else if (realName == " max" || realName == " min" ) {
2960
2966
// MAX: arguments must be integer, real, or character:
2961
2967
// F2023 16.9.135
2962
2968
// MIN: arguments must be integer, real, or character:
2963
2969
// F2023 16.9.141
2964
- if (type.IsNumeric (TypeCategory::Integer) ||
2965
- type.IsNumeric (TypeCategory::Real) || isCharacter (type)) {
2970
+ if ((type.IsNumeric (TypeCategory::Integer) ||
2971
+ type.IsNumeric (TypeCategory::Real) || isCharacter (type)) &&
2972
+ !cannotBeBuiltinReduction) {
2966
2973
return true ;
2967
2974
}
2968
2975
}
@@ -2995,9 +3002,16 @@ void OmpStructureChecker::CheckReductionObjectTypes(
2995
3002
GetSymbolsInObjectList (objects, symbols);
2996
3003
2997
3004
for (auto &[symbol, source] : symbols) {
3005
+ // Built in reductions require types which can be used in their initializer
3006
+ // and combiner expressions. For example, for +:
3007
+ // r = 0; r = r + r2
3008
+ // But it might be valid to use these with DECLARE REDUCTION.
3009
+ // Assumed size is already caught elsewhere.
3010
+ bool cannotBeBuiltinReduction{evaluate::IsAssumedRank (*symbol)};
2998
3011
if (auto *type{symbol->GetType ()}) {
2999
3012
const auto &scope{context_.FindScope (symbol->name ())};
3000
- if (!IsReductionAllowedForType (ident, *type, scope, context_)) {
3013
+ if (!IsReductionAllowedForType (
3014
+ ident, *type, cannotBeBuiltinReduction, scope, context_)) {
3001
3015
context_.Say (source,
3002
3016
" The type of '%s' is incompatible with the reduction operator." _err_en_US,
3003
3017
symbol->name ());
0 commit comments