[flang-commits] [flang] [Flang][OpenMP] Permit THREADPRIVATE variables in EQUIVALENCE statements (PR #186696)

Michael Klemm via flang-commits flang-commits at lists.llvm.org
Thu Mar 19 05:27:27 PDT 2026


https://github.com/mjklemm updated https://github.com/llvm/llvm-project/pull/186696

>From 3cc8fc5d8f49e5b916d4b621a1e40b6518203012 Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Sun, 15 Mar 2026 19:49:04 +0100
Subject: [PATCH 1/9] [Flang][OpenMP} Permit THREADPRIVATE variables in
 EQUIVALENCE statements

The OpenMP API does not allow to have THREADPRIVATE variable appear in
an EQUIVALENCE statement.  It has been requested by the community to
extend Flang such that it permits these non-conforming patterns.  This
PR changes Flang to inherit the DSA of the base object of the
EQUIVALENCE statement to the equivalenced variables.  The orginal error
message is turned into a warning.

Fixes https://github.com/llvm/llvm-project/issues/180493

Assisted-by: Claude Code, Opus 4.6
---
 flang/lib/Semantics/check-omp-structure.cpp   |  5 +++-
 flang/lib/Semantics/resolve-directives.cpp    | 30 +++++++++++++++++++
 .../OpenMP/threadprivate-equivalence.f90      | 19 ++++++++++++
 .../test/Semantics/OpenMP/threadprivate02.f90 |  3 +-
 4 files changed, 55 insertions(+), 2 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/threadprivate-equivalence.f90

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 431c41f443f7a..44f8d46862ba3 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1364,8 +1364,11 @@ void OmpStructureChecker::CheckThreadprivateOrDeclareTargetVar(
     for (const auto &obj : cb->objects()) {
       if (FindEquivalenceSet(*obj)) {
         context_.Say(name.source,
-            "A variable in a %s directive cannot appear in an EQUIVALENCE statement (variable '%s' from common block '/%s/')"_err_en_US,
+            "A variable in a %s directive used in an EQUIVALENCE statement is "
+            "an OpenMP extension (variable '%s' from common block "
+            "'/%s/')"_warn_en_US,
             ContextDirectiveAsFortran(), obj->name(), name.symbol->name());
+        fprintf(stderr, "--> %s\n", name.ToString().c_str());
       }
     }
   }
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index c8ffa22d6bb5f..0b5c776946df5 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1115,6 +1115,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
   Symbol *ResolveOmpCommonBlockName(const parser::Name *);
   void ResolveOmpNameList(const std::list<parser::Name> &, Symbol::Flag);
   void ResolveOmpName(const parser::Name &, Symbol::Flag);
+  void PropagateOmpFlagToEquivalenceSet(const Symbol &, Symbol::Flag);
   Symbol *ResolveName(const parser::Name *);
   Symbol *DeclareOrMarkOtherAccessEntity(const parser::Name &, Symbol::Flag);
   Symbol *DeclareOrMarkOtherAccessEntity(Symbol &, Symbol::Flag);
@@ -3243,6 +3244,30 @@ void OmpAttributeVisitor::ResolveOmpDesignator(
   }
 }
 
