Skip to content

[flang][OpenMP] Clarify confusing error message #144707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 38 additions & 19 deletions flang/lib/Semantics/check-omp-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3510,37 +3510,56 @@ void OmpStructureChecker::CheckAtomicUpdateAssignment(
operation::ToString(top.first));
return;
}
// Check if `atom` occurs exactly once in the argument list.
// Check how many times `atom` occurs as an argument, if it's a subexpression
// of an argument, and collect the non-atom arguments.
std::vector<SomeExpr> nonAtom;
auto unique{[&]() { // -> iterator
auto found{top.second.end()};
for (auto i{top.second.begin()}, e{top.second.end()}; i != e; ++i) {
if (IsSameOrConvertOf(*i, atom)) {
if (found != top.second.end()) {
return top.second.end();
}
found = i;
MaybeExpr subExpr;
auto atomCount{[&]() {
int count{0};
for (const SomeExpr &arg : top.second) {
if (IsSameOrConvertOf(arg, atom)) {
++count;
} else {
nonAtom.push_back(*i);
if (!subExpr && IsSubexpressionOf(atom, arg)) {
subExpr = arg;
}
nonAtom.push_back(arg);
}
}
return found;
return count;
}()};

if (unique == top.second.end()) {
if (top.first == operation::Operator::Identity) {
// This is "x = y".
bool hasError{false};
if (subExpr) {
context_.Say(rsrc,
"The atomic variable %s cannot be a proper subexpression of an argument (here: %s) in the update operation"_err_en_US,
atom.AsFortran(), subExpr->AsFortran());
hasError = true;
}
if (top.first == operation::Operator::Identity) {
// This is "x = y".
assert((atomCount == 0 || atomCount == 1) && "Unexpected count");
if (atomCount == 0) {
context_.Say(rsrc,
"The atomic variable %s should appear as an argument in the update operation"_err_en_US,
atom.AsFortran());
} else {
assert(top.first != operation::Operator::Identity &&
"Handle this separately");
hasError = true;
}
} else {
if (atomCount == 0) {
context_.Say(rsrc,
"The atomic variable %s should appear as an argument of the top-level %s operator"_err_en_US,
atom.AsFortran(), operation::ToString(top.first));
hasError = true;
} else if (atomCount > 1) {
context_.Say(rsrc,
"The atomic variable %s should occur exactly once among the arguments of the top-level %s operator"_err_en_US,
"The atomic variable %s should be exactly one of the arguments of the top-level %s operator"_err_en_US,
atom.AsFortran(), operation::ToString(top.first));
hasError = true;
}
} else {
}

if (!hasError) {
CheckStorageOverlap(atom, nonAtom, source);
}
}
Expand Down
3 changes: 2 additions & 1 deletion flang/test/Semantics/OpenMP/atomic-update-only.f90
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ subroutine f03
integer :: x, y

!$omp atomic update
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator
!ERROR: The atomic variable x cannot be a proper subexpression of an argument (here: (x+y)) in the update operation
!ERROR: The atomic variable x should appear as an argument of the top-level + operator
x = (x + y) + 1
end

Expand Down
32 changes: 16 additions & 16 deletions flang/test/Semantics/OpenMP/atomic03.f90
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@ program OmpAtomic
y = MIN(y, 8)

!$omp atomic
!ERROR: The atomic variable z should occur exactly once among the arguments of the top-level AND operator
!ERROR: The atomic variable z should appear as an argument of the top-level AND operator
z = IAND(y, 4)
!$omp atomic
!ERROR: The atomic variable z should occur exactly once among the arguments of the top-level OR operator
!ERROR: The atomic variable z should appear as an argument of the top-level OR operator
z = IOR(y, 5)
!$omp atomic
!ERROR: The atomic variable z should occur exactly once among the arguments of the top-level NEQV/EOR operator
!ERROR: The atomic variable z should appear as an argument of the top-level NEQV/EOR operator
z = IEOR(y, 6)
!$omp atomic
!ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MAX operator
!ERROR: The atomic variable z should appear as an argument of the top-level MAX operator
z = MAX(y, 7, b, c)
!$omp atomic
!ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MIN operator
!ERROR: The atomic variable z should appear as an argument of the top-level MIN operator
z = MIN(y, 8, a, d)

!$omp atomic
Expand All @@ -58,19 +58,19 @@ program OmpAtomic
y = MIN(y, 8)

!$omp atomic update
!ERROR: The atomic variable z should occur exactly once among the arguments of the top-level AND operator
!ERROR: The atomic variable z should appear as an argument of the top-level AND operator
z = IAND(y, 4)
!$omp atomic update
!ERROR: The atomic variable z should occur exactly once among the arguments of the top-level OR operator
!ERROR: The atomic variable z should appear as an argument of the top-level OR operator
z = IOR(y, 5)
!$omp atomic update
!ERROR: The atomic variable z should occur exactly once among the arguments of the top-level NEQV/EOR operator
!ERROR: The atomic variable z should appear as an argument of the top-level NEQV/EOR operator
z = IEOR(y, 6)
!$omp atomic update
!ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MAX operator
!ERROR: The atomic variable z should appear as an argument of the top-level MAX operator
z = MAX(y, 7)
!$omp atomic update
!ERROR: The atomic variable z should occur exactly once among the arguments of the top-level MIN operator
!ERROR: The atomic variable z should appear as an argument of the top-level MIN operator
z = MIN(y, 8)

!$omp atomic update
Expand All @@ -90,7 +90,7 @@ subroutine conflicting_types()
type(simple) ::s
z = 1
!$omp atomic
!ERROR: The atomic variable z should occur exactly once among the arguments of the top-level AND operator
!ERROR: The atomic variable z should appear as an argument of the top-level AND operator
z = IAND(s%z, 4)
end subroutine

Expand All @@ -103,30 +103,30 @@ subroutine more_invalid_atomic_update_stmts()
type(some_type) :: s

!$omp atomic update
!ERROR: The atomic variable a should occur exactly once among the arguments of the top-level MIN operator
!ERROR: The atomic variable a should be exactly one of the arguments of the top-level MIN operator
a = min(a, a, b)

!$omp atomic
!ERROR: The atomic variable a should occur exactly once among the arguments of the top-level MAX operator
!ERROR: The atomic variable a should be exactly one of the arguments of the top-level MAX operator
a = max(b, a, b, a)

!$omp atomic
a = min(b, a, b)

!$omp atomic
!ERROR: The atomic variable a should occur exactly once among the arguments of the top-level MAX operator
!ERROR: The atomic variable a should be exactly one of the arguments of the top-level MAX operator
a = max(b, a, b, a, b)

!$omp atomic update
!ERROR: The atomic variable y should occur exactly once among the arguments of the top-level MIN operator
!ERROR: The atomic variable y should appear as an argument of the top-level MIN operator
y = min(z, x)

!$omp atomic
z = max(z, y)

!$omp atomic update
!ERROR: Atomic variable k should be a scalar
!ERROR: The atomic variable k should occur exactly once among the arguments of the top-level MAX operator
!ERROR: The atomic variable k should appear as an argument of the top-level MAX operator
k = max(x, y)

!$omp atomic
Expand Down
60 changes: 32 additions & 28 deletions flang/test/Semantics/OpenMP/atomic04.f90
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,21 @@ program OmpAtomic
!$omp atomic
x = 1 + x
!$omp atomic
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator
!ERROR: The atomic variable x should appear as an argument of the top-level + operator
x = y + 1
!$omp atomic
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator
!ERROR: The atomic variable x should appear as an argument of the top-level + operator
x = 1 + y

!$omp atomic
x = x - 1
!$omp atomic
x = 1 - x
!$omp atomic
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator
!ERROR: The atomic variable x should appear as an argument of the top-level - operator
x = y - 1
!$omp atomic
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator
!ERROR: The atomic variable x should appear as an argument of the top-level - operator
x = 1 - y

!$omp atomic
Expand All @@ -50,64 +50,64 @@ program OmpAtomic
!$omp atomic
x = 1/x
!$omp atomic
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator
!ERROR: The atomic variable x should appear as an argument of the top-level / operator
x = y/1
!$omp atomic
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator
!ERROR: The atomic variable x should appear as an argument of the top-level / operator
x = 1/y

!$omp atomic
m = m .AND. n
!$omp atomic
m = n .AND. m
!$omp atomic
!ERROR: The atomic variable m should occur exactly once among the arguments of the top-level AND operator
!ERROR: The atomic variable m should appear as an argument of the top-level AND operator
m = n .AND. l

!$omp atomic
m = m .OR. n
!$omp atomic
m = n .OR. m
!$omp atomic
!ERROR: The atomic variable m should occur exactly once among the arguments of the top-level OR operator
!ERROR: The atomic variable m should appear as an argument of the top-level OR operator
m = n .OR. l

!$omp atomic
m = m .EQV. n
!$omp atomic
m = n .EQV. m
!$omp atomic
!ERROR: The atomic variable m should occur exactly once among the arguments of the top-level EQV operator
!ERROR: The atomic variable m should appear as an argument of the top-level EQV operator
m = n .EQV. l

!$omp atomic
m = m .NEQV. n
!$omp atomic
m = n .NEQV. m
!$omp atomic
!ERROR: The atomic variable m should occur exactly once among the arguments of the top-level NEQV/EOR operator
!ERROR: The atomic variable m should appear as an argument of the top-level NEQV/EOR operator
m = n .NEQV. l

!$omp atomic update
x = x + 1
!$omp atomic update
x = 1 + x
!$omp atomic update
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator
!ERROR: The atomic variable x should appear as an argument of the top-level + operator
x = y + 1
!$omp atomic update
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level + operator
!ERROR: The atomic variable x should appear as an argument of the top-level + operator
x = 1 + y

!$omp atomic update
x = x - 1
!$omp atomic update
x = 1 - x
!$omp atomic update
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator
!ERROR: The atomic variable x should appear as an argument of the top-level - operator
x = y - 1
!$omp atomic update
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level - operator
!ERROR: The atomic variable x should appear as an argument of the top-level - operator
x = 1 - y

!$omp atomic update
Expand All @@ -126,42 +126,42 @@ program OmpAtomic
!$omp atomic update
x = 1/x
!$omp atomic update
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator
!ERROR: The atomic variable x should appear as an argument of the top-level / operator
x = y/1
!$omp atomic update
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator
!ERROR: The atomic variable x should appear as an argument of the top-level / operator
x = 1/y

!$omp atomic update
m = m .AND. n
!$omp atomic update
m = n .AND. m
!$omp atomic update
!ERROR: The atomic variable m should occur exactly once among the arguments of the top-level AND operator
!ERROR: The atomic variable m should appear as an argument of the top-level AND operator
m = n .AND. l

!$omp atomic update
m = m .OR. n
!$omp atomic update
m = n .OR. m
!$omp atomic update
!ERROR: The atomic variable m should occur exactly once among the arguments of the top-level OR operator
!ERROR: The atomic variable m should appear as an argument of the top-level OR operator
m = n .OR. l

!$omp atomic update
m = m .EQV. n
!$omp atomic update
m = n .EQV. m
!$omp atomic update
!ERROR: The atomic variable m should occur exactly once among the arguments of the top-level EQV operator
!ERROR: The atomic variable m should appear as an argument of the top-level EQV operator
m = n .EQV. l

!$omp atomic update
m = m .NEQV. n
!$omp atomic update
m = n .NEQV. m
!$omp atomic update
!ERROR: The atomic variable m should occur exactly once among the arguments of the top-level NEQV/EOR operator
!ERROR: The atomic variable m should appear as an argument of the top-level NEQV/EOR operator
m = n .NEQV. l

end program OmpAtomic
Expand All @@ -184,27 +184,30 @@ subroutine more_invalid_atomic_update_stmts()
x = 1

!$omp atomic update
!ERROR: Within atomic operation a and a*b access the same storage
!ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: a*b) in the update operation
a = a * b + a

!$omp atomic
!ERROR: The atomic variable a should occur exactly once among the arguments of the top-level * operator
!ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: (a+9_4)) in the update operation
!ERROR: The atomic variable a should appear as an argument of the top-level * operator
a = b * (a + 9)

!$omp atomic update
!ERROR: Within atomic operation a and (a+b) access the same storage
!ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: (a+b)) in the update operation
a = a * (a + b)

!$omp atomic
!ERROR: Within atomic operation a and (b+a) access the same storage
!ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: (b+a)) in the update operation
a = (b + a) * a

!$omp atomic
!ERROR: The atomic variable a should occur exactly once among the arguments of the top-level + operator
!ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: a*b) in the update operation
!ERROR: The atomic variable a should appear as an argument of the top-level + operator
a = a * b + c

!$omp atomic update
!ERROR: The atomic variable a should occur exactly once among the arguments of the top-level + operator
!ERROR: The atomic variable a cannot be a proper subexpression of an argument (here: a+b) in the update operation
!ERROR: The atomic variable a should appear as an argument of the top-level + operator
a = a + b + c

!$omp atomic
Expand All @@ -219,11 +222,12 @@ subroutine more_invalid_atomic_update_stmts()

!$omp atomic update
!ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar REAL(4) and rank 1 array of REAL(4)
!ERROR: The atomic variable x should occur exactly once among the arguments of the top-level / operator
!ERROR: The atomic variable x cannot be a proper subexpression of an argument (here: x*y) in the update operation
!ERROR: The atomic variable x should appear as an argument of the top-level / operator
x = x * y / z

!$omp atomic
!ERROR: The atomic variable p%m should occur exactly once among the arguments of the top-level + operator
!ERROR: The atomic variable p%m should appear as an argument of the top-level + operator
p%m = x + y

!$omp atomic update
Expand Down
Loading