[flang-commits] [flang] [flang][CUDA] Preserve data attrs on assignment RHS (PR #207849)

Andre Kuhlenschmidt via flang-commits flang-commits at lists.llvm.org
Wed Jul 8 17:10:07 PDT 2026


https://github.com/akuhlens updated https://github.com/llvm/llvm-project/pull/207849

>From 399739ffead78424596b0b112b305e9217da255c Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Thu, 2 Jul 2026 17:49:01 -0700
Subject: [PATCH] [flang][CUDA] Preserve data attrs on assignment RHS

Treat a parenthesized variable as a source of CUDA data attributes when checking dummy/actual argument compatibility. Defined assignment parenthesizes non-VALUE RHS actuals to preserve value semantics, but the CUDA address space of the referenced data is unchanged by that materialization.

Add CUDA semantics coverage for a device RHS selected through defined assignment.
---
 flang/lib/Semantics/check-call.cpp            | 35 ++++++++++++++++++-
 .../CUDA/cuf-defined-assignment-rhs.cuf       | 34 ++++++++++++++++++
 2 files changed, 68 insertions(+), 1 deletion(-)
 create mode 100644 flang/test/Semantics/CUDA/cuf-defined-assignment-rhs.cuf

diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index 16c1e166ded66..060459ea0d495 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -27,6 +27,37 @@ namespace characteristics = Fortran::evaluate::characteristics;
 
 namespace Fortran::semantics {
 
+template <typename A> static bool IsParenthesizedVariable(const A &) {
+  return false;
+}
+
+template <typename T>
+static bool IsParenthesizedVariable(const evaluate::Expr<T> &expr) {
+  if (const auto *parens{
+          evaluate::UnwrapExpr<evaluate::Parentheses<T>>(expr)}) {
+    return evaluate::IsVariable(parens->left());
+  }
+  return false;
+}
+
+template <evaluate::TypeCategory CAT>
+static bool IsParenthesizedVariable(
+    const evaluate::Expr<evaluate::SomeKind<CAT>> &expr) {
+  return common::visit(
+      [](const auto &x) { return IsParenthesizedVariable(x); }, expr.u);
+}
+
+static bool IsParenthesizedVariable(
+    const evaluate::Expr<evaluate::SomeType> &expr) {
+  return common::visit(
+      [](const auto &x) { return IsParenthesizedVariable(x); }, expr.u);
+}
+
+static bool IsVariableOrParenthesizedVariable(
+    const evaluate::Expr<evaluate::SomeType> &expr) {
+  return evaluate::IsVariable(expr) || IsParenthesizedVariable(expr);
+}
+
 void CheckImplicitInterfaceArgKeywords(
     const evaluate::ActualArgument &arg, parser::ContextualMessages &messages) {
   auto restorer{
@@ -1124,7 +1155,9 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
       !FindOpenACCConstructContaining(scope)) {
     std::optional<common::CUDADataAttr> actualDataAttr, dummyDataAttr;
     // For a%b%c, the last symbol with a CUDA data attribute wins
-    if (actualIsVariable) {
+    // Parentheses here mean expression/copy semantics, but CUDA address space
+    // attributes remain stable when a variable is materialized as a copy.
+    if (IsVariableOrParenthesizedVariable(actual)) {
       for (const Symbol &s : evaluate::GetSymbolVector(actual)) {
         if (const auto *object{s.detailsIf<ObjectEntityDetails>()}) {
           if (auto cudaAttr{object->cudaDataAttr()}) {
diff --git a/flang/test/Semantics/CUDA/cuf-defined-assignment-rhs.cuf b/flang/test/Semantics/CUDA/cuf-defined-assignment-rhs.cuf
new file mode 100644
index 0000000000000..bd0ab5f7c3068
--- /dev/null
+++ b/flang/test/Semantics/CUDA/cuf-defined-assignment-rhs.cuf
@@ -0,0 +1,34 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1
+
+module m
+  type box
+    integer :: n
+  end type
+
+  interface assignment(=)
+    module procedure assign_host
+    module procedure assign_device
+  end interface
+
+contains
+  subroutine assign_host(lhs, rhs)
+    type(box), intent(inout) :: lhs
+    real, intent(in) :: rhs(:)
+  end subroutine
+
+  subroutine assign_device(lhs, rhs)
+    type(box), intent(inout) :: lhs
+    real, device, intent(in) :: rhs(:)
+  end subroutine
+end module
+
+subroutine test
+  use m
+  type(box) :: lhs
+  real :: host(4)
+  real, device, allocatable :: dev(:)
+  allocate(dev(4))
+
+  lhs = host
+  lhs = dev
+end subroutine



More information about the flang-commits mailing list