[flang-commits] [flang] [flang][FIRToMemRef] Treat heap-pointer allocas as static, not as dynamic arrays (PR #223821)

Susan Tan ス-ザン タン via flang-commits flang-commits at lists.llvm.org
Tue Sep 15 13:57:36 PDT 2026


https://github.com/SusanTan updated https://github.com/llvm/llvm-project/pull/223821

>From 0128c2f6adcb662c0923a00c3fcf95db32f80f1c Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Tue, 15 Sep 2026 13:35:18 -0700
Subject: [PATCH 1/5] impl

---
 .../Transforms/FIRToMemRefTypeConverter.h     | 123 +++++++++---------
 ...FIROpenACCPointerLikeTypeInterfaceTest.cpp |  21 +++
 2 files changed, 85 insertions(+), 59 deletions(-)

diff --git a/flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h b/flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h
index fd434b1f09c9b..50bdbeec2f376 100644
--- a/flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h
+++ b/flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h
@@ -32,6 +32,49 @@ class FIRToMemRefTypeConverter : public mlir::TypeConverter {
   bool convertComplexTypes = false;
   bool convertScalarTypesOnly = false;
 
+  /// Peel one `!fir.ref` / `!fir.ptr` / `!fir.heap`. Returns a null type if
+  /// \p ty is none of those. Nested wrappers are left on the result; a
+  /// remaining pointer is a pointer slot, not memref data.
+  static mlir::Type peelPointerWrapper(mlir::Type ty) {
+    if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(ty))
+      return refTy.getElementType();
+    if (auto pointerTy = mlir::dyn_cast<fir::PointerType>(ty))
+      return pointerTy.getElementType();
+    if (auto heapTy = mlir::dyn_cast<fir::HeapType>(ty))
+      return heapTy.getElementType();
+    return {};
+  }
+
+  mlir::MemRefType convertMemrefBaseType(mlir::Type baseTy) const {
+    if (auto charTy = mlir::dyn_cast<fir::CharacterType>(baseTy)) {
+      unsigned kind = charTy.getFKind();
+      unsigned bitWidth = kindMapping.getCharacterBitsize(kind);
+      mlir::Type elTy = mlir::IntegerType::get(charTy.getContext(), bitWidth);
+
+      if (charTy.hasConstantLen() && charTy.getLen() == 1)
+        return mlir::MemRefType::get({}, elTy);
+      if (charTy.hasConstantLen())
+        return mlir::MemRefType::get({charTy.getLen()}, elTy);
+      return mlir::MemRefType::get({mlir::ShapedType::kDynamic}, elTy);
+    }
+
+    if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(baseTy)) {
+      mlir::Type ty = convertType(seqTy.getElementType());
+      llvm::ArrayRef<int64_t> firShape = seqTy.getShape();
+      llvm::SmallVector<int64_t> shape;
+      for (auto it = firShape.rbegin(); it != firShape.rend(); ++it)
+        shape.push_back(*it);
+      assert(mlir::BaseMemRefType::isValidElementType(ty) &&
+             "got invalid memref element type from array fir type");
+      return mlir::MemRefType::get(shape, ty);
+    }
+
+    mlir::Type ty = convertType(baseTy);
+    assert(mlir::BaseMemRefType::isValidElementType(ty) &&
+           "got invalid memref element type from scalar fir type");
+    return mlir::MemRefType::get({}, ty);
+  }
+
 public:
   explicit FIRToMemRefTypeConverter(mlir::ModuleOp mod)
       : kindMapping(fir::getKindMapping(mod)) {
@@ -64,19 +107,26 @@ class FIRToMemRefTypeConverter : public mlir::TypeConverter {
   void setConvertScalarTypesOnly(bool value) { convertScalarTypesOnly = value; }
 
   /// Return true if the given FIR type can be converted to a MemRef-typed
-  /// descriptor (i.e. is a supported base element for MemRef converting).
+  /// descriptor. Uses the same `peelPointerWrapper` / `box` recursion as
+  /// `convertMemrefType`. Nested pointers such as
+  /// `!fir.ref<!fir.heap<!fir.array<?xf32>>>` are a pointer slot, not the
+  /// array, and are not convertible.
   bool convertibleMemrefType(mlir::Type ty) {
-    if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(ty))
-      return convertibleMemrefType(refTy.getElementType());
-    else if (auto pointerTy = mlir::dyn_cast<fir::PointerType>(ty))
-      return convertibleMemrefType(pointerTy.getElementType());
-    else if (auto heapTy = mlir::dyn_cast<fir::HeapType>(ty))
-      return convertibleMemrefType(heapTy.getElementType());
-    else if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty))
-      return convertibleMemrefType(seqTy.getElementType());
+    if (mlir::Type pointee = peelPointerWrapper(ty))
+      ty = pointee;
     else if (auto boxTy = mlir::dyn_cast<fir::BoxType>(ty))
       return convertibleMemrefType(boxTy.getElementType());
 
