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 @@ -229,6 +229,12 @@ void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); void CheckDoWhile(const parser::OpenMPLoopConstruct &x); void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); + template bool IsOperatorValid(const T &, const D &); + void CheckAtomicMemoryOrderClause( + const parser::OmpAtomicClauseList &, const parser::OmpAtomicClauseList &); + void CheckAtomicMemoryOrderClause(const parser::OmpAtomicClauseList &); + void CheckAtomicUpdateAssignmentStmt(const parser::AssignmentStmt &); + 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 @@ -1287,13 +1287,163 @@ } } +template +bool OmpStructureChecker::IsOperatorValid(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(), + "Atomic update variable '%s' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct"_err_en_US, + variableName); + } + return common::HasMember; + } + return true; +} + +void OmpStructureChecker::CheckAtomicUpdateAssignmentStmt( + const parser::AssignmentStmt &assignment) { + 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 (UPDATE) statement"_err_en_US); + } else if (name) { + bool foundMatch{false}; + if (auto varDesignatorIndirection = + std::get_if>(&var.u)) { + const auto &varDesignator = varDesignatorIndirection->value(); + if (const auto *dataRef = std::get_if( + &varDesignator.u)) { + if (const auto *name = + std::get_if(&dataRef->u)) { + const auto &varSymbol = *name->symbol; + if (const auto *e{GetExpr(expr)}) { + for (const Symbol &symbol : + evaluate::CollectSymbols(*e)) { + if (symbol == varSymbol) { + foundMatch = true; + break; + } + } + } + } + } + } + if (!foundMatch) { + context_.Say(expr.source, + "Atomic update variable '%s' not found in the argument list of intrinsic procedure"_err_en_US, + var.GetSource().ToString()); + } + } + }, + [&](const auto &x) { + if (!IsOperatorValid(x, var)) { + context_.Say(expr.source, + "Invalid operator in OpenMP ATOMIC (UPDATE) statement"_err_en_US); + } + }, + }, + expr.u); +} + +void OmpStructureChecker::CheckAtomicMemoryOrderClause( + const parser::OmpAtomicClauseList &clauseList) { + int numMemoryOrderClause = 0; + for (const auto &clause : clauseList.v) { + if (std::get_if(&clause.u)) { + numMemoryOrderClause++; + if (numMemoryOrderClause > 1) { + context_.Say(clause.source, + "More than one memory order clause not allowed on OpenMP Atomic construct"_err_en_US); + return; + } + } + } +} + +void OmpStructureChecker::CheckAtomicMemoryOrderClause( + const parser::OmpAtomicClauseList &leftHandClauseList, + const parser::OmpAtomicClauseList &rightHandClauseList) { + int numMemoryOrderClause = 0; + for (const auto &clause : leftHandClauseList.v) { + if (std::get_if(&clause.u)) { + numMemoryOrderClause++; + if (numMemoryOrderClause > 1) { + context_.Say(clause.source, + "More than one memory order clause not allowed on OpenMP Atomic construct"_err_en_US); + return; + } + } + } + for (const auto &clause : rightHandClauseList.v) { + if (std::get_if(&clause.u)) { + numMemoryOrderClause++; + if (numMemoryOrderClause > 1) { + context_.Say(clause.source, + "More than one memory order clause not allowed on OpenMP Atomic construct"_err_en_US); + return; + } + } + } +} + 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) { + const auto &dir{std::get(atomicConstruct.t)}; + PushContextAndClauseSets( + dir.source, llvm::omp::Directive::OMPD_atomic); + CheckAtomicUpdateAssignmentStmt( + std::get>( + atomicConstruct.t) + .statement); + CheckAtomicMemoryOrderClause( + std::get(atomicConstruct.t)); + }, + [&](const parser::OmpAtomicUpdate &atomicConstruct) { + const auto &dir{std::get(atomicConstruct.t)}; + PushContextAndClauseSets( + dir.source, llvm::omp::Directive::OMPD_atomic); + CheckAtomicUpdateAssignmentStmt( + std::get>( + atomicConstruct.t) + .statement); + CheckAtomicMemoryOrderClause( + std::get<0>(atomicConstruct.t), std::get<2>(atomicConstruct.t)); + }, + [&](const auto &atomicConstruct) { + const auto &dir{std::get(atomicConstruct.t)}; PushContextAndClauseSets( dir.source, llvm::omp::Directive::OMPD_atomic); + CheckAtomicMemoryOrderClause( + std::get<0>(atomicConstruct.t), std::get<2>(atomicConstruct.t)); }, }, x.u); diff --git a/flang/test/Semantics/omp-atomic01.f90 b/flang/test/Semantics/omp-atomic01.f90 --- a/flang/test/Semantics/omp-atomic01.f90 +++ b/flang/test/Semantics/omp-atomic01.f90 @@ -12,152 +12,184 @@ ! At most one memory-order-clause may appear on the construct. !READ + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the READ directive !$omp atomic seq_cst seq_cst read i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the READ directive !$omp atomic read seq_cst seq_cst i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the READ directive !$omp atomic seq_cst read seq_cst i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one ACQUIRE clause can appear on the READ directive !$omp atomic acquire acquire read i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one ACQUIRE clause can appear on the READ directive !$omp atomic read acquire acquire i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one ACQUIRE clause can appear on the READ directive !$omp atomic acquire read acquire i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the READ directive !$omp atomic relaxed relaxed read i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the READ directive !$omp atomic read relaxed relaxed i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the READ directive !$omp atomic relaxed read relaxed i = j !UPDATE + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive !$omp atomic seq_cst seq_cst update i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive !$omp atomic update seq_cst seq_cst i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive !$omp atomic seq_cst update seq_cst i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELEASE clause can appear on the UPDATE directive !$omp atomic release release update i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELEASE clause can appear on the UPDATE directive !$omp atomic update release release i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELEASE clause can appear on the UPDATE directive !$omp atomic release update release i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the UPDATE directive !$omp atomic relaxed relaxed update i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the UPDATE directive !$omp atomic update relaxed relaxed i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the UPDATE directive !$omp atomic relaxed update relaxed i = j !CAPTURE + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive !$omp atomic seq_cst seq_cst capture i = j j = k !$omp end atomic - + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive !$omp atomic capture seq_cst seq_cst i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive !$omp atomic seq_cst capture seq_cst i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELEASE clause can appear on the CAPTURE directive !$omp atomic release release capture i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELEASE clause can appear on the CAPTURE directive !$omp atomic capture release release i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELEASE clause can appear on the CAPTURE directive !$omp atomic release capture release i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the CAPTURE directive !$omp atomic relaxed relaxed capture i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the CAPTURE directive !$omp atomic capture relaxed relaxed i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the CAPTURE directive !$omp atomic relaxed capture relaxed i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive !$omp atomic acq_rel acq_rel capture i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive !$omp atomic capture acq_rel acq_rel i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive !$omp atomic acq_rel capture acq_rel i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive !$omp atomic acquire acquire capture i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive !$omp atomic capture acquire acquire i = j j = k !$omp end atomic + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive !$omp atomic acquire capture acquire i = j @@ -165,43 +197,55 @@ !$omp end atomic !WRITE + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the WRITE directive !$omp atomic seq_cst seq_cst write i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the WRITE directive !$omp atomic write seq_cst seq_cst i = j + + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the WRITE directive !$omp atomic seq_cst write seq_cst i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELEASE clause can appear on the WRITE directive !$omp atomic release release write i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELEASE clause can appear on the WRITE directive !$omp atomic write release release i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELEASE clause can appear on the WRITE directive !$omp atomic release write release i = j - + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the WRITE directive !$omp atomic relaxed relaxed write i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the WRITE directive !$omp atomic write relaxed relaxed i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the WRITE directive !$omp atomic relaxed write relaxed i = j !No atomic-clause + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELAXED clause can appear on the ATOMIC directive !$omp atomic relaxed relaxed i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive !$omp atomic seq_cst seq_cst i = j + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct !ERROR: At most one RELEASE clause can appear on the ATOMIC directive !$omp atomic release release i = j 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,109 @@ +! 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 (UPDATE) statement + a = a**4 + !$omp atomic + !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement + c = c//d + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement + l = a .LT. b + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement + l = a .LE. b + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement + l = a .EQ. b + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement + l = a .NE. b + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement + l = a .GE. b + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Invalid operator in OpenMP ATOMIC (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 (UPDATE) statement + a = a**4 + !$omp atomic update + !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement + c = c//d + !$omp atomic update + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement + l = a .LT. b + !$omp atomic update + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement + l = a .LE. b + !$omp atomic update + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement + l = a .EQ. b + !$omp atomic update + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement + l = a .GE. b + !$omp atomic update + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Invalid operator in OpenMP ATOMIC (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,93 @@ +! 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, z, a, b, c, d + x = 5.73 + y = 3 + z = 1 +!$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: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IAND(y, 4) +!$omp atomic + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IOR(y, 5) +!$omp atomic + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IEOR(y, 6) +!$omp atomic + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = MAX(y, 7, b, c) +!$omp atomic + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = MIN(y, 8, a, d) + +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement + y = FRACTION(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (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: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IAND(y, 4) +!$omp atomic update + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IOR(y, 5) +!$omp atomic update + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IEOR(y, 6) +!$omp atomic update + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = MAX(y, 7) +!$omp atomic update + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = MIN(y, 8) + +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement + y = MOD(y, 9) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC (UPDATE) statement + x = ABS(x) +end program OmpAtomic + +subroutine conflicting_types() + type simple + integer :: z + end type + real x + integer :: y, z + type(simple) ::s + z = 1 + !$omp atomic + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IAND(s%z, 4) +end subroutine 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: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = y + 1 +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = 1 + y + +!$omp atomic + x = x - 1 +!$omp atomic + x = 1 - x +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = y - 1 +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = 1 - y + +!$omp atomic + x = x*1 +!$omp atomic + x = 1*x +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = y*1 +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = 1*y + +!$omp atomic + x = x/1 +!$omp atomic + x = 1/x +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = y/1 +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = 1/y + +!$omp atomic + m = m .AND. n +!$omp atomic + m = n .AND. m +!$omp atomic + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + m = n .AND. l + +!$omp atomic + m = m .OR. n +!$omp atomic + m = n .OR. m +!$omp atomic + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + m = n .OR. l + +!$omp atomic + m = m .EQV. n +!$omp atomic + m = n .EQV. m +!$omp atomic + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + m = n .EQV. l + +!$omp atomic + m = m .NEQV. n +!$omp atomic + m = n .NEQV. m +!$omp atomic + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + m = n .NEQV. l + +!$omp atomic update + x = x + 1 +!$omp atomic update + x = 1 + x +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = y + 1 +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = 1 + y + +!$omp atomic update + x = x - 1 +!$omp atomic update + x = 1 - x +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = y - 1 +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = 1 - y + +!$omp atomic update + x = x*1 +!$omp atomic update + x = 1*x +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = y*1 +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = 1*y + +!$omp atomic update + x = x/1 +!$omp atomic update + x = 1/x +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = y/1 +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + x = 1/y + +!$omp atomic update + m = m .AND. n +!$omp atomic update + m = n .AND. m +!$omp atomic update + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + m = n .AND. l + +!$omp atomic update + m = m .OR. n +!$omp atomic update + m = n .OR. m +!$omp atomic update + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + m = n .OR. l + +!$omp atomic update + m = m .EQV. n +!$omp atomic update + m = n .EQV. m +!$omp atomic update + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + m = n .EQV. l + +!$omp atomic update + m = m .NEQV. n +!$omp atomic update + m = n .NEQV. m +!$omp atomic update + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + m = n .NEQV. l + +end program OmpAtomic diff --git a/flang/test/Semantics/omp-atomic05.f90 b/flang/test/Semantics/omp-atomic05.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-atomic05.f90 @@ -0,0 +1,26 @@ +! RUN: %python %S/test_errors.py %s %flang -fopenmp + +! This tests the various semantics related to the clauses of various OpenMP atomic constructs + +program OmpAtomic + use omp_lib + integer :: g, x + + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct + !$omp atomic relaxed, seq_cst + x = x + 1 + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct + !$omp atomic read seq_cst, relaxed + x = g + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct + !$omp atomic write relaxed, release + x = 2 * 4 + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct + !$omp atomic update release, seq_cst + x = 10 + !ERROR: More than one memory order clause not allowed on OpenMP Atomic construct + !$omp atomic capture release, seq_cst + x = g + g = x * 10 + !$omp end atomic +end program OmpAtomic