diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -227,6 +227,10 @@ void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); void CheckDoWhile(const parser::OpenMPLoopConstruct &x); void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); + template + bool CheckOperatorValidity(const T &, const D &); + template void CheckAtomicConstructStructure(T &); + void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &); void CheckDistLinear(const parser::OpenMPLoopConstruct &x); void CheckSIMDNest(const parser::OpenMPConstruct &x); void CheckTargetNest(const parser::OpenMPConstruct &x); diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1202,11 +1202,83 @@ } } +template +bool OmpStructureChecker::CheckOperatorValidity( + const T &node, const D &variable) { + using AllowedBinaryOperators = + std::variant; + using BinaryOperators = std::variant; + + if constexpr (common::HasMember) { + const auto &variableName{variable.GetSource().ToString()}; + const auto &exprLeft{std::get<0>(node.t)}; + const auto &exprRight{std::get<1>(node.t)}; + if ((exprLeft.value().source.ToString() != variableName) && + (exprRight.value().source.ToString() != variableName)) { + context_.Say(variable.GetSource(), + "Variable name mismatch on lvalue and rvalue"_err_en_US); + } + + if constexpr (common::HasMember) { + return true; + } else { + return false; + } + } + return true; +} +template +void OmpStructureChecker::CheckAtomicConstructStructure(T &construct) { + const auto &dir{std::get(construct.t)}; + PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_atomic); + const auto &assignment{ + std::get>(construct.t) + .statement}; + const auto &expr{std::get(assignment.t)}; + const auto &var{std::get(assignment.t)}; + std::visit( + common::visitors{ + [&](const common::Indirection &x) { + const auto &procedureDesignator{ + std::get(x.value().v.t)}; + const parser::Name *name{ + std::get_if(&procedureDesignator.u)}; + if (name && + !(name->source == "max" || name->source == "min" || + name->source == "iand" || name->source == "ior" || + name->source == "ieor")) { + context_.Say(expr.source, + "Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement"_err_en_US); + } + }, + [&](const auto &x) { + if (!CheckOperatorValidity(x, var)) { + context_.Say(expr.source, + "Invalid operator in OpenMP ATOMIC construct UPDATE statement"_err_en_US); + } + }, + }, + expr.u); +} + void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) { std::visit( common::visitors{ - [&](const auto &someAtomicConstruct) { - const auto &dir{std::get(someAtomicConstruct.t)}; + [&](const parser::OmpAtomic &atomicConstruct) { + CheckAtomicConstructStructure(atomicConstruct); + }, + [&](const parser::OmpAtomicUpdate &atomicConstruct) { + CheckAtomicConstructStructure(atomicConstruct); + }, + [&](const auto &atomicConstruct) { + const auto &dir{std::get(atomicConstruct.t)}; PushContextAndClauseSets( dir.source, llvm::omp::Directive::OMPD_atomic); }, diff --git a/flang/test/Semantics/omp-atomic02.f90 b/flang/test/Semantics/omp-atomic02.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-atomic02.f90 @@ -0,0 +1,113 @@ +! RUN: python %S/test_errors.py %s %flang -fopenmp + +! OpenMP Atomic construct +! section 2.17.7 +! operator is one of +, *, -, /, .AND., .OR., .EQV., or .NEQV + +program OmpAtomic + use omp_lib + CHARACTER c*3, d*3 + LOGICAL l, m, n + + a = 1 + b = 2 + c = 'foo' + d = 'bar' + m = .TRUE. + n = .FALSE. + !$omp parallel num_threads(4) + + !$omp atomic + a = a + (4*2) + !$omp atomic + a = a*(b + 1) + !$omp atomic + a = a - 3 + !$omp atomic + a = a/(b + 1) + !$omp atomic + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + a = a**4 + !$omp atomic + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + c = c//d + !$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .LT. b + !$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .LE. b + !$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .EQ. b + !$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .NE. b + !$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .GE. b + !$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .GT. b + !$omp atomic + m = m .AND. n + !$omp atomic + m = m .OR. n + !$omp atomic + m = m .EQV. n + !$omp atomic + m = m .NEQV. n + !$omp atomic update + a = a + (4*2) + !$omp atomic update + a = a*(b + 1) + !$omp atomic update + a = a - 3 + !$omp atomic update + a = a/(b + 1) + !$omp atomic update + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + a = a**4 + !$omp atomic update + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + c = c//d + !$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .LT. b + !$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .LE. b + !$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .EQ. b + !$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .NE. b + !$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .GE. b + !$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .GT. b + !$omp atomic update + m = m .AND. n + !$omp atomic update + m = m .OR. n + !$omp atomic update + m = m .EQV. n + !$omp atomic update + m = m .NEQV. n + !$omp end parallel +end program OmpAtomic diff --git a/flang/test/Semantics/omp-atomic03.f90 b/flang/test/Semantics/omp-atomic03.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-atomic03.f90 @@ -0,0 +1,129 @@ +! RUN: python %S/test_errors.py %s %flang -fopenmp + +! OpenMP Atomic construct +! section 2.17.7 +! Intrinsic procedure name is one of MAX, MIN, IAND, IOR, or IEOR. + +program OmpAtomic + use omp_lib + real x + integer y + x = 5.73 + y = 3 +!$omp atomic + y = IAND(y, 4) +!$omp atomic + y = IOR(y, 5) +!$omp atomic + y = IEOR(y, 6) +!$omp atomic + y = MAX(y, 7) +!$omp atomic + y = MIN(y, 8) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = MOD(y, 9) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ABS(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = SQRT(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = SIN(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = COS(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = TAN(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ASIN(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ACOS(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ATAN(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = EXP(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = LOG(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = INT(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = NINT(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = FLOOR(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = FRACTION(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = REAL(x) +!$omp atomic update + y = IAND(y, 4) +!$omp atomic update + y = IOR(y, 5) +!$omp atomic update + y = IEOR(y, 6) +!$omp atomic update + y = MAX(y, 7) +!$omp atomic update + y = MIN(y, 8) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = MOD(y, 9) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ABS(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = SQRT(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = SIN(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = COS(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = TAN(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ASIN(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ACOS(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ATAN(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = EXP(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = LOG(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = INT(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = NINT(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = FLOOR(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = FRACTION(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = REAL(x) +end program OmpAtomic diff --git a/flang/test/Semantics/omp-atomic04.f90 b/flang/test/Semantics/omp-atomic04.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-atomic04.f90 @@ -0,0 +1,168 @@ +! RUN: python %S/test_errors.py %s %flang -fopenmp + +! OpenMP Atomic construct +! section 2.17.7 +! Update assignment must be 'var = var op expr' or 'var = expr op var' + +program OmpAtomic + use omp_lib + real x + integer y + logical m, n, l + x = 5.73 + y = 3 + m = .TRUE. + n = .FALSE. +!$omp atomic + x = x + 1 +!$omp atomic + x = 1 + x +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + x = y + 1 +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + x = 1 + y + +!$omp atomic + x = x - 1 +!$omp atomic + x = 1 - x +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + x = y - 1 +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + x = 1 - y + +!$omp atomic + x = x*1 +!$omp atomic + x = 1*x +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + x = y*1 +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + x = 1*y + +!$omp atomic + x = x/1 +!$omp atomic + x = 1/x +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + x = y/1 +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + x = 1/y + +!$omp atomic + m = m .AND. n +!$omp atomic + m = n .AND. m +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + m = n .AND. l + +!$omp atomic + m = m .OR. n +!$omp atomic + m = n .OR. m +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + m = n .OR. l + +!$omp atomic + m = m .EQV. n +!$omp atomic + m = n .EQV. m +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + m = n .EQV. l + +!$omp atomic + m = m .NEQV. n +!$omp atomic + m = n .NEQV. m +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + m = n .NEQV. l + +!$omp atomic update + x = x + 1 +!$omp atomic update + x = 1 + x +!$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + x = y + 1 +!$omp atomic + !ERROR: Variable name mismatch on lvalue and rvalue + x = 1 + y + +!$omp atomic update + x = x - 1 +!$omp atomic update + x = 1 - x +!$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + x = y - 1 +!$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + x = 1 - y + +!$omp atomic update + x = x*1 +!$omp atomic update + x = 1*x +!$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + x = y*1 +!$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + x = 1*y + +!$omp atomic update + x = x/1 +!$omp atomic update + x = 1/x +!$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + x = y/1 +!$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + x = 1/y + +!$omp atomic update + m = m .AND. n +!$omp atomic update + m = n .AND. m +!$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + m = n .AND. l + +!$omp atomic update + m = m .OR. n +!$omp atomic update + m = n .OR. m +!$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + m = n .OR. l + +!$omp atomic update + m = m .EQV. n +!$omp atomic update + m = n .EQV. m +!$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + m = n .EQV. l + +!$omp atomic update + m = m .NEQV. n +!$omp atomic update + m = n .NEQV. m +!$omp atomic update + !ERROR: Variable name mismatch on lvalue and rvalue + m = n .NEQV. l + +end program OmpAtomic