+    // convertMemrefType peels only one pointer wrapper. A remaining pointer
+    // or box is not a valid memref element.
+    if (fir::isa_ref_type(ty) || fir::isa_box_type(ty))
+      return false;
+
+    if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty))
+      ty = seqTy.getElementType();
+    if (fir::isa_ref_type(ty) || fir::isa_box_type(ty))
+      return false;
+
     setConvertScalarTypesOnly(true);
     bool result = convertibleType(ty);
     setConvertScalarTypesOnly(false);
@@ -140,64 +190,19 @@ class FIRToMemRefTypeConverter : public mlir::TypeConverter {
 
   /// Convert a FIR element / aggregate type to a MemRef descriptor type.
   mlir::MemRefType convertMemrefType(mlir::Type firTy) const {
-    auto convertBaseType = [&](mlir::Type firTy) -> mlir::MemRefType {
-      if (auto charTy = mlir::dyn_cast<fir::CharacterType>(firTy)) {
-        unsigned kind = charTy.getFKind();
-        unsigned bitWidth = kindMapping.getCharacterBitsize(kind);
-        mlir::Type elTy = mlir::IntegerType::get(charTy.getContext(), bitWidth);
-
-        if (charTy.hasConstantLen() && charTy.getLen() == 1) {
-          return mlir::MemRefType::get({}, elTy);
-        } else if (charTy.hasConstantLen()) {
-          int64_t len = charTy.getLen();
-          return mlir::MemRefType::get({len}, elTy);
-        } else {
-          return mlir::MemRefType::get({mlir::ShapedType::kDynamic}, elTy);
-        }
-      }
-
-      if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(firTy)) {
-        auto elTy = seqTy.getElementType();
-        mlir::Type ty = convertType(elTy);
-
-        llvm::ArrayRef<int64_t> firShape = seqTy.getShape();
-        llvm::SmallVector<int64_t> shape;
-        for (auto it = firShape.rbegin(); it != firShape.rend(); ++it)
-          shape.push_back(*it);
-
-        assert(mlir::BaseMemRefType::isValidElementType(ty) &&
-               "got invalid memref element type from array fir type");
-        return mlir::MemRefType::get(shape, ty);
-      }
-
-      mlir::Type ty = convertType(firTy);
-      assert(mlir::BaseMemRefType::isValidElementType(ty) &&
-             "got invalid memref element type from scalar fir type");
-      return mlir::MemRefType::get({}, ty);
-    };
-
-    if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(firTy))
-      return convertBaseType(refTy.getElementType());
-
-    if (auto pointerTy = mlir::dyn_cast<fir::PointerType>(firTy))
-      return convertBaseType(pointerTy.getElementType());
-
-    if (auto heapTy = mlir::dyn_cast<fir::HeapType>(firTy))
-      return convertBaseType(heapTy.getElementType());
+    if (mlir::Type pointee = peelPointerWrapper(firTy))
+      return convertMemrefBaseType(pointee);
 
     if (auto boxTy = mlir::dyn_cast<fir::BoxType>(firTy)) {
-      auto elTy = boxTy.getElementType();
-
-      auto memRefTy = convertMemrefType(elTy);
-      mlir::MemRefType dynTy = mlir::MemRefType::Builder(memRefTy).setLayout(
+      mlir::MemRefType memRefTy = convertMemrefType(boxTy.getElementType());
+      return mlir::MemRefType::Builder(memRefTy).setLayout(
           mlir::StridedLayoutAttr::get(
               memRefTy.getContext(), mlir::ShapedType::kDynamic,
               llvm::SmallVector<int64_t>(memRefTy.getRank(),
                                          mlir::ShapedType::kDynamic)));
-      return dynTy;
     }
 
-    return convertBaseType(firTy);
+    return convertMemrefBaseType(firTy);
   }
 };
 
