[flang-commits] [flang] fa1857e - [flang][cuda] Reject DEVICE derived types with attributed allocatable components (#220411)

via flang-commits flang-commits at lists.llvm.org
Thu Sep 3 11:46:01 PDT 2026


Author: Valentin Clement (バレンタイン クレメン)
Date: 2026-09-03T11:45:55-07:00
New Revision: fa1857e0ef5575c8472d0b0f59661d811e03f09a

URL: https://github.com/llvm/llvm-project/commit/fa1857e0ef5575c8472d0b0f59661d811e03f09a
DIFF: https://github.com/llvm/llvm-project/commit/fa1857e0ef5575c8472d0b0f59661d811e03f09a.diff

LOG: [flang][cuda] Reject DEVICE derived types with attributed allocatable components (#220411)

CUDA attributed allocatables are allocated from the host in most case
(PINNED, MANAGED, UNIFIED). A DEVICE derived-type object keeps its
component descriptors in device global memory, so allocating such a
component is not valid. It's also invalid for a DEVICE component unless
the allocate statement is in device context.

Added: 
    flang/test/Semantics/CUDA/cuf32.cuf

Modified: 
    flang/lib/Semantics/check-allocate.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/check-allocate.cpp b/flang/lib/Semantics/check-allocate.cpp
index 2ac242abd5788..4bbc652f6f9cd 100644
--- a/flang/lib/Semantics/check-allocate.cpp
+++ b/flang/lib/Semantics/check-allocate.cpp
@@ -12,6 +12,7 @@
 #include "flang/Evaluate/fold.h"
 #include "flang/Evaluate/shape.h"
 #include "flang/Evaluate/type.h"
+#include "flang/Parser/characters.h"
 #include "flang/Parser/parse-tree.h"
 #include "flang/Parser/tools.h"
 #include "flang/Semantics/attr.h"
@@ -715,6 +716,32 @@ bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) {
           "Object in ALLOCATE must have DEVICE attribute when STREAM option is specified"_err_en_US);
     }
   }