+void OmpAttributeVisitor::PropagateOmpFlagToEquivalenceSet(
+    const Symbol &symbol, Symbol::Flag ompFlag) {
+  // Find the equivalence set containing this symbol
+  if (const EquivalenceSet *eqSet = FindEquivalenceSet(symbol)) {
+    // Propagate the flag to all symbols in the equivalence set
+    for (const EquivalenceObject &eqObj : *eqSet) {
+      Symbol &eqSymbol = eqObj.symbol;
+
+      // Skip the symbol itself (already has the flag)
+      if (&eqSymbol == &symbol) {
+        continue;
+      }
+
+      // Set the OpenMP flag on the equivalenced symbol
+      if (Symbol * resolvedSymbol{ResolveOmp(eqSymbol, ompFlag, currScope())}) {
+        // Also add to the context if needed
+        if (ompFlagsRequireMark.test(ompFlag)) {
+          AddToContextObjectWithExplicitDSA(*resolvedSymbol, ompFlag);
+        }
+      }
+    }
+  }
+}
+
 void OmpAttributeVisitor::ResolveOmpCommonBlock(
     const parser::Name &name, Symbol::Flag ompFlag) {
   if (auto *symbol{ResolveOmpCommonBlockName(&name)}) {
@@ -3261,6 +3286,11 @@ void OmpAttributeVisitor::ResolveOmpCommonBlock(
           AddToContextObjectWithExplicitDSA(*resolvedObject, ompFlag);
         }
         details.replace_object(*resolvedObject, index);
+
+        // Propagate the flag to symbols in the equivalence set
+        if (ompFlagsRequireMark.test(ompFlag)) {
+          PropagateOmpFlagToEquivalenceSet(*resolvedObject, ompFlag);
+        }
       }
     }
   } else {
diff --git a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90 b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
new file mode 100644
index 0000000000000..8896697c8812a
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
@@ -0,0 +1,19 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+! OpenMP Version 5.1
+! Check OpenMP construct validity for the following directives:
+! 2.21.2 Threadprivate Directive
+
+program threadprivate02
+  common /blk1/ a1
+  real :: a1
+  real :: eq_a
+  equivalence(eq_a, a1)
+
+  ! This is an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
+  !WARNING: A variable in a THREADPRIVATE directive used in an EQUIVALENCE statement is an OpenMP extension (variable 'a1' from common block '/blk1/')
+  !$omp threadprivate(/blk1/)
+
+  !ERROR: A THREADPRIVATE variable cannot be in SHARED clause
+  !$omp parallel shared(eq_a)
+  !$omp end parallel
+end
\ No newline at end of file
diff --git a/flang/test/Semantics/OpenMP/threadprivate02.f90 b/flang/test/Semantics/OpenMP/threadprivate02.f90
index 9dc031a8ce47e..fbbabc4319259 100644
--- a/flang/test/Semantics/OpenMP/threadprivate02.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate02.f90
@@ -28,7 +28,8 @@ program threadprivate02
   !$omp threadprivate(eq_c)
   equivalence(eq_c, eq_d)
 
-  !ERROR: A variable in a THREADPRIVATE directive cannot appear in an EQUIVALENCE statement (variable 'eq_e' from common block '/blk2/')
+  ! This is an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
+  !WARNING: A variable in a THREADPRIVATE directive used in an EQUIVALENCE statement is an OpenMP extension (variable 'eq_e' from common block '/blk2/')
   !$omp threadprivate(/blk2/)
 
 contains

>From 16953fc64ad996bdf49271edc38162a90660ce5b Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Sun, 15 Mar 2026 20:49:33 +0100
Subject: [PATCH 2/9] Implement suggestions of code review

---
 flang/lib/Semantics/check-omp-structure.cpp | 5 +----
 flang/lib/Semantics/resolve-directives.cpp  | 4 ++--
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 44f8d46862ba3..515e08c2f9915 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1364,11 +1364,8 @@ void OmpStructureChecker::CheckThreadprivateOrDeclareTargetVar(
     for (const auto &obj : cb->objects()) {
       if (FindEquivalenceSet(*obj)) {
         context_.Say(name.source,
-            "A variable in a %s directive used in an EQUIVALENCE statement is "
-            "an OpenMP extension (variable '%s' from common block "
-            "'/%s/')"_warn_en_US,
+            "A variable in a %s directive used in an EQUIVALENCE statement is an OpenMP extension (variable '%s' from common block '/%s/')"_warn_en_US,
             ContextDirectiveAsFortran(), obj->name(), name.symbol->name());
-        fprintf(stderr, "--> %s\n", name.ToString().c_str());
       }
     }
   }
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 0b5c776946df5..5c054d8fe87e9 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -3247,10 +3247,10 @@ void OmpAttributeVisitor::ResolveOmpDesignator(
 void OmpAttributeVisitor::PropagateOmpFlagToEquivalenceSet(
     const Symbol &symbol, Symbol::Flag ompFlag) {
   // Find the equivalence set containing this symbol
-  if (const EquivalenceSet *eqSet = FindEquivalenceSet(symbol)) {
+  if (const EquivalenceSet *eqSet{FindEquivalenceSet(symbol)}) {
     // Propagate the flag to all symbols in the equivalence set
     for (const EquivalenceObject &eqObj : *eqSet) {
-      Symbol &eqSymbol = eqObj.symbol;
+      Symbol &eqSymbol{eqObj.symbol};
 
       // Skip the symbol itself (already has the flag)
       if (&eqSymbol == &symbol) {

>From f7a88253b9a08850af64f8a819b61f1ba919bae3 Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Sun, 15 Mar 2026 21:09:52 +0100
Subject: [PATCH 3/9] Separate message for THREADPRIVATE and DELCARE TARGET

---
 flang/lib/Semantics/check-omp-structure.cpp | 13 ++++++++++---
 flang/lib/Semantics/resolve-directives.cpp  |  2 +-
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 515e08c2f9915..1a953e789b6ef 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1361,11 +1361,18 @@ void OmpStructureChecker::CheckThreadprivateOrDeclareTargetVar(
   }
 
   if (auto *cb{name.symbol->detailsIf<CommonBlockDetails>()}) {
+    llvm::omp::Directive directive{GetContext().directive};
     for (const auto &obj : cb->objects()) {
       if (FindEquivalenceSet(*obj)) {
-        context_.Say(name.source,
-            "A variable in a %s directive used in an EQUIVALENCE statement is an OpenMP extension (variable '%s' from common block '/%s/')"_warn_en_US,
-            ContextDirectiveAsFortran(), obj->name(), name.symbol->name());
+        if (directive == llvm::omp::Directive::OMPD_threadprivate) {
+          context_.Say(name.source,
+              "A variable in a %s directive used in an EQUIVALENCE statement is an OpenMP extension (variable '%s' from common block '/%s/')"_warn_en_US,
+              ContextDirectiveAsFortran(), obj->name(), name.symbol->name());
+        } else {
+          context_.Say(name.source,
+              "A variable in a %s directive cannot appear in an EQUIVALENCE statement (variable '%s' from common block '/%s/')"_err_en_US,
+              ContextDirectiveAsFortran(), obj->name(), name.symbol->name());
+        }
       }
     }
   }
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 5c054d8fe87e9..c18b00b4aec93 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -3288,7 +3288,7 @@ void OmpAttributeVisitor::ResolveOmpCommonBlock(
         details.replace_object(*resolvedObject, index);
 
         // Propagate the flag to symbols in the equivalence set
-        if (ompFlagsRequireMark.test(ompFlag)) {
+        if (ompFlag == Symbol::Flag::OmpThreadprivate) {
           PropagateOmpFlagToEquivalenceSet(*resolvedObject, ompFlag);
         }
       }

>From 3587d9a39a6554c870393e0130f712d3bef1f60b Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Sun, 15 Mar 2026 21:27:01 +0100
Subject: [PATCH 4/9] Make the warning have a -Wno flag

---
 flang/include/flang/Support/Fortran-features.h            | 3 ++-
 flang/lib/Semantics/check-omp-structure.cpp               | 3 ++-
 flang/lib/Support/Fortran-features.cpp                    | 1 +
 flang/test/Semantics/OpenMP/threadprivate-equivalence.f90 | 2 +-
 flang/test/Semantics/OpenMP/threadprivate02.f90           | 2 +-
 5 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index cbcb3592f04c3..87326ffa7a6f0 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -57,7 +57,8 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
     ForwardRefExplicitTypeDummy, InaccessibleDeferredOverride,
     CudaWarpMatchFunction, DoConcurrentOffload, TransferBOZ, Coarray,
     PointerPassObject, MultipleIdenticalDATA,
-    DefaultStructConstructorNullPointer, AssumedRankIoItem)
+    DefaultStructConstructorNullPointer, AssumedRankIoItem,
+    OpenMPThreadprivateEquivalence)
 
 // Portability and suspicious usage warnings
 ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 1a953e789b6ef..d4c0f79d87afb 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1365,7 +1365,8 @@ void OmpStructureChecker::CheckThreadprivateOrDeclareTargetVar(
     for (const auto &obj : cb->objects()) {
       if (FindEquivalenceSet(*obj)) {
         if (directive == llvm::omp::Directive::OMPD_threadprivate) {
-          context_.Say(name.source,
+          context_.Warn(common::LanguageFeature::OpenMPThreadprivateEquivalence,
+              name.source,
               "A variable in a %s directive used in an EQUIVALENCE statement is an OpenMP extension (variable '%s' from common block '/%s/')"_warn_en_US,
               ContextDirectiveAsFortran(), obj->name(), name.symbol->name());
         } else {
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 83d1affba5ed2..861af18de75b7 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -153,6 +153,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
   warnLanguage_.set(LanguageFeature::NullActualForAllocatable);
   warnUsage_.set(UsageWarning::BadValueInDeadCode);
   warnUsage_.set(UsageWarning::MisplacedIgnoreTKR);
+  warnLanguage_.set(LanguageFeature::OpenMPThreadprivateEquivalence);
 }
 
 std::optional<LanguageControlFlag> LanguageFeatureControl::FindWarning(
diff --git a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90 b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
index 8896697c8812a..a4a4aaea8e383 100644
--- a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
@@ -10,7 +10,7 @@ program threadprivate02
   equivalence(eq_a, a1)
 
   ! This is an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
-  !WARNING: A variable in a THREADPRIVATE directive used in an EQUIVALENCE statement is an OpenMP extension (variable 'a1' from common block '/blk1/')
+  !WARNING: A variable in a THREADPRIVATE directive used in an EQUIVALENCE statement is an OpenMP extension (variable 'a1' from common block '/blk1/') [-Wopen-mp-threadprivate-equivalence]
   !$omp threadprivate(/blk1/)
 
   !ERROR: A THREADPRIVATE variable cannot be in SHARED clause
diff --git a/flang/test/Semantics/OpenMP/threadprivate02.f90 b/flang/test/Semantics/OpenMP/threadprivate02.f90
index fbbabc4319259..591711429c502 100644
--- a/flang/test/Semantics/OpenMP/threadprivate02.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate02.f90
@@ -29,7 +29,7 @@ program threadprivate02
   equivalence(eq_c, eq_d)
 
   ! This is an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
-  !WARNING: A variable in a THREADPRIVATE directive used in an EQUIVALENCE statement is an OpenMP extension (variable 'eq_e' from common block '/blk2/')
+  !WARNING: A variable in a THREADPRIVATE directive used in an EQUIVALENCE statement is an OpenMP extension (variable 'eq_e' from common block '/blk2/') [-Wopen-mp-threadprivate-equivalence]
   !$omp threadprivate(/blk2/)
 
 contains

>From 22b592d0fc58b5567fd915836618dab3a0b1f753 Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Sun, 15 Mar 2026 21:40:23 +0100
Subject: [PATCH 5/9] Add test to check that warning can be disabled

---
 .../OpenMP/threadprivate-equivalence-nowarn.f90  | 16 ++++++++++++++++
 .../OpenMP/threadprivate-equivalence.f90         |  6 ++----
 2 files changed, 18 insertions(+), 4 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90

diff --git a/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90 b/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
new file mode 100644
index 0000000000000..0af4f88dac502
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
@@ -0,0 +1,16 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -Wno-open-mp-threadprivate-equivalence
+
+! This a test for is an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
+
+program threadprivate02
+  common /blk1/ a1
+  real :: a1
+  real :: eq_a
+  equivalence(eq_a, a1)
+
+  !$omp threadprivate(/blk1/)
+
+  !ERROR: A THREADPRIVATE variable cannot be in SHARED clause
+  !$omp parallel shared(eq_a)
+  !$omp end parallel
+end
\ No newline at end of file
diff --git a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90 b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
index a4a4aaea8e383..ea07ef7759551 100644
--- a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
@@ -1,7 +1,6 @@
 ! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
-! OpenMP Version 5.1
-! Check OpenMP construct validity for the following directives:
-! 2.21.2 Threadprivate Directive
+
+! This a test for is an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
 
 program threadprivate02
   common /blk1/ a1
@@ -9,7 +8,6 @@ program threadprivate02
   real :: eq_a
   equivalence(eq_a, a1)
 
-  ! This is an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
   !WARNING: A variable in a THREADPRIVATE directive used in an EQUIVALENCE statement is an OpenMP extension (variable 'a1' from common block '/blk1/') [-Wopen-mp-threadprivate-equivalence]
   !$omp threadprivate(/blk1/)
 

>From 5a39f9c6f2579aa44555ef1f3bc42a87e0eac5bb Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Sun, 15 Mar 2026 21:50:13 +0100
Subject: [PATCH 6/9] Add missing newlines at the end of the file

---
 .../test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90  | 2 +-
 flang/test/Semantics/OpenMP/threadprivate-equivalence.f90       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90 b/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
index 0af4f88dac502..a4d8270fb1b29 100644
--- a/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
@@ -13,4 +13,4 @@ program threadprivate02
   !ERROR: A THREADPRIVATE variable cannot be in SHARED clause
   !$omp parallel shared(eq_a)
   !$omp end parallel
-end
\ No newline at end of file
+end
diff --git a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90 b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
index ea07ef7759551..ef814378d8462 100644
--- a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
@@ -14,4 +14,4 @@ program threadprivate02
   !ERROR: A THREADPRIVATE variable cannot be in SHARED clause
   !$omp parallel shared(eq_a)
   !$omp end parallel
-end
\ No newline at end of file
+end

>From 9845ff2e7be22ff9d9ef0abf111e3b8e61bffe85 Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Sun, 15 Mar 2026 22:14:14 +0100
Subject: [PATCH 7/9] Remove weird hyphen from warning option as workaround
 until -Wopen-mp is fixed

---
 flang/lib/Support/Fortran-features.cpp                     | 7 +++++++
 .../Semantics/OpenMP/threadprivate-equivalence-nowarn.f90  | 2 +-
 flang/test/Semantics/OpenMP/threadprivate-equivalence.f90  | 2 +-
 flang/test/Semantics/OpenMP/threadprivate02.f90            | 2 +-
 4 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 861af18de75b7..3107a5350f858 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -70,6 +70,13 @@ LanguageFeatureControl::LanguageFeatureControl() {
         std::move(cliOption);
   });
 
+  // Fix CLI spellings where the auto-generated hyphenation is wrong.
+  // TODO: -Wopen-mp-* should be fixed in a central place.  See
+  // see Discourse at
+  // https://discourse.llvm.org/t/openmp-misspelling-of-wopen-mp/90196.
+  ReplaceCliCanonicalSpelling(LanguageFeature::OpenMPThreadprivateEquivalence,
+      "openmp-threadprivate-equivalence");
+
   // These features must be explicitly enabled by command line options.
   disable_.set(LanguageFeature::OldDebugLines);
   disable_.set(LanguageFeature::OpenACC);
diff --git a/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90 b/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
index a4d8270fb1b29..19c671d3ff3b9 100644
--- a/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
@@ -1,4 +1,4 @@
-! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -Wno-open-mp-threadprivate-equivalence
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -Wno-openmp-threadprivate-equivalence
 
 ! This a test for is an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
 
diff --git a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90 b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
index ef814378d8462..b36fa01c6fa01 100644
--- a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
@@ -8,7 +8,7 @@ program threadprivate02
   real :: eq_a
   equivalence(eq_a, a1)
 
-  !WARNING: A variable in a THREADPRIVATE directive used in an EQUIVALENCE statement is an OpenMP extension (variable 'a1' from common block '/blk1/') [-Wopen-mp-threadprivate-equivalence]
+  !WARNING: A variable in a THREADPRIVATE directive used in an EQUIVALENCE statement is an OpenMP extension (variable 'a1' from common block '/blk1/') [-Wopenmp-threadprivate-equivalence]
   !$omp threadprivate(/blk1/)
 
   !ERROR: A THREADPRIVATE variable cannot be in SHARED clause
diff --git a/flang/test/Semantics/OpenMP/threadprivate02.f90 b/flang/test/Semantics/OpenMP/threadprivate02.f90
index 591711429c502..6ac024780aa79 100644
--- a/flang/test/Semantics/OpenMP/threadprivate02.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate02.f90
@@ -29,7 +29,7 @@ program threadprivate02
   equivalence(eq_c, eq_d)
 
   ! This is an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
-  !WARNING: A variable in a THREADPRIVATE directive used in an EQUIVALENCE statement is an OpenMP extension (variable 'eq_e' from common block '/blk2/') [-Wopen-mp-threadprivate-equivalence]
+  !WARNING: A variable in a THREADPRIVATE directive used in an EQUIVALENCE statement is an OpenMP extension (variable 'eq_e' from common block '/blk2/') [-Wopenmp-threadprivate-equivalence]
   !$omp threadprivate(/blk2/)
 
 contains

>From b1aea8e33073da007989d40e30185f2bd2035bf7 Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Mon, 16 Mar 2026 16:58:41 +0100
Subject: [PATCH 8/9] Add Arm's downstream work on making copyprivate work

---
 flang/lib/Lower/OpenMP/ClauseProcessor.cpp    |  4 +-
 flang/test/Integration/OpenMP/copyprivate.f90 | 38 ++++-----
 .../Lower/OpenMP/copyprivate-equivalence.f90  | 78 +++++++++++++++++++
 flang/test/Lower/OpenMP/copyprivate.f90       | 66 ++++++++--------
 flang/test/Lower/OpenMP/copyprivate2.f90      | 16 ++--
 flang/test/Lower/OpenMP/copyprivate3.f90      |  4 +-
 flang/test/Lower/OpenMP/copyprivate4.f90      |  2 +-
 flang/test/Lower/OpenMP/copyprivate5.f90      |  4 +-
 8 files changed, 145 insertions(+), 67 deletions(-)
 create mode 100644 flang/test/Lower/OpenMP/copyprivate-equivalence.f90

diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 9696bc21b5fbb..c05cbffc99993 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -939,10 +939,10 @@ createCopyFunc(mlir::Location loc, lower::AbstractConverter &converter,
                mlir::Type varType, fir::FortranVariableFlagsEnum varAttrs) {
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
   mlir::ModuleOp module = builder.getModule();
-  mlir::Type eleTy = mlir::cast<fir::ReferenceType>(varType).getEleTy();
+  mlir::Type eleTy = fir::unwrapRefType(varType);
   TypeInfo typeInfo(eleTy);
   std::string copyFuncName =
-      fir::getTypeAsString(eleTy, builder.getKindMap(), "_copy");
+      fir::getTypeAsString(varType, builder.getKindMap(), "_copy");
 
   if (auto decl = module.lookupSymbol<mlir::func::FuncOp>(copyFuncName))
     return decl;
diff --git a/flang/test/Integration/OpenMP/copyprivate.f90 b/flang/test/Integration/OpenMP/copyprivate.f90
index 43c8612d0a1da..7b4de32bb5cc7 100644
--- a/flang/test/Integration/OpenMP/copyprivate.f90
+++ b/flang/test/Integration/OpenMP/copyprivate.f90
@@ -8,24 +8,24 @@
 
 !RUN: %flang_fc1 -emit-llvm -fopenmp %s -o - | FileCheck %s
 
-!CHECK-DAG: define internal void @_copy_box_Uxi32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_box_10xi32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_i64(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_box_Uxi64(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_f32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_box_2x3xf32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_z32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_box_10xz32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_l32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_box_5xl32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_c8x8(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_box_10xc8x8(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_c16x5(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_rec__QFtest_typesTdt(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_box_heap_Uxi32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
-!CHECK-DAG: define internal void @_copy_box_ptr_Uxc8x9(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_box_Uxi32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_box_10xi32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_i64(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_box_Uxi64(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_f32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_box_2x3xf32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_z32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_box_10xz32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_l32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_box_5xl32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_c8x8(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_box_10xc8x8(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_c16x5(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_rec__QFtest_typesTdt(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_box_heap_Uxi32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
+!CHECK-DAG: define internal void @_copy_ref_box_ptr_Uxc8x9(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
 
-!CHECK-LABEL: define internal void @_copy_i32(
+!CHECK-LABEL: define internal void @_copy_ref_i32(
 !CHECK-SAME:                         ptr {{[^%]*}}%[[DST:.*]], ptr {{[^%]*}}%[[SRC:.*]]){{.*}} {
 !CHECK-NEXT:    %[[SRC_VAL:.*]] = load i32, ptr %[[SRC]]
 !CHECK-NEXT:    store i32 %[[SRC_VAL]], ptr %[[DST]]
@@ -49,10 +49,10 @@
 !CHECK:       [[OMP_REGION_END]]:
 !CHECK:         %[[THREAD_NUM2:.*]] = call i32 @__kmpc_global_thread_num(ptr @[[LOC:.*]])
 !CHECK:         %[[DID_IT_VAL:.*]] = load i32, ptr %[[DID_IT]]
-!CHECK:         call void @__kmpc_copyprivate(ptr @[[LOC]], i32 %[[THREAD_NUM2]], i64 0, ptr %[[I]], ptr @_copy_i32, i32 %[[DID_IT_VAL]])
+!CHECK:         call void @__kmpc_copyprivate(ptr @[[LOC]], i32 %[[THREAD_NUM2]], i64 0, ptr %[[I]], ptr @_copy_ref_i32, i32 %[[DID_IT_VAL]])
 !CHECK:         %[[THREAD_NUM3:.*]] = call i32 @__kmpc_global_thread_num(ptr @[[LOC]])
 !CHECK:         %[[DID_IT_VAL2:.*]] = load i32, ptr %[[DID_IT]]
-!CHECK:         call void @__kmpc_copyprivate(ptr @[[LOC]], i32 %[[THREAD_NUM3]], i64 0, ptr %[[J]], ptr @_copy_i32, i32 %[[DID_IT_VAL2]])
+!CHECK:         call void @__kmpc_copyprivate(ptr @[[LOC]], i32 %[[THREAD_NUM3]], i64 0, ptr %[[J]], ptr @_copy_ref_i32, i32 %[[DID_IT_VAL2]])
 
 !CHECK:       [[OMP_REGION_BODY]]:
 !CHECK:         br label %[[OMP_SINGLE_REGION:.*]]
diff --git a/flang/test/Lower/OpenMP/copyprivate-equivalence.f90 b/flang/test/Lower/OpenMP/copyprivate-equivalence.f90
new file mode 100644
index 0000000000000..6cdf51ee3e992
--- /dev/null
+++ b/flang/test/Lower/OpenMP/copyprivate-equivalence.f90
@@ -0,0 +1,78 @@
+! Downstream only: support for equivalence with threadprivate/copyprivate
+
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s | FileCheck %s
+
+subroutine s1
+  equivalence (k(2),kk)
+  common /com1/ k(2)
+  !$omp threadprivate(/com1/)
+
+  !$omp parallel
+    k=0
+    !$omp single
+      k(1)=1
+      kk=2
+    !$omp end single copyprivate(/com1/)
+  !$omp end parallel
+end
+
+! Check we can generate a copy function for !fir.ptr arguments
+! CHECK-LABEL:   func.func private @_copy_ptr_2xi32(
+! CHECK-SAME:      %[[ARG0:.*]]: !fir.ptr<!fir.array<2xi32>>,
+! CHECK-SAME:      %[[ARG1:.*]]: !fir.ptr<!fir.array<2xi32>>) attributes {llvm.linkage = #llvm.linkage<internal>} {
+! CHECK:           %[[CONSTANT_0:.*]] = arith.constant 2 : index
+! CHECK:           %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_0]] : (index) -> !fir.shape<1>
+! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[ARG0]](%[[SHAPE_0]]) {uniq_name = "_copy_ptr_2xi32_dst"} : (!fir.ptr<!fir.array<2xi32>>, !fir.shape<1>) -> (!fir.ptr<!fir.array<2xi32>>, !fir.ptr<!fir.array<2xi32>>)
+! CHECK:           %[[DECLARE_1:.*]]:2 = hlfir.declare %[[ARG1]](%[[SHAPE_0]]) {uniq_name = "_copy_ptr_2xi32_src"} : (!fir.ptr<!fir.array<2xi32>>, !fir.shape<1>) -> (!fir.ptr<!fir.array<2xi32>>, !fir.ptr<!fir.array<2xi32>>)
+! CHECK:           hlfir.assign %[[DECLARE_1]]#0 to %[[DECLARE_0]]#0 : !fir.ptr<!fir.array<2xi32>>, !fir.ptr<!fir.array<2xi32>>
+! CHECK:           return
+! CHECK:         }
+
+! CHECK-LABEL:   func.func @_QPs1() {
+! CHECK:           %[[DUMMY_SCOPE_0:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK:           %[[ADDRESS_OF_0:.*]] = fir.address_of(@com1_) : !fir.ref<!fir.array<8xi8>>
+! CHECK:           %[[CONSTANT_0:.*]] = arith.constant 0 : index
+! CHECK:           %[[COORDINATE_OF_0:.*]] = fir.coordinate_of %[[ADDRESS_OF_0]], %[[CONSTANT_0]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+! CHECK:           %[[CONVERT_0:.*]] = fir.convert %[[COORDINATE_OF_0]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<2xi32>>
+! CHECK:           %[[CONSTANT_1:.*]] = arith.constant 2 : index
+! CHECK:           %[[SHAPE_0:.*]] = fir.shape %[[CONSTANT_1]] : (index) -> !fir.shape<1>
+! CHECK:           %[[DECLARE_0:.*]]:2 = hlfir.declare %[[CONVERT_0]](%[[SHAPE_0]]) storage(%[[ADDRESS_OF_0]][0]) {uniq_name = "_QFs1Ek"} : (!fir.ptr<!fir.array<2xi32>>, !fir.shape<1>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ptr<!fir.array<2xi32>>, !fir.ptr<!fir.array<2xi32>>)
+! CHECK:           %[[THREADPRIVATE_0:.*]] = omp.threadprivate %[[ADDRESS_OF_0]] : !fir.ref<!fir.array<8xi8>> -> !fir.ref<!fir.array<8xi8>>
+! CHECK:           %[[CONSTANT_2:.*]] = arith.constant 0 : index
+! CHECK:           %[[COORDINATE_OF_1:.*]] = fir.coordinate_of %[[THREADPRIVATE_0]], %[[CONSTANT_2]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+! CHECK:           %[[CONVERT_1:.*]] = fir.convert %[[COORDINATE_OF_1]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<2xi32>>
+! CHECK:           %[[SHAPE_1:.*]] = fir.shape %[[CONSTANT_1]] : (index) -> !fir.shape<1>
+! CHECK:           %[[DECLARE_1:.*]]:2 = hlfir.declare %[[CONVERT_1]](%[[SHAPE_1]]) storage(%[[THREADPRIVATE_0]][0]) {uniq_name = "_QFs1Ek"} : (!fir.ptr<!fir.array<2xi32>>, !fir.shape<1>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ptr<!fir.array<2xi32>>, !fir.ptr<!fir.array<2xi32>>)
+! CHECK:           %[[CONSTANT_3:.*]] = arith.constant 4 : index
+! CHECK:           %[[COORDINATE_OF_2:.*]] = fir.coordinate_of %[[THREADPRIVATE_0]], %[[CONSTANT_3]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+! CHECK:           %[[CONVERT_2:.*]] = fir.convert %[[COORDINATE_OF_2]] : (!fir.ref<i8>) -> !fir.ptr<i32>
+! CHECK:           %[[DECLARE_2:.*]]:2 = hlfir.declare %[[CONVERT_2]] storage(%[[THREADPRIVATE_0]][4]) {uniq_name = "_QFs1Ekk"} : (!fir.ptr<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! CHECK:           omp.parallel {
+! CHECK:             %[[THREADPRIVATE_1:.*]] = omp.threadprivate %[[ADDRESS_OF_0]] : !fir.ref<!fir.array<8xi8>> -> !fir.ref<!fir.array<8xi8>>
+! CHECK:             %[[CONSTANT_4:.*]] = arith.constant 0 : index
+! CHECK:             %[[COORDINATE_OF_3:.*]] = fir.coordinate_of %[[THREADPRIVATE_1]], %[[CONSTANT_4]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+! CHECK:             %[[CONVERT_3:.*]] = fir.convert %[[COORDINATE_OF_3]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<2xi32>>
+! CHECK:             %[[SHAPE_2:.*]] = fir.shape %[[CONSTANT_1]] : (index) -> !fir.shape<1>
+! CHECK:             %[[DECLARE_3:.*]]:2 = hlfir.declare %[[CONVERT_3]](%[[SHAPE_2]]) storage(%[[THREADPRIVATE_1]][0]) {uniq_name = "_QFs1Ek"} : (!fir.ptr<!fir.array<2xi32>>, !fir.shape<1>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ptr<!fir.array<2xi32>>, !fir.ptr<!fir.array<2xi32>>)
+! CHECK:             %[[CONSTANT_5:.*]] = arith.constant 4 : index
+
+! Check that the equivalence'd value kk comes from omp.threadprivate not from a shared variable
+! CHECK:             %[[COORDINATE_OF_4:.*]] = fir.coordinate_of %[[THREADPRIVATE_1]], %[[CONSTANT_5]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+! CHECK:             %[[CONVERT_4:.*]] = fir.convert %[[COORDINATE_OF_4]] : (!fir.ref<i8>) -> !fir.ptr<i32>
+! CHECK:             %[[DECLARE_4:.*]]:2 = hlfir.declare %[[CONVERT_4]] storage(%[[THREADPRIVATE_1]][4]) {uniq_name = "_QFs1Ekk"} : (!fir.ptr<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+
+! CHECK:             %[[CONSTANT_6:.*]] = arith.constant 0 : i32
+! CHECK:             hlfir.assign %[[CONSTANT_6]] to %[[DECLARE_3]]#0 : i32, !fir.ptr<!fir.array<2xi32>>
+! CHECK:             omp.single copyprivate(%[[DECLARE_3]]#0 -> @_copy_ptr_2xi32 : !fir.ptr<!fir.array<2xi32>>) {
+! CHECK:               %[[CONSTANT_7:.*]] = arith.constant 1 : i32
+! CHECK:               %[[CONSTANT_8:.*]] = arith.constant 1 : index
+! CHECK:               %[[DESIGNATE_0:.*]] = hlfir.designate %[[DECLARE_3]]#0 (%[[CONSTANT_8]])  : (!fir.ptr<!fir.array<2xi32>>, index) -> !fir.ref<i32>
+! CHECK:               hlfir.assign %[[CONSTANT_7]] to %[[DESIGNATE_0]] : i32, !fir.ref<i32>
+! CHECK:               %[[CONSTANT_9:.*]] = arith.constant 2 : i32
+! CHECK:               hlfir.assign %[[CONSTANT_9]] to %[[DECLARE_4]]#0 : i32, !fir.ptr<i32>
+! CHECK:               omp.terminator
+! CHECK:             }
+! CHECK:             omp.terminator
+! CHECK:           }
+! CHECK:           return
+! CHECK:         }
diff --git a/flang/test/Lower/OpenMP/copyprivate.f90 b/flang/test/Lower/OpenMP/copyprivate.f90
index 4c3ed9389369f..f3e6a76d95acb 100644
--- a/flang/test/Lower/OpenMP/copyprivate.f90
+++ b/flang/test/Lower/OpenMP/copyprivate.f90
@@ -2,38 +2,38 @@
 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 \
 ! RUN: | FileCheck %s
 
-!CHECK-DAG: func private @_copy_i64(%{{.*}}: !fir.ref<i64>, %{{.*}}: !fir.ref<i64>)
-!CHECK-DAG: func private @_copy_f32(%{{.*}}: !fir.ref<f32>, %{{.*}}: !fir.ref<f32>)
-!CHECK-DAG: func private @_copy_f64(%{{.*}}: !fir.ref<f64>, %{{.*}}: !fir.ref<f64>)
-!CHECK-DAG: func private @_copy_z32(%{{.*}}: !fir.ref<complex<f32>>, %{{.*}}: !fir.ref<complex<f32>>)
-!CHECK-DAG: func private @_copy_z64(%{{.*}}: !fir.ref<complex<f64>>, %{{.*}}: !fir.ref<complex<f64>>)
-!CHECK-DAG: func private @_copy_l32(%{{.*}}: !fir.ref<!fir.logical<4>>, %{{.*}}: !fir.ref<!fir.logical<4>>)
-!CHECK-DAG: func private @_copy_l64(%{{.*}}: !fir.ref<!fir.logical<8>>, %{{.*}}: !fir.ref<!fir.logical<8>>)
-!CHECK-DAG: func private @_copy_c8x3(%{{.*}}: !fir.ref<!fir.char<1,3>>, %{{.*}}: !fir.ref<!fir.char<1,3>>)
-!CHECK-DAG: func private @_copy_c8x8(%{{.*}}: !fir.ref<!fir.char<1,8>>, %{{.*}}: !fir.ref<!fir.char<1,8>>)
-!CHECK-DAG: func private @_copy_c16x8(%{{.*}}: !fir.ref<!fir.char<2,8>>, %{{.*}}: !fir.ref<!fir.char<2,8>>)
+!CHECK-DAG: func private @_copy_ref_i64(%{{.*}}: !fir.ref<i64>, %{{.*}}: !fir.ref<i64>)
+!CHECK-DAG: func private @_copy_ref_f32(%{{.*}}: !fir.ref<f32>, %{{.*}}: !fir.ref<f32>)
+!CHECK-DAG: func private @_copy_ref_f64(%{{.*}}: !fir.ref<f64>, %{{.*}}: !fir.ref<f64>)
+!CHECK-DAG: func private @_copy_ref_z32(%{{.*}}: !fir.ref<complex<f32>>, %{{.*}}: !fir.ref<complex<f32>>)
+!CHECK-DAG: func private @_copy_ref_z64(%{{.*}}: !fir.ref<complex<f64>>, %{{.*}}: !fir.ref<complex<f64>>)
+!CHECK-DAG: func private @_copy_ref_l32(%{{.*}}: !fir.ref<!fir.logical<4>>, %{{.*}}: !fir.ref<!fir.logical<4>>)
+!CHECK-DAG: func private @_copy_ref_l64(%{{.*}}: !fir.ref<!fir.logical<8>>, %{{.*}}: !fir.ref<!fir.logical<8>>)
+!CHECK-DAG: func private @_copy_ref_c8x3(%{{.*}}: !fir.ref<!fir.char<1,3>>, %{{.*}}: !fir.ref<!fir.char<1,3>>)
+!CHECK-DAG: func private @_copy_ref_c8x8(%{{.*}}: !fir.ref<!fir.char<1,8>>, %{{.*}}: !fir.ref<!fir.char<1,8>>)
+!CHECK-DAG: func private @_copy_ref_c16x8(%{{.*}}: !fir.ref<!fir.char<2,8>>, %{{.*}}: !fir.ref<!fir.char<2,8>>)
 
-!CHECK-DAG: func private @_copy_box_Uxi32(%{{.*}}: !fir.ref<!fir.box<!fir.array<?xi32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<?xi32>>>)
-!CHECK-DAG: func private @_copy_box_10xi32(%{{.*}}: !fir.ref<!fir.box<!fir.array<10xi32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<10xi32>>>)
-!CHECK-DAG: func private @_copy_box_3x4xi32(%{{.*}}: !fir.ref<!fir.box<!fir.array<3x4xi32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<3x4xi32>>>)
-!CHECK-DAG: func private @_copy_box_10xf32(%{{.*}}: !fir.ref<!fir.box<!fir.array<10xf32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<10xf32>>>)
-!CHECK-DAG: func private @_copy_box_3x4xz32(%{{.*}}: !fir.ref<!fir.box<!fir.array<3x4xcomplex<f32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<3x4xcomplex<f32>>>>)
-!CHECK-DAG: func private @_copy_box_10xl32(%{{.*}}: !fir.ref<!fir.box<!fir.array<10x!fir.logical<4>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<10x!fir.logical<4>>>>)
-!CHECK-DAG: func private @_copy_box_3xc8x8(%{{.*}}: !fir.ref<!fir.box<!fir.array<3x!fir.char<1,8>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<3x!fir.char<1,8>>>>)
-!CHECK-DAG: func private @_copy_box_3xc16x5(%{{.*}}: !fir.ref<!fir.box<!fir.array<3x!fir.char<2,5>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<3x!fir.char<2,5>>>>)
+!CHECK-DAG: func private @_copy_ref_box_Uxi32(%{{.*}}: !fir.ref<!fir.box<!fir.array<?xi32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<?xi32>>>)
+!CHECK-DAG: func private @_copy_ref_box_10xi32(%{{.*}}: !fir.ref<!fir.box<!fir.array<10xi32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<10xi32>>>)
+!CHECK-DAG: func private @_copy_ref_box_3x4xi32(%{{.*}}: !fir.ref<!fir.box<!fir.array<3x4xi32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<3x4xi32>>>)
+!CHECK-DAG: func private @_copy_ref_box_10xf32(%{{.*}}: !fir.ref<!fir.box<!fir.array<10xf32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<10xf32>>>)
+!CHECK-DAG: func private @_copy_ref_box_3x4xz32(%{{.*}}: !fir.ref<!fir.box<!fir.array<3x4xcomplex<f32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<3x4xcomplex<f32>>>>)
+!CHECK-DAG: func private @_copy_ref_box_10xl32(%{{.*}}: !fir.ref<!fir.box<!fir.array<10x!fir.logical<4>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<10x!fir.logical<4>>>>)
+!CHECK-DAG: func private @_copy_ref_box_3xc8x8(%{{.*}}: !fir.ref<!fir.box<!fir.array<3x!fir.char<1,8>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<3x!fir.char<1,8>>>>)
+!CHECK-DAG: func private @_copy_ref_box_3xc16x5(%{{.*}}: !fir.ref<!fir.box<!fir.array<3x!fir.char<2,5>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.array<3x!fir.char<2,5>>>>)
 
-!CHECK-DAG: func private @_copy_rec__QFtest_dtTdt(%{{.*}}: !fir.ref<!fir.type<_QFtest_dtTdt{i:i32,r:f32}>>, %{{.*}}: !fir.ref<!fir.type<_QFtest_dtTdt{i:i32,r:f32}>>)
-!CHECK-DAG: func private @_copy_box_heap_Uxi32(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
-!CHECK-DAG: func private @_copy_box_heap_i32(%{{.*}}: !fir.ref<!fir.box<!fir.heap<i32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<i32>>>)
-!CHECK-DAG: func private @_copy_box_ptr_i32(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>)
-!CHECK-DAG: func private @_copy_box_ptr_Uxf32(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>)
-!CHECK-DAG: func private @_copy_box_heap_Uxc8x5(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,5>>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,5>>>>>)
-!CHECK-DAG: func private @_copy_box_ptr_Uxc8x9(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,9>>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,9>>>>>)
+!CHECK-DAG: func private @_copy_ref_rec__QFtest_dtTdt(%{{.*}}: !fir.ref<!fir.type<_QFtest_dtTdt{i:i32,r:f32}>>, %{{.*}}: !fir.ref<!fir.type<_QFtest_dtTdt{i:i32,r:f32}>>)
+!CHECK-DAG: func private @_copy_ref_box_heap_Uxi32(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
+!CHECK-DAG: func private @_copy_ref_box_heap_i32(%{{.*}}: !fir.ref<!fir.box<!fir.heap<i32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<i32>>>)
+!CHECK-DAG: func private @_copy_ref_box_ptr_i32(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<i32>>>)
+!CHECK-DAG: func private @_copy_ref_box_ptr_Uxf32(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>)
+!CHECK-DAG: func private @_copy_ref_box_heap_Uxc8x5(%{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,5>>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,5>>>>>)
+!CHECK-DAG: func private @_copy_ref_box_ptr_Uxc8x9(%{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,9>>>>>, %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,9>>>>>)
 
-!CHECK-LABEL: func private @_copy_i32(
+!CHECK-LABEL: func private @_copy_ref_i32(
 !CHECK-SAME:                  %[[ARG0:.*]]: !fir.ref<i32>, %[[ARG1:.*]]: !fir.ref<i32>) attributes {llvm.linkage = #llvm.linkage<internal>} {
-!CHECK-NEXT:    %[[DST:.*]]:2 = hlfir.declare %[[ARG0]] {uniq_name = "_copy_i32_dst"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-!CHECK-NEXT:    %[[SRC:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_copy_i32_src"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK-NEXT:    %[[DST:.*]]:2 = hlfir.declare %[[ARG0]] {uniq_name = "_copy_ref_i32_dst"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK-NEXT:    %[[SRC:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_copy_ref_i32_src"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK-NEXT:    %[[SRC_VAL:.*]] = fir.load %[[SRC]]#0 : !fir.ref<i32>
 !CHECK-NEXT:    hlfir.assign %[[SRC_VAL]] to %[[DST]]#0 : i32, !fir.ref<i32>
 !CHECK-NEXT:    return
@@ -44,7 +44,7 @@
 !CHECK:           %[[I:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFtest_tpEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK:           %[[J:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFtest_tpEj"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 !CHECK:           %[[K:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFtest_tpEk"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
-!CHECK:           omp.single copyprivate(%[[I]]#0 -> @_copy_i32 : !fir.ref<i32>, %[[J]]#0 -> @_copy_i32 : !fir.ref<i32>, %[[K]]#0 -> @_copy_f32 : !fir.ref<f32>)
+!CHECK:           omp.single copyprivate(%[[I]]#0 -> @_copy_ref_i32 : !fir.ref<i32>, %[[J]]#0 -> @_copy_ref_i32 : !fir.ref<i32>, %[[K]]#0 -> @_copy_ref_f32 : !fir.ref<f32>)
 subroutine test_tp()
   integer, save :: i, j
   !$omp threadprivate(i, j)
@@ -73,7 +73,7 @@ subroutine test_tp()
 !CHECK:           %[[S1:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFtest_scalarEs1"} : (!fir.ref<!fir.char<1,3>>, index) -> (!fir.ref<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>)
 !CHECK:           %[[S2:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFtest_scalarEs2"} : (!fir.ref<!fir.char<1,8>>, index) -> (!fir.ref<!fir.char<1,8>>, !fir.ref<!fir.char<1,8>>)
 !CHECK:           %[[S3:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFtest_scalarEs3"} : (!fir.ref<!fir.char<2,8>>, index) -> (!fir.ref<!fir.char<2,8>>, !fir.ref<!fir.char<2,8>>)
-!CHECK:           omp.single copyprivate(%[[I1]]#0 -> @_copy_i32 : !fir.ref<i32>, %[[I2]]#0 -> @_copy_i64 : !fir.ref<i64>, %[[I3]]#0 -> @_copy_i64 : !fir.ref<i64>, %[[R1]]#0 -> @_copy_f32 : !fir.ref<f32>, %[[R2]]#0 -> @_copy_f64 : !fir.ref<f64>, %[[C1]]#0 -> @_copy_z32 : !fir.ref<complex<f32>>, %[[C2]]#0 -> @_copy_z64 : !fir.ref<complex<f64>>, %[[L1]]#0 -> @_copy_l32 : !fir.ref<!fir.logical<4>>, %[[L2]]#0 -> @_copy_l64 : !fir.ref<!fir.logical<8>>, %[[S1]]#0 -> @_copy_c8x3 : !fir.ref<!fir.char<1,3>>, %[[S2]]#0 -> @_copy_c8x8 : !fir.ref<!fir.char<1,8>>, %[[S3]]#0 -> @_copy_c16x8 : !fir.ref<!fir.char<2,8>>)
+!CHECK:           omp.single copyprivate(%[[I1]]#0 -> @_copy_ref_i32 : !fir.ref<i32>, %[[I2]]#0 -> @_copy_ref_i64 : !fir.ref<i64>, %[[I3]]#0 -> @_copy_ref_i64 : !fir.ref<i64>, %[[R1]]#0 -> @_copy_ref_f32 : !fir.ref<f32>, %[[R2]]#0 -> @_copy_ref_f64 : !fir.ref<f64>, %[[C1]]#0 -> @_copy_ref_z32 : !fir.ref<complex<f32>>, %[[C2]]#0 -> @_copy_ref_z64 : !fir.ref<complex<f64>>, %[[L1]]#0 -> @_copy_ref_l32 : !fir.ref<!fir.logical<4>>, %[[L2]]#0 -> @_copy_ref_l64 : !fir.ref<!fir.logical<8>>, %[[S1]]#0 -> @_copy_ref_c8x3 : !fir.ref<!fir.char<1,3>>, %[[S2]]#0 -> @_copy_ref_c8x8 : !fir.ref<!fir.char<1,8>>, %[[S3]]#0 -> @_copy_ref_c16x8 : !fir.ref<!fir.char<2,8>>)
 subroutine test_scalar()
   integer(4) :: i1
   integer(8) :: i2, i3
@@ -104,7 +104,7 @@ subroutine test_scalar()
 !CHECK:           %[[L1:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFtest_arrayEl1"}
 !CHECK:           %[[S1:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_arrayEs1"}
 !CHECK:           %[[S2:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_arrayEs2"}
-!CHECK:           omp.single copyprivate(%[[A]]#0 -> @_copy_box_Uxi32 : {{.*}}, %[[I1]]#0 -> @_copy_box_10xi32 : {{.*}}, %[[I2]]#0 -> @_copy_box_3x4xi32 : {{.*}}, %[[I3]]#0 -> @_copy_box_Uxi32 : {{.*}}, %[[R1]]#0 -> @_copy_box_10xf32 : {{.*}}, %[[C1]]#0 -> @_copy_box_3x4xz32 : {{.*}}, %[[L1]]#0 -> @_copy_box_10xl32 : {{.*}}, %[[S1]]#0 -> @_copy_box_3xc8x8 : {{.*}}, %[[S2]]#0 -> @_copy_box_3xc16x5 : {{.*}})
+!CHECK:           omp.single copyprivate(%[[A]]#0 -> @_copy_ref_box_Uxi32 : {{.*}}, %[[I1]]#0 -> @_copy_ref_box_10xi32 : {{.*}}, %[[I2]]#0 -> @_copy_ref_box_3x4xi32 : {{.*}}, %[[I3]]#0 -> @_copy_ref_box_Uxi32 : {{.*}}, %[[R1]]#0 -> @_copy_ref_box_10xf32 : {{.*}}, %[[C1]]#0 -> @_copy_ref_box_3x4xz32 : {{.*}}, %[[L1]]#0 -> @_copy_ref_box_10xl32 : {{.*}}, %[[S1]]#0 -> @_copy_ref_box_3xc8x8 : {{.*}}, %[[S2]]#0 -> @_copy_ref_box_3xc16x5 : {{.*}})
 subroutine test_array(a, n)
   integer :: a(:), n
   integer :: i1(10), i2(3, 4), i3(n)
@@ -123,7 +123,7 @@ subroutine test_array(a, n)
 !CHECK-LABEL: func @_QPtest_dt
 !CHECK:         omp.parallel
 !CHECK:           %[[T:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFtest_dtEt"} : (!fir.ref<!fir.type<_QFtest_dtTdt{i:i32,r:f32}>>) -> (!fir.ref<!fir.type<_QFtest_dtTdt{i:i32,r:f32}>>, !fir.ref<!fir.type<_QFtest_dtTdt{i:i32,r:f32}>>)
-!CHECK:           omp.single copyprivate(%[[T]]#0 -> @_copy_rec__QFtest_dtTdt : !fir.ref<!fir.type<_QFtest_dtTdt{i:i32,r:f32}>>)
+!CHECK:           omp.single copyprivate(%[[T]]#0 -> @_copy_ref_rec__QFtest_dtTdt : !fir.ref<!fir.type<_QFtest_dtTdt{i:i32,r:f32}>>)
 subroutine test_dt()
   type dt
     integer :: i
@@ -145,7 +145,7 @@ subroutine test_dt()
 !CHECK:           %[[R1:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtest_attrEr1"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>)
 !CHECK:           %[[C1:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_attrEc1"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,5>>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,5>>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,5>>>>>)
 !CHECK:           %[[C2:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtest_attrEc2"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,9>>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,9>>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,9>>>>>)
-!CHECK:           omp.single copyprivate(%[[I1]]#0 -> @_copy_box_heap_Uxi32 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %[[I2:.*]]#0 -> @_copy_box_heap_i32 : !fir.ref<!fir.box<!fir.heap<i32>>>, %[[I3]]#0 -> @_copy_box_ptr_i32 : !fir.ref<!fir.box<!fir.ptr<i32>>>, %[[R1]]#0 -> @_copy_box_ptr_Uxf32 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>,  %[[C1]]#0 -> @_copy_box_heap_Uxc8x5 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,5>>>>>, %[[C2]]#0 -> @_copy_box_ptr_Uxc8x9 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,9>>>>>)
+!CHECK:           omp.single copyprivate(%[[I1]]#0 -> @_copy_ref_box_heap_Uxi32 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %[[I2:.*]]#0 -> @_copy_ref_box_heap_i32 : !fir.ref<!fir.box<!fir.heap<i32>>>, %[[I3]]#0 -> @_copy_ref_box_ptr_i32 : !fir.ref<!fir.box<!fir.ptr<i32>>>, %[[R1]]#0 -> @_copy_ref_box_ptr_Uxf32 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>,  %[[C1]]#0 -> @_copy_ref_box_heap_Uxc8x5 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,5>>>>>, %[[C2]]#0 -> @_copy_ref_box_ptr_Uxc8x9 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,9>>>>>)
 subroutine test_attr()
   integer, allocatable :: i1(:)
   integer, allocatable :: i2
diff --git a/flang/test/Lower/OpenMP/copyprivate2.f90 b/flang/test/Lower/OpenMP/copyprivate2.f90
index 993a81d199f56..9e2eb49779bb2 100644
--- a/flang/test/Lower/OpenMP/copyprivate2.f90
+++ b/flang/test/Lower/OpenMP/copyprivate2.f90
@@ -1,30 +1,30 @@
 ! Test lowering of COPYPRIVATE with allocatable/pointer variables.
 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s
 
-!CHECK-LABEL: func private @_copy_box_ptr_i32(
+!CHECK-LABEL: func private @_copy_ref_box_ptr_i32(
 !CHECK-SAME:                  %[[ARG0:.*]]: !fir.ref<!fir.box<!fir.ptr<i32>>>,
 !CHECK-SAME:                  %[[ARG1:.*]]: !fir.ref<!fir.box<!fir.ptr<i32>>>)
 !CHECK-SAME:                  attributes {llvm.linkage = #llvm.linkage<internal>} {
 !CHECK-NEXT:    %[[DST:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs<pointer>,
-!CHECK-SAME:      uniq_name = "_copy_box_ptr_i32_dst"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) ->
+!CHECK-SAME:      uniq_name = "_copy_ref_box_ptr_i32_dst"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) ->
 !CHECK-SAME:      (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
 !CHECK-NEXT:    %[[SRC:.*]]:2 = hlfir.declare %[[ARG1]] {fortran_attrs = #fir.var_attrs<pointer>,
-!CHECK-SAME:      uniq_name = "_copy_box_ptr_i32_src"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) ->
+!CHECK-SAME:      uniq_name = "_copy_ref_box_ptr_i32_src"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) ->
 !CHECK-SAME:      (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
 !CHECK-NEXT:    %[[SRC_VAL:.*]] = fir.load %[[SRC]]#0 : !fir.ref<!fir.box<!fir.ptr<i32>>>
 !CHECK-NEXT:    fir.store %[[SRC_VAL]] to %[[DST]]#0 : !fir.ref<!fir.box<!fir.ptr<i32>>>
 !CHECK-NEXT:    return
 !CHECK-NEXT:  }
 
-!CHECK-LABEL: func private @_copy_box_heap_Uxi32(
+!CHECK-LABEL: func private @_copy_ref_box_heap_Uxi32(
 !CHECK-SAME:        %[[ARG0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>,
 !CHECK-SAME:        %[[ARG1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
 !CHECK-SAME:        attributes {llvm.linkage = #llvm.linkage<internal>} {
 !CHECK-NEXT:    %[[DST:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs<allocatable>,
-!CHECK-SAME:      uniq_name = "_copy_box_heap_Uxi32_dst"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) ->
+!CHECK-SAME:      uniq_name = "_copy_ref_box_heap_Uxi32_dst"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) ->
 !CHECK-SAME:      (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
 !CHECK-NEXT:    %[[SRC:.*]]:2 = hlfir.declare %[[ARG1]] {fortran_attrs = #fir.var_attrs<allocatable>,
-!CHECK-SAME:      uniq_name = "_copy_box_heap_Uxi32_src"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) ->
+!CHECK-SAME:      uniq_name = "_copy_ref_box_heap_Uxi32_src"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) ->
 !CHECK-SAME:      (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
 !CHECK-NEXT:    %[[SRC_BOX:.*]] = fir.load %[[SRC]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
 !CHECK-NEXT:    hlfir.assign %[[SRC_BOX]] to %[[DST]]#0 realloc : !fir.box<!fir.heap<!fir.array<?xi32>>>,
@@ -41,8 +41,8 @@
 !CHECK-SAME:        uniq_name = "_QFtest_alloc_ptrEp"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) ->
 !CHECK-SAME:        (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
 !CHECK:           omp.single copyprivate(
-!CHECK-SAME:        %[[A]]#0 -> @_copy_box_heap_Uxi32 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>,
-!CHECK-SAME:        %[[P]]#0 -> @_copy_box_ptr_i32 : !fir.ref<!fir.box<!fir.ptr<i32>>>)
+!CHECK-SAME:        %[[A]]#0 -> @_copy_ref_box_heap_Uxi32 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>,
+!CHECK-SAME:        %[[P]]#0 -> @_copy_ref_box_ptr_i32 : !fir.ref<!fir.box<!fir.ptr<i32>>>)
 !CHECK:         }
 subroutine test_alloc_ptr()
   integer, allocatable :: a(:)
diff --git a/flang/test/Lower/OpenMP/copyprivate3.f90 b/flang/test/Lower/OpenMP/copyprivate3.f90
index 13926e45f1948..4bc58ac5e849b 100644
--- a/flang/test/Lower/OpenMP/copyprivate3.f90
+++ b/flang/test/Lower/OpenMP/copyprivate3.f90
@@ -3,7 +3,7 @@
 
 !CHICK-SAME:    %arg0: [[TYPE:!fir.ref<!fir.boxproc<() -> i32>>>]],
 
-!CHECK-LABEL: func.func private @_copy_boxproc_i32_args(
+!CHECK-LABEL: func.func private @_copy_ref_boxproc_i32_args(
 !CHECK-SAME:        %arg0: [[TYPE:!fir.ref<!fir.boxproc<\(\) -> i32>>]],
 !CHECK-SAME:        %arg1: [[TYPE]])
 !CHECK:         %[[DST:.*]]:2 = hlfir.declare %arg0 {{.*}} : ([[TYPE]]) -> ([[TYPE]], [[TYPE]])
@@ -14,7 +14,7 @@
 
 !CHECK-LABEL: func @_QPtest_proc_ptr
 !CHECK:         omp.parallel
-!CHECK:           omp.single copyprivate(%{{.*}}#0 -> @_copy_boxproc_i32_args : !fir.ref<!fir.boxproc<() -> i32>>)
+!CHECK:           omp.single copyprivate(%{{.*}}#0 -> @_copy_ref_boxproc_i32_args : !fir.ref<!fir.boxproc<() -> i32>>)
 subroutine test_proc_ptr()
   interface
      function sub1() bind(c) result(ret)
diff --git a/flang/test/Lower/OpenMP/copyprivate4.f90 b/flang/test/Lower/OpenMP/copyprivate4.f90
index 02fdbc71edc59..4c2d8868f5484 100644
--- a/flang/test/Lower/OpenMP/copyprivate4.f90
+++ b/flang/test/Lower/OpenMP/copyprivate4.f90
@@ -4,7 +4,7 @@
 
 !Check that we don't crash on this.
 
-!CHECK: omp.single copyprivate(%6#0 -> @_copy_class_ptr_rec__QFf01Tt : !fir.ref<!fir.class<!fir.ptr<!fir.type<_QFf01Tt>>>>) {
+!CHECK: omp.single copyprivate(%6#0 -> @_copy_ref_class_ptr_rec__QFf01Tt : !fir.ref<!fir.class<!fir.ptr<!fir.type<_QFf01Tt>>>>) {
 !CHECK:   omp.terminator
 !CHECK: }
 
diff --git a/flang/test/Lower/OpenMP/copyprivate5.f90 b/flang/test/Lower/OpenMP/copyprivate5.f90
index c75eb82a45e9f..4564ba1e7c962 100644
--- a/flang/test/Lower/OpenMP/copyprivate5.f90
+++ b/flang/test/Lower/OpenMP/copyprivate5.f90
@@ -3,7 +3,7 @@
 
 ! Testcase from: https://github.com/llvm/llvm-project/issues/142123
 
-! CHECK-LABEL:  func.func private @_copy_boxchar_c8xU(
+! CHECK-LABEL:  func.func private @_copy_ref_boxchar_c8xU(
 ! CHECK-SAME:     %arg0: [[TYPE:!fir.ref<!fir.boxchar<1>>]],
 ! CHECK-SAME:     %arg1: [[TYPE]]) attributes {llvm.linkage = #llvm.linkage<internal>} {
 ! CHECK:    %[[RDST:.*]] = fir.load %arg0 : [[TYPE]]
@@ -19,7 +19,7 @@
 ! CHECK-LABEL: func.func @_QPs(%arg0: !fir.boxchar<1> {fir.bindc_name = "c"}) {
 ! CHECK: %[[ALLOC:.*]] = fir.alloca !fir.boxchar<1>
 ! CHECK: fir.store %[[SRC:.*]] to %[[ALLOC:.*]] : !fir.ref<!fir.boxchar<1>>
-! CHECK: omp.single copyprivate([[ALLOC:.*]] -> @_copy_boxchar_c8xU : !fir.ref<!fir.boxchar<1>>) {
+! CHECK: omp.single copyprivate([[ALLOC:.*]] -> @_copy_ref_boxchar_c8xU : !fir.ref<!fir.boxchar<1>>) {
 ! CHECK:   hlfir.assign %[[NEW_VAL:.*]] to %[[SRC:.*]] : !fir.ref<!fir.char<1,3>>, !fir.boxchar<1>
 ! CHECK:   omp.terminator
 ! CHECK: }

>From b45ad4669b30b479eb155cee7c5d42eff3b7885d Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Thu, 19 Mar 2026 13:24:26 +0100
Subject: [PATCH 9/9] Fix typos in test description

---
 .../test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90  | 2 +-
 flang/test/Semantics/OpenMP/threadprivate-equivalence.f90       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90 b/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
index 19c671d3ff3b9..02ebeea5aeed7 100644
--- a/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
@@ -1,6 +1,6 @@
 ! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp -Wno-openmp-threadprivate-equivalence
 
-! This a test for is an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
+! This is a test for an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
 
 program threadprivate02
   common /blk1/ a1
diff --git a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90 b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
index b36fa01c6fa01..b39fae95c6774 100644
--- a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
+++ b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
@@ -1,6 +1,6 @@
 ! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
 
-! This a test for is an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
+! This is a test for an extension to the OpenMP semantics, see https://github.com/llvm/llvm-project/issues/180493
 
 program threadprivate02
   common /blk1/ a1



More information about the flang-commits mailing list