diff --git a/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp b/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
index 4000ed6f68091..f25ad3e98208e 100644
--- a/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
+++ b/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
@@ -14,6 +14,7 @@
 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
 #include "flang/Optimizer/OpenACC/Support/RegisterOpenACCExtensions.h"
 #include "flang/Optimizer/Support/InitFIR.h"
+#include "flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h"
 
 using namespace mlir;
 
@@ -121,4 +122,24 @@ TEST_F(FIROpenACCPointerLikeTypeInterfaceTest,
   EXPECT_EQ(elTy.getWidth(), kindMap->getLogicalBitsize(logicalKind));
 }
 
+TEST_F(FIROpenACCPointerLikeTypeInterfaceTest,
+    GetAsMemRefTypeFromFirRefToHeapArrayIsNotConvertible) {
+  Type f32 = Float32Type::get(&context);
+  Type seq = fir::SequenceType::get({ShapedType::kDynamic}, f32);
+  Type heapTy = fir::HeapType::get(seq);
+  Type refTy = fir::ReferenceType::get(heapTy);
+  auto ptrLike = cast<acc::PointerLikeType>(refTy);
+
+  // A ref-to-heap-array is a pointer slot, not the array data.
+  // convertibleMemrefType must not peel the inner heap, or getAsMemRefType
+  // would call convertMemrefType and assert.
+  EXPECT_FALSE(ptrLike.getAsMemRefType(module));
+
+  fir::FIRToMemRefTypeConverter converter(module);
+  converter.setConvertComplexTypes(true);
+  EXPECT_TRUE(converter.convertibleMemrefType(heapTy));
+  EXPECT_FALSE(converter.convertibleMemrefType(refTy));
+  EXPECT_TRUE(converter.convertibleMemrefType(fir::BoxType::get(heapTy)));
+}
+
 } // namespace

>From 42e55576f3f9f2631e30955caa616fcedf8baf32 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Tue, 15 Sep 2026 13:35:46 -0700
Subject: [PATCH 2/5] tweak

---
 .../flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h     | 4 ++--
 .../OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp        | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h b/flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h
