Skip to content

Commit 59ab4d4

Browse files
KrxGuKrish Gupta
andauthored
[flang][OpenMP] Add diagnostic for ATOMIC WRITE with pointer to non-intrinsic type (#162364)
Fixes llvm/llvm-project#161932 Added a check for non-intrinsic types in non-pointer assignments. Added bool checkTypeOnPointer = true to both CheckAtomicVariable and CheckAtomicType. All atomic assignment functions now pass !IsPointerAssignment(...) to control the check. The pointer-to-non-intrinsic check lives in CheckAtomicType, guarded by the checkTypeOnPointer flag. The check now applies uniformly to all atomic operations while properly excluding pointer assignments (=>). --------- Co-authored-by: Krish Gupta <[email protected]>
1 parent 4b84e0f commit 59ab4d4

File tree

3 files changed

+42
-13
lines changed

3 files changed

+42
-13
lines changed

flang/lib/Semantics/check-omp-atomic.cpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -519,8 +519,8 @@ struct AtomicAnalysis {
519519
/// function references with scalar data pointer result of non-character
520520
/// intrinsic type or variables that are non-polymorphic scalar pointers
521521
/// and any length type parameter must be constant.
522-
void OmpStructureChecker::CheckAtomicType(
523-
SymbolRef sym, parser::CharBlock source, std::string_view name) {
522+
void OmpStructureChecker::CheckAtomicType(SymbolRef sym,
523+
parser::CharBlock source, std::string_view name, bool checkTypeOnPointer) {
524524
const DeclTypeSpec *typeSpec{sym->GetType()};
525525
if (!typeSpec) {
526526
return;
@@ -547,6 +547,22 @@ void OmpStructureChecker::CheckAtomicType(
547547
return;
548548
}
549549

550+
// Apply pointer-to-non-intrinsic rule only for intrinsic-assignment paths.
551+
if (checkTypeOnPointer) {
552+
using Category = DeclTypeSpec::Category;
553+
Category cat{typeSpec->category()};
554+
if (cat != Category::Numeric && cat != Category::Logical) {
555+
std::string details = " has the POINTER attribute";
556+
if (const auto *derived{typeSpec->AsDerived()}) {
557+
details += " and derived type '"s + derived->name().ToString() + "'";
558+
}
559+
context_.Say(source,
560+
"ATOMIC operation requires an intrinsic scalar variable; '%s'%s"_err_en_US,
561+
sym->name(), details);
562+
return;
563+
}
564+
}
565+
550566
// Go over all length parameters, if any, and check if they are
551567
// explicit.
552568
if (const DerivedTypeSpec *derived{typeSpec->AsDerived()}) {
@@ -562,7 +578,7 @@ void OmpStructureChecker::CheckAtomicType(
562578
}
563579

564580
void OmpStructureChecker::CheckAtomicVariable(
565-
const SomeExpr &atom, parser::CharBlock source) {
581+
const SomeExpr &atom, parser::CharBlock source, bool checkTypeOnPointer) {
566582
if (atom.Rank() != 0) {
567583
context_.Say(source, "Atomic variable %s should be a scalar"_err_en_US,
568584
atom.AsFortran());
@@ -572,7 +588,7 @@ void OmpStructureChecker::CheckAtomicVariable(
572588
assert(dsgs.size() == 1 && "Should have a single top-level designator");
573589
evaluate::SymbolVector syms{evaluate::GetSymbolVector(dsgs.front())};
574590

575-
CheckAtomicType(syms.back(), source, atom.AsFortran());
591+
CheckAtomicType(syms.back(), source, atom.AsFortran(), checkTypeOnPointer);
576592

577593
if (IsAllocatable(syms.back()) && !IsArrayElement(atom)) {
578594
context_.Say(source, "Atomic variable %s cannot be ALLOCATABLE"_err_en_US,
@@ -789,7 +805,8 @@ void OmpStructureChecker::CheckAtomicCaptureAssignment(
789805
if (!IsVarOrFunctionRef(atom)) {
790806
ErrorShouldBeVariable(atom, rsrc);
791807
} else {
792-
CheckAtomicVariable(atom, rsrc);
808+
CheckAtomicVariable(
809+
atom, rsrc, /*checkTypeOnPointer=*/!IsPointerAssignment(capture));
793810
// This part should have been checked prior to calling this function.
794811
assert(*GetConvertInput(capture.rhs) == atom &&
795812
"This cannot be a capture assignment");
@@ -808,7 +825,8 @@ void OmpStructureChecker::CheckAtomicReadAssignment(
808825
if (!IsVarOrFunctionRef(atom)) {
809826
ErrorShouldBeVariable(atom, rsrc);
810827
} else {
811-
CheckAtomicVariable(atom, rsrc);
828+
CheckAtomicVariable(
829+
atom, rsrc, /*checkTypeOnPointer=*/!IsPointerAssignment(read));
812830
CheckStorageOverlap(atom, {read.lhs}, source);
813831
}
814832
} else {
@@ -829,7 +847,8 @@ void OmpStructureChecker::CheckAtomicWriteAssignment(
829847
if (!IsVarOrFunctionRef(atom)) {
830848
ErrorShouldBeVariable(atom, rsrc);
831849
} else {
832-
CheckAtomicVariable(atom, lsrc);
850+
CheckAtomicVariable(
851+
atom, lsrc, /*checkTypeOnPointer=*/!IsPointerAssignment(write));
833852
CheckStorageOverlap(atom, {write.rhs}, source);
834853
}
835854
}
@@ -854,7 +873,8 @@ OmpStructureChecker::CheckAtomicUpdateAssignment(
854873
return std::nullopt;
855874
}
856875

857-
CheckAtomicVariable(atom, lsrc);
876+
CheckAtomicVariable(
877+
atom, lsrc, /*checkTypeOnPointer=*/!IsPointerAssignment(update));
858878

859879
auto [hasErrors, tryReassoc]{CheckAtomicUpdateAssignmentRhs(
860880
atom, update.rhs, source, /*suppressDiagnostics=*/true)};
@@ -1017,7 +1037,8 @@ void OmpStructureChecker::CheckAtomicConditionalUpdateAssignment(
10171037
return;
10181038
}
10191039

1020-
CheckAtomicVariable(atom, alsrc);
1040+
CheckAtomicVariable(
1041+
atom, alsrc, /*checkTypeOnPointer=*/!IsPointerAssignment(assign));
10211042

10221043
auto top{GetTopLevelOperationIgnoreResizing(cond)};
10231044
// Missing arguments to operations would have been diagnosed by now.

flang/lib/Semantics/check-omp-structure.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,10 @@ class OmpStructureChecker
262262
void CheckStorageOverlap(const evaluate::Expr<evaluate::SomeType> &,
263263
llvm::ArrayRef<evaluate::Expr<evaluate::SomeType>>, parser::CharBlock);
264264
void ErrorShouldBeVariable(const MaybeExpr &expr, parser::CharBlock source);
265-
void CheckAtomicType(
266-
SymbolRef sym, parser::CharBlock source, std::string_view name);
267-
void CheckAtomicVariable(
268-
const evaluate::Expr<evaluate::SomeType> &, parser::CharBlock);
265+
void CheckAtomicType(SymbolRef sym, parser::CharBlock source,
266+
std::string_view name, bool checkTypeOnPointer = true);
267+
void CheckAtomicVariable(const evaluate::Expr<evaluate::SomeType> &,
268+
parser::CharBlock, bool checkTypeOnPointer = true);
269269
std::pair<const parser::ExecutionPartConstruct *,
270270
const parser::ExecutionPartConstruct *>
271271
CheckUpdateCapture(const parser::ExecutionPartConstruct *ec1,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
! RUN: not %flang_fc1 -fopenmp -fsyntax-only %s 2>&1 | FileCheck %s
2+
type t
3+
end type
4+
type(t), pointer :: a1, a2
5+
!$omp atomic write
6+
a1 = a2
7+
! CHECK: error: ATOMIC operation requires an intrinsic scalar variable; 'a1' has the POINTER attribute and derived type 't'
8+
end

0 commit comments

Comments
 (0)