Skip to content

Conversation

@KrxGu
Copy link
Contributor

@KrxGu KrxGu commented Oct 7, 2025

Fixes #161932

Problem

When using !$omp atomic write with a POINTER variable to a derived type in intrinsic assignment, Flang would crash with a FIR verifier error instead of providing a clear semantic diagnostic.

Example that previously crashed:

module p
    type t
    end type
    contains
    subroutine s(a1, a2)
        type(t), pointer :: a1, a2
        !$omp atomic write
        a1 = a2  ! Crashed with FIR verifier error
    end subroutine
end module

Solution
Added a semantic check in CheckAtomicWriteAssignment() that detects when:

The assignment is an intrinsic assignment (not pointer assignment =>)
The variable has the POINTER attribute
The pointee type is non-intrinsic (derived type, character, etc.)
The check now emits a clear error message before reaching the FIR stage:
error: ATOMIC WRITE requires an intrinsic scalar variable; 'a1' has the POINTER attribute and derived type 't'

image

What remains valid
According to OpenMP 6.0 spec, the following cases are still allowed:

✅ integer, pointer :: p; p = 5 - pointer to intrinsic type with intrinsic assignment
✅ integer, pointer :: p, q; p => q - pointer assignment
✅ type(t), pointer :: a, b; a => b - pointer assignment with derived type
What is now rejected
❌ type(t), pointer :: a, b; a = b - intrinsic assignment where the dereferenced value is non-intrinsic

Testing
All existing atomic tests pass (15/15)
New test validates the error diagnostic
Verified the original crash scenario now produces a clear error instead

image

@llvmbot llvmbot added flang Flang issues not falling into any other category flang:openmp flang:semantics labels Oct 7, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 7, 2025

@llvm/pr-subscribers-flang-semantics

@llvm/pr-subscribers-flang-openmp

Author: Krish Gupta (KrxGu)

Changes

Fixes #161932

Problem

When using !$omp atomic write with a POINTER variable to a derived type in intrinsic assignment, Flang would crash with a FIR verifier error instead of providing a clear semantic diagnostic.

Example that previously crashed:

module p
    type t
    end type
    contains
    subroutine s(a1, a2)
        type(t), pointer :: a1, a2
        !$omp atomic write
        a1 = a2  ! Crashed with FIR verifier error
    end subroutine
end module

Solution
Added a semantic check in CheckAtomicWriteAssignment() that detects when:

The assignment is an intrinsic assignment (not pointer assignment =>)
The variable has the POINTER attribute
The pointee type is non-intrinsic (derived type, character, etc.)
The check now emits a clear error message before reaching the FIR stage:
error: ATOMIC WRITE requires an intrinsic scalar variable; 'a1' has the POINTER attribute and derived type 't'

<img width="1234" height="214" alt="image" src="https://github.com/user-attachments/assets/1067148f-3734-4a39-913b-df37f0e38b0f" />

What remains valid
According to OpenMP 6.0 spec, the following cases are still allowed:

✅ integer, pointer :: p; p = 5 — pointer to intrinsic type with intrinsic assignment
✅ integer, pointer :: p, q; p => q — pointer assignment
✅ type(t), pointer :: a, b; a => b — pointer assignment with derived type
What is now rejected
❌ type(t), pointer :: a, b; a = b — intrinsic assignment where the dereferenced value is non-intrinsic

Testing
All existing atomic tests pass (15/15)
New test validates the error diagnostic
Verified the original crash scenario now produces a clear error instead

<img width="1180" height="364" alt="image" src="https://github.com/user-attachments/assets/3740f431-cd1a-4cb9-b58c-ad97f17fa52c" />


Full diff: https://github.com/llvm/llvm-project/pull/162364.diff

3 Files Affected:

  • (modified) flang/lib/Semantics/check-omp-atomic.cpp (+25-1)
  • (added) flang/test/Semantics/OpenMP/omp-atomic-write-pointer-derived.f90 (+8)
  • (added) flang/test/Semantics/OpenMP/omp-common-fp-lp.f90 (+13)
diff --git a/flang/lib/Semantics/check-omp-atomic.cpp b/flang/lib/Semantics/check-omp-atomic.cpp
index 351af5c099aee..00c6a2d2b5fe3 100644
--- a/flang/lib/Semantics/check-omp-atomic.cpp
+++ b/flang/lib/Semantics/check-omp-atomic.cpp
@@ -539,7 +539,6 @@ void OmpStructureChecker::CheckAtomicType(
     return;
   }
 