index 50bdbeec2f376..36b3ef62a3a05 100644
--- a/flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h
+++ b/flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h
@@ -34,7 +34,7 @@ class FIRToMemRefTypeConverter : public mlir::TypeConverter {
 
   /// Peel one `!fir.ref` / `!fir.ptr` / `!fir.heap`. Returns a null type if
   /// \p ty is none of those. Nested wrappers are left on the result; a
-  /// remaining pointer is a pointer slot, not memref data.
+  /// remaining pointer is a heap/pointer address, not memref data.
   static mlir::Type peelPointerWrapper(mlir::Type ty) {
     if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(ty))
       return refTy.getElementType();
@@ -109,7 +109,7 @@ class FIRToMemRefTypeConverter : public mlir::TypeConverter {
   /// Return true if the given FIR type can be converted to a MemRef-typed
   /// descriptor. Uses the same `peelPointerWrapper` / `box` recursion as
   /// `convertMemrefType`. Nested pointers such as
-  /// `!fir.ref<!fir.heap<!fir.array<?xf32>>>` are a pointer slot, not the
+  /// `!fir.ref<!fir.heap<!fir.array<?xf32>>>` hold a heap address, not the
   /// array, and are not convertible.
   bool convertibleMemrefType(mlir::Type ty) {
     if (mlir::Type pointee = peelPointerWrapper(ty))
diff --git a/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp b/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
index f25ad3e98208e..d5dc81fe2480f 100644
--- a/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
+++ b/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
@@ -130,7 +130,7 @@ TEST_F(FIROpenACCPointerLikeTypeInterfaceTest,
   Type refTy = fir::ReferenceType::get(heapTy);
   auto ptrLike = cast<acc::PointerLikeType>(refTy);
 
-  // A ref-to-heap-array is a pointer slot, not the array data.
+  // A ref-to-heap-array holds a heap address, not the array data.
   // convertibleMemrefType must not peel the inner heap, or getAsMemRefType
   // would call convertMemrefType and assert.
   EXPECT_FALSE(ptrLike.getAsMemRefType(module));

>From 4b1bb6593334251c12c85cbf2d105f283b5ac855 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Tue, 15 Sep 2026 13:42:40 -0700
Subject: [PATCH 3/5] add more tests

---
 ...FIROpenACCPointerLikeTypeInterfaceTest.cpp | 53 ++++++++++++++-----
 1 file changed, 40 insertions(+), 13 deletions(-)

diff --git a/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp b/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
index d5dc81fe2480f..c1d6e32bc405e 100644
--- a/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
+++ b/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
@@ -123,23 +123,50 @@ TEST_F(FIROpenACCPointerLikeTypeInterfaceTest,
 }
 
 TEST_F(FIROpenACCPointerLikeTypeInterfaceTest,
-    GetAsMemRefTypeFromFirRefToHeapArrayIsNotConvertible) {
+       NestedPointerTypesAreNotConvertible) {
   Type f32 = Float32Type::get(&context);
-  Type seq = fir::SequenceType::get({ShapedType::kDynamic}, f32);
-  Type heapTy = fir::HeapType::get(seq);
-  Type refTy = fir::ReferenceType::get(heapTy);
-  auto ptrLike = cast<acc::PointerLikeType>(refTy);
-
-  // A ref-to-heap-array holds a heap address, not the array data.
-  // convertibleMemrefType must not peel the inner heap, or getAsMemRefType
-  // would call convertMemrefType and assert.
-  EXPECT_FALSE(ptrLike.getAsMemRefType(module));
+  Type dyn1 = fir::SequenceType::get({ShapedType::kDynamic}, f32);
+  Type dyn2 =
+      fir::SequenceType::get({ShapedType::kDynamic, ShapedType::kDynamic}, f32);
+  Type stat = fir::SequenceType::get({16}, f32);
 
   fir::FIRToMemRefTypeConverter converter(module);
   converter.setConvertComplexTypes(true);
-  EXPECT_TRUE(converter.convertibleMemrefType(heapTy));
-  EXPECT_FALSE(converter.convertibleMemrefType(refTy));
-  EXPECT_TRUE(converter.convertibleMemrefType(fir::BoxType::get(heapTy)));
+  auto conv = [&](Type t) { return converter.convertibleMemrefType(t); };
+
+  // One pointer/box to the array or scalar is convertible.
+  EXPECT_TRUE(conv(fir::HeapType::get(dyn1)));
+  EXPECT_TRUE(conv(fir::PointerType::get(dyn1)));
+  EXPECT_TRUE(conv(fir::ReferenceType::get(dyn1)));
+  EXPECT_TRUE(conv(fir::HeapType::get(dyn2)));
+  EXPECT_TRUE(conv(fir::HeapType::get(stat)));
+  EXPECT_TRUE(conv(fir::HeapType::get(f32)));
+  EXPECT_TRUE(conv(fir::BoxType::get(fir::HeapType::get(dyn1))));
+  EXPECT_TRUE(conv(fir::BoxType::get(fir::PointerType::get(dyn1))));
+  EXPECT_TRUE(conv(fir::BoxType::get(dyn1)));
+
+  // A remaining pointer after one peel holds an address, not the array.
+  EXPECT_FALSE(conv(fir::ReferenceType::get(fir::HeapType::get(dyn1))));
+  EXPECT_FALSE(conv(fir::ReferenceType::get(fir::PointerType::get(dyn1))));
+  EXPECT_FALSE(conv(fir::PointerType::get(fir::HeapType::get(dyn1))));
+  EXPECT_FALSE(conv(fir::HeapType::get(fir::PointerType::get(dyn1))));
+  EXPECT_FALSE(conv(fir::ReferenceType::get(fir::ReferenceType::get(dyn1))));
+  EXPECT_FALSE(conv(fir::ReferenceType::get(fir::HeapType::get(dyn2))));
+  EXPECT_FALSE(conv(fir::ReferenceType::get(fir::HeapType::get(stat))));
+  EXPECT_FALSE(conv(fir::ReferenceType::get(fir::HeapType::get(f32))));
+  EXPECT_FALSE(conv(
+      fir::ReferenceType::get(fir::BoxType::get(fir::HeapType::get(dyn1)))));
+  EXPECT_FALSE(conv(
+      fir::BoxType::get(fir::ReferenceType::get(fir::HeapType::get(dyn1)))));
+
+  auto asMemRef = [&](Type t) {
+    return cast<acc::PointerLikeType>(t).getAsMemRefType(module);
+  };
+  EXPECT_FALSE(asMemRef(fir::ReferenceType::get(fir::HeapType::get(dyn1))));
+  EXPECT_FALSE(asMemRef(fir::ReferenceType::get(fir::PointerType::get(dyn1))));
+  EXPECT_FALSE(asMemRef(fir::PointerType::get(fir::HeapType::get(dyn1))));
+  EXPECT_FALSE(asMemRef(fir::HeapType::get(fir::PointerType::get(dyn1))));
+  EXPECT_FALSE(asMemRef(fir::ReferenceType::get(fir::HeapType::get(f32))));
 }
 
 } // namespace

>From 108d77b58bb2143c6a768200b86930338d567ed2 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Tue, 15 Sep 2026 13:45:35 -0700
Subject: [PATCH 4/5] tweak

---
 .../OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp     | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp b/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
index c1d6e32bc405e..14658ce4c28fb 100644
--- a/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
+++ b/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
@@ -123,7 +123,7 @@ TEST_F(FIROpenACCPointerLikeTypeInterfaceTest,
 }
 
 TEST_F(FIROpenACCPointerLikeTypeInterfaceTest,
-       NestedPointerTypesAreNotConvertible) {
+    NestedPointerTypesAreNotConvertible) {
   Type f32 = Float32Type::get(&context);
   Type dyn1 = fir::SequenceType::get({ShapedType::kDynamic}, f32);
   Type dyn2 =
@@ -146,10 +146,9 @@ TEST_F(FIROpenACCPointerLikeTypeInterfaceTest,
   EXPECT_TRUE(conv(fir::BoxType::get(dyn1)));
 
   // A remaining pointer after one peel holds an address, not the array.
+  // `!fir.ptr`/`!fir.heap` cannot wrap another pointer type.
   EXPECT_FALSE(conv(fir::ReferenceType::get(fir::HeapType::get(dyn1))));
   EXPECT_FALSE(conv(fir::ReferenceType::get(fir::PointerType::get(dyn1))));
-  EXPECT_FALSE(conv(fir::PointerType::get(fir::HeapType::get(dyn1))));
-  EXPECT_FALSE(conv(fir::HeapType::get(fir::PointerType::get(dyn1))));
   EXPECT_FALSE(conv(fir::ReferenceType::get(fir::ReferenceType::get(dyn1))));
   EXPECT_FALSE(conv(fir::ReferenceType::get(fir::HeapType::get(dyn2))));
   EXPECT_FALSE(conv(fir::ReferenceType::get(fir::HeapType::get(stat))));
@@ -164,8 +163,6 @@ TEST_F(FIROpenACCPointerLikeTypeInterfaceTest,
   };
   EXPECT_FALSE(asMemRef(fir::ReferenceType::get(fir::HeapType::get(dyn1))));
   EXPECT_FALSE(asMemRef(fir::ReferenceType::get(fir::PointerType::get(dyn1))));
-  EXPECT_FALSE(asMemRef(fir::PointerType::get(fir::HeapType::get(dyn1))));
-  EXPECT_FALSE(asMemRef(fir::HeapType::get(fir::PointerType::get(dyn1))));
   EXPECT_FALSE(asMemRef(fir::ReferenceType::get(fir::HeapType::get(f32))));
 }
 

>From 7663b876bf2ed0f45c6395d0e6d9faee3bc35e90 Mon Sep 17 00:00:00 2001
From: Susan Tan <zujunt at nvidia.com>
Date: Tue, 15 Sep 2026 13:57:23 -0700
Subject: [PATCH 5/5] tweak

---
 .../Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp b/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
index 14658ce4c28fb..9e86baf6df78c 100644
--- a/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
+++ b/flang/unittests/Optimizer/OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
@@ -149,7 +149,6 @@ TEST_F(FIROpenACCPointerLikeTypeInterfaceTest,
   // `!fir.ptr`/`!fir.heap` cannot wrap another pointer type.
   EXPECT_FALSE(conv(fir::ReferenceType::get(fir::HeapType::get(dyn1))));
   EXPECT_FALSE(conv(fir::ReferenceType::get(fir::PointerType::get(dyn1))));
-  EXPECT_FALSE(conv(fir::ReferenceType::get(fir::ReferenceType::get(dyn1))));
   EXPECT_FALSE(conv(fir::ReferenceType::get(fir::HeapType::get(dyn2))));
   EXPECT_FALSE(conv(fir::ReferenceType::get(fir::HeapType::get(stat))));
   EXPECT_FALSE(conv(fir::ReferenceType::get(fir::HeapType::get(f32))));



More information about the flang-commits mailing list