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 @@ -175,7 +175,9 @@ template bool IsOperatorValid(const T &, const D &); void CheckAtomicMemoryOrderClause( const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *); - void CheckAtomicUpdateAssignmentStmt(const parser::AssignmentStmt &); + void CheckAtomicUpdateStmt(const parser::AssignmentStmt &); + void CheckAtomicCaptureStmt(const parser::AssignmentStmt &); + void CheckAtomicWriteStmt(const parser::AssignmentStmt &); void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &); void CheckDistLinear(const parser::OpenMPLoopConstruct &x); void CheckSIMDNest(const parser::OpenMPConstruct &x); @@ -214,7 +216,11 @@ void ExitDirectiveNest(const int index) { directiveNest_[index]--; } int GetDirectiveNest(const int index) { return directiveNest_[index]; } template void CheckHintClause(D *, D *); - + inline void ErrIfAllocatableVariable(const parser::Variable &); + inline void ErrIfLHSAndRHSSymbolsMatch( + const parser::Variable &, const parser::Expr &); + inline void ErrIfNonScalarAssignmentStmt( + const parser::Variable &, const parser::Expr &); enum directiveNestType { SIMDNest, TargetBlockOnlyTeams, 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 @@ -1647,6 +1647,67 @@ } } +inline void OmpStructureChecker::ErrIfAllocatableVariable( + const parser::Variable &var) { + // Err out if the given symbol has + // ALLOCATABLE attribute + if (const auto *e{GetExpr(context_, var)}) + for (const Symbol &symbol : evaluate::CollectSymbols(*e)) + if (IsAllocatable(symbol)) { + const auto &designator = + std::get>(var.u); + const auto *dataRef = + std::get_if(&designator.value().u); + const Fortran::parser::Name *name = + dataRef ? std::get_if(&dataRef->u) : nullptr; + if (name) + context_.Say(name->source, + "%s must not have ALLOCATABLE " + "attribute"_err_en_US, + name->ToString()); + } +} + +inline void OmpStructureChecker::ErrIfLHSAndRHSSymbolsMatch( + const parser::Variable &var, const parser::Expr &expr) { + // Err out if the symbol on the LHS is also used on the RHS of the assignment + // statement + const auto *e{GetExpr(context_, expr)}; + const auto *v{GetExpr(context_, var)}; + if (e && v) { + const Symbol &varSymbol = evaluate::GetSymbolVector(*v).front(); + for (const Symbol &symbol : evaluate::GetSymbolVector(*e)) { + if (varSymbol == symbol) { + context_.Say(expr.source, + "RHS expression " + "on atomic assignment statement" + " cannot access '%s'"_err_en_US, + var.GetSource().ToString()); + } + } + } +} + +inline void OmpStructureChecker::ErrIfNonScalarAssignmentStmt( + const parser::Variable &var, const parser::Expr &expr) { + // Err out if either the variable on the LHS or the expression on the RHS of + // the assignment statement are non-scalar (i.e. have rank > 0) + const auto *e{GetExpr(context_, expr)}; + const auto *v{GetExpr(context_, var)}; + if (e && v) { + if (e->Rank() != 0) + context_.Say(expr.source, + "Expected scalar expression " + "on the RHS of atomic assignment " + "statement"_err_en_US); + if (v->Rank() != 0) + context_.Say(var.GetSource(), + "Expected scalar variable " + "on the LHS of atomic assignment " + "statement"_err_en_US); + } +} + template bool OmpStructureChecker::IsOperatorValid(const T &node, const D &variable) { using AllowedBinaryOperators = @@ -1667,16 +1728,55 @@ 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); + "Atomic update statement should be of form " + "`%s = %s operator expr` OR `%s = expr operator %s`"_err_en_US, + variableName, variableName, variableName, variableName); } return common::HasMember; } return true; } -void OmpStructureChecker::CheckAtomicUpdateAssignmentStmt( +void OmpStructureChecker::CheckAtomicCaptureStmt( + const parser::AssignmentStmt &assignmentStmt) { + const auto &var{std::get(assignmentStmt.t)}; + const auto &expr{std::get(assignmentStmt.t)}; + common::visit( + common::visitors{ + [&](const common::Indirection &designator) { + const auto *dataRef = + std::get_if(&designator.value().u); + const auto *name = dataRef + ? std::get_if(&dataRef->u) + : nullptr; + if (name && IsAllocatable(*name->symbol)) + context_.Say(name->source, + "%s must not have ALLOCATABLE " + "attribute"_err_en_US, + name->ToString()); + }, + [&](const auto &) { + // Anything other than a `parser::Designator` is not allowed + context_.Say(expr.source, + "Expected scalar variable " + "of intrinsic type on RHS of atomic " + "assignment statement"_err_en_US); + }}, + expr.u); + ErrIfLHSAndRHSSymbolsMatch(var, expr); + ErrIfNonScalarAssignmentStmt(var, expr); +} + +void OmpStructureChecker::CheckAtomicWriteStmt( + const parser::AssignmentStmt &assignmentStmt) { + const auto &var{std::get(assignmentStmt.t)}; + const auto &expr{std::get(assignmentStmt.t)}; + ErrIfAllocatableVariable(var); + ErrIfLHSAndRHSSymbolsMatch(var, expr); + ErrIfNonScalarAssignmentStmt(var, expr); +} + +void OmpStructureChecker::CheckAtomicUpdateStmt( const parser::AssignmentStmt &assignment) { const auto &expr{std::get(assignment.t)}; const auto &var{std::get(assignment.t)}; @@ -1734,6 +1834,7 @@ }, }, expr.u); + ErrIfAllocatableVariable(var); } void OmpStructureChecker::CheckAtomicMemoryOrderClause( @@ -1772,7 +1873,7 @@ const auto &dir{std::get(atomicConstruct.t)}; PushContextAndClauseSets( dir.source, llvm::omp::Directive::OMPD_atomic); - CheckAtomicUpdateAssignmentStmt( + CheckAtomicUpdateStmt( std::get>( atomicConstruct.t) .statement); @@ -1787,7 +1888,7 @@ const auto &dir{std::get(atomicUpdate.t)}; PushContextAndClauseSets( dir.source, llvm::omp::Directive::OMPD_atomic); - CheckAtomicUpdateAssignmentStmt( + CheckAtomicUpdateStmt( std::get>( atomicUpdate.t) .statement); @@ -1796,6 +1897,32 @@ CheckHintClause( &std::get<0>(atomicUpdate.t), &std::get<2>(atomicUpdate.t)); }, + [&](const parser::OmpAtomicRead &atomicRead) { + const auto &dir{std::get(atomicRead.t)}; + PushContextAndClauseSets( + dir.source, llvm::omp::Directive::OMPD_atomic); + CheckAtomicMemoryOrderClause( + &std::get<0>(atomicRead.t), &std::get<2>(atomicRead.t)); + CheckHintClause( + &std::get<0>(atomicRead.t), &std::get<2>(atomicRead.t)); + CheckAtomicCaptureStmt( + std::get>( + atomicRead.t) + .statement); + }, + [&](const parser::OmpAtomicWrite &atomicWrite) { + const auto &dir{std::get(atomicWrite.t)}; + PushContextAndClauseSets( + dir.source, llvm::omp::Directive::OMPD_atomic); + CheckAtomicMemoryOrderClause( + &std::get<0>(atomicWrite.t), &std::get<2>(atomicWrite.t)); + CheckHintClause( + &std::get<0>(atomicWrite.t), &std::get<2>(atomicWrite.t)); + CheckAtomicWriteStmt( + std::get>( + atomicWrite.t) + .statement); + }, [&](const auto &atomicConstruct) { const auto &dir{std::get(atomicConstruct.t)}; PushContextAndClauseSets( diff --git a/flang/test/Semantics/OpenMP/atomic-hint-clause.f90 b/flang/test/Semantics/OpenMP/atomic-hint-clause.f90 --- a/flang/test/Semantics/OpenMP/atomic-hint-clause.f90 +++ b/flang/test/Semantics/OpenMP/atomic-hint-clause.f90 @@ -95,6 +95,7 @@ x = 10 * y !$omp atomic write hint(a) + !ERROR: RHS expression on atomic assignment statement cannot access 'x' x = y + x !$omp atomic hint(abs(-1)) write diff --git a/flang/test/Semantics/OpenMP/atomic02.f90 b/flang/test/Semantics/OpenMP/atomic02.f90 --- a/flang/test/Semantics/OpenMP/atomic02.f90 +++ b/flang/test/Semantics/OpenMP/atomic02.f90 @@ -32,27 +32,27 @@ !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: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` !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: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` !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: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` !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: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` !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: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` !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: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement l = a .GT. b !$omp atomic @@ -78,23 +78,23 @@ !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: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` !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: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` !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: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` !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: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` !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: Atomic update statement should be of form `l = l operator expr` OR `l = expr operator l` !ERROR: Invalid operator in OpenMP ATOMIC (UPDATE) statement l = a .GT. b !$omp atomic update diff --git a/flang/test/Semantics/OpenMP/atomic04.f90 b/flang/test/Semantics/OpenMP/atomic04.f90 --- a/flang/test/Semantics/OpenMP/atomic04.f90 +++ b/flang/test/Semantics/OpenMP/atomic04.f90 @@ -18,21 +18,22 @@ !$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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` 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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` + x = 1 + (y + x) !$omp atomic - x = x - 1 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` + x = 1 - (10 * (y + x)) !$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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` x = y - 1 !$omp atomic - !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` x = 1 - y !$omp atomic @@ -40,21 +41,21 @@ !$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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` + x = y*(10 + x) !$omp atomic - !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct - x = 1*y + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` + x = (44 * x) * 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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` x = y/1 !$omp atomic - !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC (UPDATE) construct + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` x = 1/y !$omp atomic @@ -62,7 +63,7 @@ !$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 + !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` m = n .AND. l !$omp atomic @@ -70,7 +71,7 @@ !$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 + !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` m = n .OR. l !$omp atomic @@ -78,7 +79,7 @@ !$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 + !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` m = n .EQV. l !$omp atomic @@ -86,7 +87,7 @@ !$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 + !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` m = n .NEQV. l !$omp atomic update @@ -94,10 +95,10 @@ !$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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` 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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` x = 1 + y !$omp atomic update @@ -105,10 +106,10 @@ !$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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` 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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` x = 1 - y !$omp atomic update @@ -116,10 +117,10 @@ !$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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` 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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` x = 1*y !$omp atomic update @@ -127,18 +128,18 @@ !$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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` + x = max(x, y) + 10 !$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 + !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x` + x = y * min(x, 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 + !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` m = n .AND. l !$omp atomic update @@ -146,7 +147,7 @@ !$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 + !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` m = n .OR. l !$omp atomic update @@ -154,7 +155,7 @@ !$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 + !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` m = n .EQV. l !$omp atomic update @@ -162,7 +163,7 @@ !$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 + !ERROR: Atomic update statement should be of form `m = m operator expr` OR `m = expr operator m` m = n .NEQV. l end program OmpAtomic diff --git a/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90 b/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90 @@ -0,0 +1,86 @@ +! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp +! Semantic checks for various assignments related to atomic constructs + +program sample + use omp_lib + integer :: x, v + integer :: y(10) + integer, allocatable :: k + integer a(10) + type sample_type + integer :: y + integer :: m + endtype + type(sample_type) :: z + !$omp atomic read + v = x + + !$omp atomic read + !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar INTEGER(4) and rank 1 array of INTEGER(4) + !ERROR: Expected scalar expression on the RHS of atomic assignment statement + v = y(1:3) + + !$omp atomic read + !ERROR: Expected scalar variable of intrinsic type on RHS of atomic assignment statement + v = x * (10 + x) + + !$omp atomic read + !ERROR: Expected scalar variable of intrinsic type on RHS of atomic assignment statement + v = 4 + + !$omp atomic read + !ERROR: k must not have ALLOCATABLE attribute + v = k + + !$omp atomic write + !ERROR: k must not have ALLOCATABLE attribute + k = x + + !$omp atomic update + !ERROR: Atomic update statement should be of form `k = k operator expr` OR `k = expr operator k` + !ERROR: k must not have ALLOCATABLE attribute + k = v + k * (v * k) + + !$omp atomic + !ERROR: k must not have ALLOCATABLE attribute + k = v * k + + !$omp atomic write + !ERROR: RHS expression on atomic assignment statement cannot access 'z%y' + z%y = x + z%y + + !$omp atomic write + !ERROR: RHS expression on atomic assignment statement cannot access 'x' + x = x + + !$omp atomic write + !ERROR: RHS expression on atomic assignment statement cannot access 'm' + m = min(m, x, z%m) + k + + !$omp atomic read + !ERROR: RHS expression on atomic assignment statement cannot access 'x' + x = x + + !$omp atomic read + !ERROR: Expected scalar variable of intrinsic type on RHS of atomic assignment statement + !ERROR: RHS expression on atomic assignment statement cannot access 'm' + m = min(m, x, z%m) + k + + !$omp atomic read + !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar INTEGER(4) and rank 1 array of INTEGER(4) + !ERROR: Expected scalar expression on the RHS of atomic assignment statement + x = a + + !$omp atomic read + !ERROR: Expected scalar variable on the LHS of atomic assignment statement + a = x + + !$omp atomic write + !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar INTEGER(4) and rank 1 array of INTEGER(4) + !ERROR: Expected scalar expression on the RHS of atomic assignment statement + x = a + + !$omp atomic write + !ERROR: Expected scalar variable on the LHS of atomic assignment statement + a = x +end program