[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