8
8
9
9
#include " check-omp-structure.h"
10
10
#include " definable.h"
11
+ #include " resolve-names-utils.h"
11
12
#include " flang/Evaluate/check-expression.h"
12
13
#include " flang/Evaluate/expression.h"
13
14
#include " flang/Evaluate/type.h"
@@ -3520,6 +3521,17 @@ bool OmpStructureChecker::CheckReductionOperator(
3520
3521
break ;
3521
3522
}
3522
3523
}
3524
+ // User-defined operators are OK if there has been a declared reduction
3525
+ // for that. We mangle those names to store the user details.
3526
+ if (const auto *definedOp{std::get_if<parser::DefinedOpName>(&dOpr.u )}) {
3527
+ std::string mangled{MangleDefinedOperator (definedOp->v .symbol ->name ())};
3528
+ const Scope &scope{definedOp->v .symbol ->owner ()};
3529
+ if (const Symbol *symbol{scope.FindSymbol (mangled)}) {
3530
+ if (symbol->detailsIf <UserReductionDetails>()) {
3531
+ return true ;
3532
+ }
3533
+ }
3534
+ }
3523
3535
context_.Say (source, " Invalid reduction operator in %s clause." _err_en_US,
3524
3536
parser::ToUpperCaseLetters (getClauseName (clauseId).str ()));
3525
3537
return false ;
@@ -3533,8 +3545,7 @@ bool OmpStructureChecker::CheckReductionOperator(
3533
3545
valid =
3534
3546
llvm::is_contained ({" max" , " min" , " iand" , " ior" , " ieor" }, realName);
3535
3547
if (!valid) {
3536
- auto *misc{name->symbol ->detailsIf <MiscDetails>()};
3537
- valid = misc && misc->kind () == MiscDetails::Kind::ConstructName;
3548
+ valid = name->symbol ->detailsIf <UserReductionDetails>();
3538
3549
}
3539
3550
}
3540
3551
if (!valid) {
@@ -3614,8 +3625,20 @@ void OmpStructureChecker::CheckReductionObjects(
3614
3625
}
3615
3626
}
3616
3627
3628
+ static bool CheckSymbolSupportsType (const Scope &scope,
3629
+ const parser::CharBlock &name, const DeclTypeSpec &type) {
3630
+ if (const auto *symbol{scope.FindSymbol (name)}) {
3631
+ if (const auto *reductionDetails{
3632
+ symbol->detailsIf <UserReductionDetails>()}) {
3633
+ return reductionDetails->SupportsType (type);
3634
+ }
3635
+ }
3636
+ return false ;
3637
+ }
3638
+
3617
3639
static bool IsReductionAllowedForType (
3618
- const parser::OmpReductionIdentifier &ident, const DeclTypeSpec &type) {
3640
+ const parser::OmpReductionIdentifier &ident, const DeclTypeSpec &type,
3641
+ const Scope &scope, SemanticsContext &context) {
3619
3642
auto isLogical{[](const DeclTypeSpec &type) -> bool {
3620
3643
return type.category () == DeclTypeSpec::Logical;
3621
3644
}};
@@ -3635,27 +3658,40 @@ static bool IsReductionAllowedForType(
3635
3658
case parser::DefinedOperator::IntrinsicOperator::Multiply:
3636
3659
case parser::DefinedOperator::IntrinsicOperator::Add:
3637
3660
case parser::DefinedOperator::IntrinsicOperator::Subtract:
3638
- return type.IsNumeric (TypeCategory::Integer) ||
3661
+ if ( type.IsNumeric (TypeCategory::Integer) ||
3639
3662
type.IsNumeric (TypeCategory::Real) ||
3640
- type.IsNumeric (TypeCategory::Complex);
3663
+ type.IsNumeric (TypeCategory::Complex))
3664
+ return true ;
3665
+ break ;
3641
3666
3642
3667
case parser::DefinedOperator::IntrinsicOperator::AND:
3643
3668
case parser::DefinedOperator::IntrinsicOperator::OR:
3644
3669
case parser::DefinedOperator::IntrinsicOperator::EQV:
3645
3670
case parser::DefinedOperator::IntrinsicOperator::NEQV:
3646
- return isLogical (type);
3671
+ if (isLogical (type)) {
3672
+ return true ;
3673
+ }
3674
+ break ;
3647
3675
3648
3676
// Reduction identifier is not in OMP5.2 Table 5.2
3649
3677
default :
3650
3678
DIE (" This should have been caught in CheckIntrinsicOperator" );
3651
3679
return false ;
3652
3680
}
3653
- }
3654
- return true ;
3681
+ parser::CharBlock name{MakeNameFromOperator (*intrinsicOp, context)};
3682
+ return CheckSymbolSupportsType (scope, name, type);
3683
+ } else if (const auto *definedOp{
3684
+ std::get_if<parser::DefinedOpName>(&dOpr.u )}) {
3685
+ return CheckSymbolSupportsType (
3686
+ scope, MangleDefinedOperator (definedOp->v .symbol ->name ()), type);
3687
+ }
3688
+ llvm_unreachable (
3689
+ " A DefinedOperator is either a DefinedOpName or an IntrinsicOperator" );
3655
3690
}};
3656
3691
3657
3692
auto checkDesignator{[&](const parser::ProcedureDesignator &procD) {
3658
3693
const parser::Name *name{std::get_if<parser::Name>(&procD.u )};
3694
+ CHECK (name && name->symbol );
3659
3695
if (name && name->symbol ) {
3660
3696
const SourceName &realName{name->symbol ->GetUltimate ().name ()};
3661
3697
// OMP5.2: The type [...] of a list item that appears in a
@@ -3664,18 +3700,35 @@ static bool IsReductionAllowedForType(
3664
3700
// IAND: arguments must be integers: F2023 16.9.100
3665
3701
// IEOR: arguments must be integers: F2023 16.9.106
3666
3702
// IOR: arguments must be integers: F2023 16.9.111
3667
- return type.IsNumeric (TypeCategory::Integer);
3703
+ if (type.IsNumeric (TypeCategory::Integer)) {
3704
+ return true ;
3705
+ }
3668
3706
} else if (realName == " max" || realName == " min" ) {
3669
3707
// MAX: arguments must be integer, real, or character:
3670
3708
// F2023 16.9.135
3671
3709
// MIN: arguments must be integer, real, or character:
3672
3710
// F2023 16.9.141
3673
- return type.IsNumeric (TypeCategory::Integer) ||
3674
- type.IsNumeric (TypeCategory::Real) || isCharacter (type);
3711
+ if (type.IsNumeric (TypeCategory::Integer) ||
3712
+ type.IsNumeric (TypeCategory::Real) || isCharacter (type)) {
3713
+ return true ;
3714
+ }
3675
3715
}
3716
+
3717
+ // If we get here, it may be a user declared reduction, so check
3718
+ // if the symbol has UserReductionDetails, and if so, the type is
3719
+ // supported.
3720
+ if (const auto *reductionDetails{
3721
+ name->symbol ->detailsIf <UserReductionDetails>()}) {
3722
+ return reductionDetails->SupportsType (type);
3723
+ }
3724
+
3725
+ // We also need to check for mangled names (max, min, iand, ieor and ior)
3726
+ // and then check if the type is there.
3727
+ parser::CharBlock mangledName{MangleSpecialFunctions (name->source )};
3728
+ return CheckSymbolSupportsType (scope, mangledName, type);
3676
3729
}
3677
- // TODO: user defined reduction operators. Just allow everything for now .
3678
- return true ;
3730
+ // Everything else is "not matching type" .
3731
+ return false ;
3679
3732
}};
3680
3733
3681
3734
return common::visit (
@@ -3690,7 +3743,8 @@ void OmpStructureChecker::CheckReductionObjectTypes(
3690
3743
3691
3744
for (auto &[symbol, source] : symbols) {
3692
3745
if (auto *type{symbol->GetType ()}) {
3693
- if (!IsReductionAllowedForType (ident, *type)) {
3746
+ const auto &scope{context_.FindScope (symbol->name ())};
3747
+ if (!IsReductionAllowedForType (ident, *type, scope, context_)) {
3694
3748
context_.Say (source,
3695
3749
" The type of '%s' is incompatible with the reduction operator." _err_en_US,
3696
3750
symbol->name ());
0 commit comments