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

via flang-commits flang-commits at lists.llvm.org
Thu Mar 19 06:37:46 PDT 2026


Author: Michael Klemm
Date: 2026-03-19T14:37:41+01:00
New Revision: e3415da3cd126b766d0af178e0d332e9ff96bc17

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

LOG: [Flang][OpenMP] Permit THREADPRIVATE variables in EQUIVALENCE statements (#186696)

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.

This PR contains code from downstream PR
https://github.com/arm/arm-toolchain/pull/755 that @tblah pointed to
during the review.

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

Assisted-by: Claude Code, Opus 4.6

Added: 
    flang/test/Lower/OpenMP/copyprivate-equivalence.f90
    flang/test/Semantics/OpenMP/threadprivate-equivalence-nowarn.f90
    flang/test/Semantics/OpenMP/threadprivate-equivalence.f90

Modified: 
    flang/include/flang/Support/Fortran-features.h
    flang/lib/Lower/OpenMP/ClauseProcessor.cpp
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/resolve-directives.cpp
    flang/lib/Support/Fortran-features.cpp
    flang/test/Integration/OpenMP/copyprivate.f90
    flang/test/Lower/OpenMP/copyprivate.f90
    flang/test/Lower/OpenMP/copyprivate2.f90
    flang/test/Lower/OpenMP/copyprivate3.f90
    flang/test/Lower/OpenMP/copyprivate4.f90
    flang/test/Lower/OpenMP/copyprivate5.f90
    flang/test/Semantics/OpenMP/threadprivate02.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index ce35e06091bfd..feadc11ab7f85 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -58,7 +58,8 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
     CudaWarpMatchFunction, DoConcurrentOffload, TransferBOZ, Coarray,
     PointerPassObject, MultipleIdenticalDATA,
     DefaultStructConstructorNullPointer, AssumedRankIoItem,
-    MultipleProgramUnitsOnSameLine, AllocatedForAssociated)
+    MultipleProgramUnitsOnSameLine, AllocatedForAssociated,
+    OpenMPThreadprivateEquivalence)
 
 // Portability and suspicious usage warnings
 ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,

diff  --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 0bd25e36b6468..8e50c38ce68cb 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1126,10 +1126,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/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 179581469e5c9..0c182e35de068 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1361,11 +1361,19 @@ 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 cannot appear in an EQUIVALENCE statement (variable '%s' from common block '/%s/')"_err_en_US,
-            ContextDirectiveAsFortran(), obj->name(), name.symbol->name());
+        if (directive == llvm::omp::Directive::OMPD_threadprivate) {
+          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 {
+          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 c3f9caf5df5d4..7fca738d43ca6 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1120,6 +1120,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);
@@ -3246,6 +3247,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)}) {
@@ -3264,6 +3289,11 @@ void OmpAttributeVisitor::ResolveOmpCommonBlock(
           AddToContextObjectWithExplicitDSA(*resolvedObject, ompFlag);
         }
         details.replace_object(*resolvedObject, index);
+
+        // Propagate the flag to symbols in the equivalence set
+        if (ompFlag == Symbol::Flag::OmpThreadprivate) {
+          PropagateOmpFlagToEquivalenceSet(*resolvedObject, ompFlag);
+        }
       }
     }
   } else {

diff  --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 79fa807af06a6..19080251b6462 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);
@@ -154,6 +161,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/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: }

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..02ebeea5aeed7
--- /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-openmp-threadprivate-equivalence
+
+! 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
+  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

diff  --git a/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90 b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
new file mode 100644
index 0000000000000..b39fae95c6774
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/threadprivate-equivalence.f90
@@ -0,0 +1,17 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+
+! 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
+  real :: a1
+  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/') [-Wopenmp-threadprivate-equivalence]
+  !$omp threadprivate(/blk1/)
+
+  !ERROR: A THREADPRIVATE variable cannot be in SHARED clause
+  !$omp parallel shared(eq_a)
+  !$omp end parallel
+end

diff  --git a/flang/test/Semantics/OpenMP/threadprivate02.f90 b/flang/test/Semantics/OpenMP/threadprivate02.f90
index 9dc031a8ce47e..6ac024780aa79 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/') [-Wopenmp-threadprivate-equivalence]
   !$omp threadprivate(/blk2/)
 
 contains


        


More information about the flang-commits mailing list