+  if (const auto *component{
+          std::get_if<parser::StructureComponent>(&allocateObject_.u)}) {
+    // The descriptors of a DEVICE object live in device global memory, so a
+    // component of one can only be allocated where they are addressable.
+    const auto *details{ultimate_->detailsIf<ObjectEntityDetails>()};
+    std::optional<common::CUDADataAttr> attr{
+        details ? details->cudaDataAttr() : std::nullopt};
+    const parser::Name &base{parser::GetFirstName(*component)};
+    if (attr && base.symbol && IsCUDADevice(*base.symbol)) {
+      if (*attr == common::CUDADataAttr::Pinned ||
+          *attr == common::CUDADataAttr::Managed ||
+          *attr == common::CUDADataAttr::Unified) {
+        // These allocatables are placed in host-accessible memory, so their
+        // descriptors have to be host accessible too.
+        context.Say(name_.source,
+            "%s allocatable component '%s' must not be allocated in DEVICE object '%s'"_err_en_US,
+            parser::ToUpperCaseLetters(common::EnumToString(*attr)),
+            name_.source, base.source);
+      } else if (*attr == common::CUDADataAttr::Device &&
+          !FindCUDADeviceContext(&context.FindScope(name_.source))) {
+        context.Say(name_.source,
+            "DEVICE allocatable component '%s' of DEVICE object '%s' may only be allocated in a device subprogram"_err_en_US,
+            name_.source, base.source);
+      }
+    }
+  }
 
   if (const SomeExpr *allocObj{GetExpr(context, allocateObject_)}) {
     if (AreSameAllocation(allocObj, allocateInfo_.statVar)) {

diff  --git a/flang/test/Semantics/CUDA/cuf32.cuf b/flang/test/Semantics/CUDA/cuf32.cuf
new file mode 100644
index 0000000000000..a012b2e71c476
--- /dev/null
+++ b/flang/test/Semantics/CUDA/cuf32.cuf
@@ -0,0 +1,123 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1
+! The descriptors of a DEVICE object live in device global memory, so a
+! component of one can only be allocated where they are addressable.
+module m
+  type :: t
+    integer(4), allocatable, pinned :: pc(:)
+    integer(4), allocatable, managed :: mc(:)
+    integer(4), allocatable, unified :: uc(:)
+  end type
+  type :: inner_alloc
+    type(t), allocatable :: x
+  end type
+  type :: td
+    integer(4), allocatable, device :: dc(:)
+  end type
+
+  type(t), device :: mds(10)
+
+contains
+  ! PINNED, MANAGED, and UNIFIED allocatables are placed in host-accessible
+  ! memory, so such a component of a DEVICE object may never be allocated.
+  subroutine test_device_derived_host_mem_components()
+    type(t), allocatable, device :: d(:)
+    type(t), device :: ds(10)
+    type(t), allocatable :: h(:)
+    type(t), allocatable, managed :: md(:)
+    type(inner_alloc), allocatable, device :: nest(:)
+    integer :: n, i
+    n = 2
+    i = 1
+
+    allocate(h(n))
+    allocate(h(i)%pc(3))
+    allocate(h(i)%mc(3))
+    allocate(h(i)%uc(3))
+    h(i)%pc = 10
+
+    allocate(md(n))
+    allocate(md(i)%pc(3))
+    allocate(md(i)%mc(3))
+    allocate(md(i)%uc(3))
+
+    allocate(d(n))
+    !ERROR: PINNED allocatable component 'pc' must not be allocated in DEVICE object 'd'
+    allocate(d(i)%pc(3))
+    !ERROR: MANAGED allocatable component 'mc' must not be allocated in DEVICE object 'd'
+    allocate(d(i)%mc(3))
+    !ERROR: UNIFIED allocatable component 'uc' must not be allocated in DEVICE object 'd'
+    allocate(d(i)%uc(3))
+
+    !ERROR: PINNED allocatable component 'pc' must not be allocated in DEVICE object 'ds'
+    allocate(ds(i)%pc(3))
+    !ERROR: MANAGED allocatable component 'mc' must not be allocated in DEVICE object 'ds'
+    allocate(ds(i)%mc(3))
+    !ERROR: UNIFIED allocatable component 'uc' must not be allocated in DEVICE object 'ds'
+    allocate(ds(i)%uc(3))
+
+    !ERROR: PINNED allocatable component 'pc' must not be allocated in DEVICE object 'mds'
+    allocate(mds(i)%pc(3))
+    !ERROR: MANAGED allocatable component 'mc' must not be allocated in DEVICE object 'mds'
+    allocate(mds(i)%mc(3))
+    !ERROR: UNIFIED allocatable component 'uc' must not be allocated in DEVICE object 'mds'
+    allocate(mds(i)%uc(3))
+
+    allocate(nest(n))
+    allocate(nest(i)%x)
+    !ERROR: PINNED allocatable component 'pc' must not be allocated in DEVICE object 'nest'
+    allocate(nest(i)%x%pc(3))
+    !ERROR: MANAGED allocatable component 'mc' must not be allocated in DEVICE object 'nest'
+    allocate(nest(i)%x%mc(3))
+    !ERROR: UNIFIED allocatable component 'uc' must not be allocated in DEVICE object 'nest'
+    allocate(nest(i)%x%uc(3))
+  end subroutine
+
+  subroutine host_ok(h)
+    type(t), intent(inout) :: h(:)
+    allocate(h(1)%pc(3))
+    allocate(h(1)%mc(3))
+    allocate(h(1)%uc(3))
+  end subroutine
+
+  subroutine dummy_device(d)
+    type(t), device :: d(:)
+    !ERROR: PINNED allocatable component 'pc' must not be allocated in DEVICE object 'd'
+    allocate(d(1)%pc(3))
+    !ERROR: MANAGED allocatable component 'mc' must not be allocated in DEVICE object 'd'
+    allocate(d(1)%mc(3))
+    !ERROR: UNIFIED allocatable component 'uc' must not be allocated in DEVICE object 'd'
+    allocate(d(1)%uc(3))
+  end subroutine
+
+  ! A DEVICE component of a DEVICE object may only be allocated from device
+  ! code, where the device-resident descriptor can be updated.
+  subroutine test_device_derived_device_component()
+    type(td), device :: dd(10)
+    type(td), allocatable, device :: ad(:)
+    type(td) :: h
+    type(td), allocatable, managed :: md(:)
+    integer :: i
+    i = 1
+
+    ! Allocating a DEVICE component of a host or MANAGED object is fine.
+    allocate(h%dc(3))
+    allocate(md(2))
+    allocate(md(i)%dc(3))
+
+    !ERROR: DEVICE allocatable component 'dc' of DEVICE object 'dd' may only be allocated in a device subprogram
+    allocate(dd(i)%dc(3))
+    allocate(ad(2))
+    !ERROR: DEVICE allocatable component 'dc' of DEVICE object 'ad' may only be allocated in a device subprogram
+    allocate(ad(i)%dc(3))
+  end subroutine
+
+  attributes(global) subroutine global_ok(dd)
+    type(td), device :: dd(:)
+    allocate(dd(1)%dc(3))
+  end subroutine
+
+  attributes(device) subroutine device_ok(dd)
+    type(td), device :: dd(:)
+    allocate(dd(1)%dc(3))
+  end subroutine
+end module


        


More information about the flang-commits mailing list