-  // Variable is a pointer.
   if (typeSpec->IsPolymorphic()) {
     context_.Say(source,
         "Atomic variable %s cannot be a pointer to a polymorphic type"_err_en_US,
@@ -829,6 +828,31 @@ void OmpStructureChecker::CheckAtomicWriteAssignment(
   if (!IsVarOrFunctionRef(atom)) {
     ErrorShouldBeVariable(atom, rsrc);
   } else {
+    // For intrinsic assignment (x = expr), check if the variable is a pointer
+    // to a non-intrinsic type, which is not allowed in ATOMIC WRITE
+    if (!IsPointerAssignment(write)) {
+      std::vector<SomeExpr> dsgs{GetAllDesignators(atom)};
+      if (!dsgs.empty()) {
+        evaluate::SymbolVector syms{evaluate::GetSymbolVector(dsgs.front())};
+        if (!syms.empty() && IsPointer(syms.back())) {
+          SymbolRef sym = syms.back();
+          if (const DeclTypeSpec *typeSpec{sym->GetType()}) {
+            using Category = DeclTypeSpec::Category;
+            Category cat{typeSpec->category()};
+            if (cat != Category::Numeric && cat != Category::Logical) {
+              std::string details = " has the POINTER attribute";
+              if (const auto *derived{typeSpec->AsDerived()}) {
+                details += " and derived type '"s + derived->name().ToString() + "'";
+              }
+              context_.Say(lsrc,
+                  "ATOMIC WRITE requires an intrinsic scalar variable; '%s'%s"_err_en_US,
+                  sym->name(), details);
+              return;
+            }
+          }
+        }
+      }
+    }
     CheckAtomicVariable(atom, lsrc);
     CheckStorageOverlap(atom, {write.rhs}, source);
   }
diff --git a/flang/test/Semantics/OpenMP/omp-atomic-write-pointer-derived.f90 b/flang/test/Semantics/OpenMP/omp-atomic-write-pointer-derived.f90
new file mode 100644
index 0000000000000..d1ca2308047ad
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/omp-atomic-write-pointer-derived.f90
@@ -0,0 +1,8 @@
+! RUN: not %flang_fc1 -fopenmp -fsyntax-only %s 2>&1 | FileCheck %s
+type t
+end type
+type(t), pointer :: a1, a2
+!$omp atomic write
+a1 = a2
+! CHECK: error: ATOMIC WRITE requires an intrinsic scalar variable; 'a1' has the POINTER attribute and derived type 't'
+end
diff --git a/flang/test/Semantics/OpenMP/omp-common-fp-lp.f90 b/flang/test/Semantics/OpenMP/omp-common-fp-lp.f90
new file mode 100644
index 0000000000000..3d6ba1547a09e
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/omp-common-fp-lp.f90
@@ -0,0 +1,13 @@
+! RUN: %flang_fc1 -fopenmp -fsyntax-only %s 2>&1 | FileCheck %s --allow-empty
+! CHECK-NOT: error:
+! CHECK-NOT: warning:
+
+subroutine sub1()
+  common /com/ j
+  j = 10
+!$omp parallel do firstprivate(j) lastprivate(/com/)
+  do i = 1, 10
+     j = j + 1
+  end do
+!$omp end parallel do
+end

@github-actions
Copy link

github-actions bot commented Oct 7, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@KrxGu KrxGu force-pushed the flang-omp-atomic-write-diag branch 2 times, most recently from 40781a0 to 28e3606 Compare October 7, 2025 20:25
@@ -539,7 +539,6 @@ void OmpStructureChecker::CheckAtomicType(
return;
}

// Variable is a pointer.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated change

@@ -829,6 +828,32 @@ void OmpStructureChecker::CheckAtomicWriteAssignment(
if (!IsVarOrFunctionRef(atom)) {
ErrorShouldBeVariable(atom, rsrc);
} else {
// For intrinsic assignment (x = expr), check if the variable is a pointer
// to a non-intrinsic type, which is not allowed in ATOMIC WRITE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't specific to WRITE. It should be checked in CheckAtomicType.

@kparzysz
Copy link
Contributor

kparzysz commented Oct 7, 2025

If you want to work on an issue that is already assigned to someone, at least let them know.

@KrxGu
Copy link
Contributor Author

KrxGu commented Oct 7, 2025

If you want to work on an issue that is already assigned to someone, at least let them know.

Hi @kparzysz — apologies for the oversight🙏. I missed that this was already self-assigned to you. I’ll make sure to check assignments and coordinate with the assignee before picking up work in the future.

I’ve opened #162364 with a semantics fix and tests. If you feel it addresses the issue, please go ahead and merge it. If there are minor changes needed, I’m happy to make them quickly. Otherwise, if it’s not up to the mark or conflicts with your approach, I can close the PR. Your call, and thank you for the guidance.

@kparzysz
Copy link
Contributor

Did you miss my first review comment by any chance?

@KrxGu KrxGu force-pushed the flang-omp-atomic-write-diag branch from 28e3606 to 022dd65 Compare October 12, 2025 05:57
@KrxGu
Copy link
Contributor Author

KrxGu commented Oct 12, 2025

Did you miss my first review comment by any chance?

Thank you for the feedback! I've addressed both of your comments:

  1. Unrelated change: The deleted comment has been restored.
  2. Centralization: I've moved the pointer-to-non-intrinsic check to a centralized location. Instead of modifying [CheckAtomicType](which doesn't have assignment context), I created an overload of [CheckAtomicVariable] that accepts the assignment parameter. This overload is now called by all atomic operations (WRITE, UPDATE, READ, CAPTURE, and CONDITIONAL UPDATE), ensuring the check applies universally.

The changes have been tested and all atomic operations now correctly detect pointers to non-intrinsic types.
image

@KrxGu
Copy link
Contributor Author

KrxGu commented Oct 12, 2025

Updated the FileCheck pattern to match the generic “ATOMIC operation …” diagnostic emitted from the centralized checker. The test remains a negative case for intrinsic assignment to a pointer-to-derived.

CI all green, @kparzysz. good to merge!!

@kparzysz
Copy link
Contributor

This looks good! I have a suggestion:

Remove the CheckAtomicVariable overload, instead add a parameter e.g. "bool CheckTypeOnPointer = true". Pass "!IsPointerAssignment(...)" at the call sites where needed. Add the same parameter to CheckAtomicType and pass it from CheckAtomicVariable. Then put the actual check into CheckAtomicType.

This way the checks are done where they logically belong.

@KrxGu KrxGu force-pushed the flang-omp-atomic-write-diag branch from 6a88852 to 65472a5 Compare October 14, 2025 20:12
@KrxGu
Copy link
Contributor Author

KrxGu commented Oct 14, 2025

This looks good! I have a suggestion:

Remove the CheckAtomicVariable overload, instead add a parameter e.g. "bool CheckTypeOnPointer = true". Pass "!IsPointerAssignment(...)" at the call sites where needed. Add the same parameter to CheckAtomicType and pass it from CheckAtomicVariable. Then put the actual check into CheckAtomicType.

This way the checks are done where they logically belong.

Thank you for the feedback! I've implemented your suggestions:

  1. Removed the overload - Deleted the CheckAtomicVariable(atom, source, assign) overload
  2. Added bool parameter - Added bool checkTypeOnPointer = true to both CheckAtomicVariable and CheckAtomicType
  3. Updated call sites - All atomic assignment functions now pass !IsPointerAssignment(...) to control the check:
    • CheckAtomicWriteAssignment
    • CheckAtomicReadAssignment
    • CheckAtomicCaptureAssignment
    • CheckAtomicUpdateAssignment
    • CheckAtomicConditionalUpdateAssignment
  4. Moved logic to CheckAtomicType - The pointer-to-non-intrinsic check now lives in CheckAtomicType, guarded by the checkTypeOnPointer flag

The check now applies uniformly to all atomic operations while properly excluding pointer assignments (=>). Tests pass locally with the updated implementation.

@kparzysz CI is all green, good to merge!!

@kparzysz
Copy link
Contributor

The commit message is too verbose, plus it contains outdated information. I plan to reduce it when merging. Let me know if you're ok with the text below.


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 (=>).

@KrxGu
Copy link
Contributor Author

KrxGu commented Oct 15, 2025

The commit message is too verbose, plus it contains outdated information. I plan to reduce it when merging. Let me know if you're ok with the text below.

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 (=>).

@kparzysz Yes, SGTM - please go ahead with your version of the commit message. I appreciate you cleaning it up!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:openmp flang:semantics flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Flang][OpenMP] verification of lowering to FIR failed on omp atomic write with pointer assignment to derived type

3 participants