https://github.com/andykaylor created 
https://github.com/llvm/llvm-project/pull/175996

This change upstreams the code to generate CIR for bool casts and reinterpret 
casts involving member pointer types and the code to lower these casts for the 
Itanium C++ ABI.

>From d53e6dfa53ef31579a2087610f3c2559e84ab49a Mon Sep 17 00:00:00 2001
From: Andy Kaylor <[email protected]>
Date: Tue, 13 Jan 2026 16:15:28 -0800
Subject: [PATCH] [CIR] Upstream handling for member pointer bool and
 reinterpret casts

This change upstreams the code to generate CIR for bool casts and
reinterpret casts involving member pointer types and the code to
lower these casts for the Itanium C++ ABI.
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  1 +
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp    |  5 ++
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 11 ++-
 .../CIR/Dialect/Transforms/CXXABILowering.cpp | 42 ++++++++++-
 .../Transforms/TargetLowering/CIRCXXABI.h     | 18 +++++
 .../TargetLowering/LowerItaniumCXXABI.cpp     | 61 ++++++++++++++++
 .../CodeGen/pointer-to-data-member-cast.cpp   | 55 ++++++++++++++
 .../CodeGen/pointer-to-member-func-cast.cpp   | 71 +++++++++++++++++++
 clang/test/CIR/IR/invalid-cast.cir            | 27 +++++++
 9 files changed, 287 insertions(+), 4 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp
 create mode 100644 clang/test/CIR/IR/invalid-cast.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index ceb9899a00ac4..8352f99380845 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -241,6 +241,7 @@ def CIR_CastOp : CIR_Op<"cast", [
   // The input and output types should match the cast kind.
   let hasVerifier = 1;
   let hasFolder = 1;
+  let hasCXXABILowering = 1;
 
   let extraLLVMLoweringPatternDecl = [{
     mlir::Type convertTy(mlir::Type ty) const;
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 2a4e6d9b89ee4..8a3af1ffcdbdf 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -2243,6 +2243,11 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr 
*ce) {
     return builder.getNullDataMemberPtr(ty, cgf.getLoc(subExpr->getExprLoc()));
   }
 
+  case CK_ReinterpretMemberPointer: {
+    mlir::Value src = Visit(subExpr);
+    return builder.createBitcast(cgf.getLoc(subExpr->getExprLoc()), src,
+                                 cgf.convertType(destTy));
+  }
   case CK_BaseToDerivedMemberPointer:
   case CK_DerivedToBaseMemberPointer: {
     mlir::Value src = Visit(subExpr);
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 6c4607abb40e7..1be7fe06d8be3 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -657,9 +657,16 @@ LogicalResult cir::CastOp::verify() {
              << "requires floating point !cir.complex type for result";
     return success();
   }
-  default:
-    llvm_unreachable("Unknown CastOp kind?");
+  case cir::CastKind::member_ptr_to_bool: {
+    if (!mlir::isa<cir::DataMemberType, cir::MethodType>(srcType))
+      return emitOpError()
+             << "requires !cir.data_member or !cir.method type for source";
+    if (!mlir::isa<cir::BoolType>(resType))
+      return emitOpError() << "requires !cir.bool type for result";
+    return success();
+  }
   }
+  llvm_unreachable("Unknown CastOp kind?");
 }
 
 static bool isIntOrBoolCast(cir::CastOp op) {
diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index 145f8574893f4..2a928a556b762 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -57,8 +57,8 @@ class CIRGenericCXXABILoweringPattern : public 
mlir::ConversionPattern {
   matchAndRewrite(mlir::Operation *op, llvm::ArrayRef<mlir::Value> operands,
                   mlir::ConversionPatternRewriter &rewriter) const override {
     // Do not match on operations that have dedicated ABI lowering rewrite 
rules
-    if (llvm::isa<cir::AllocaOp, cir::BaseDataMemberOp, cir::ConstantOp,
-                  cir::CmpOp, cir::DerivedDataMemberOp, cir::FuncOp,
+    if (llvm::isa<cir::AllocaOp, cir::BaseDataMemberOp, cir::CastOp, 
cir::CmpOp,
+                  cir::ConstantOp, cir::DerivedDataMemberOp, cir::FuncOp,
                   cir::GetRuntimeMemberOp, cir::GlobalOp>(op))
       return mlir::failure();
 
@@ -130,6 +130,44 @@ mlir::LogicalResult 
CIRAllocaOpABILowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRCastOpABILowering::matchAndRewrite(
+    cir::CastOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  mlir::Type srcTy = op.getSrc().getType();
+  assert((mlir::isa<cir::DataMemberType, cir::MethodType>(srcTy)) &&
+         "input to bitcast in ABI lowering must be a data member or method");
+
+  switch (op.getKind()) {
+  case cir::CastKind::bitcast: {
+    mlir::Type destTy = getTypeConverter()->convertType(op.getType());
+    mlir::Value loweredResult;
+    if (mlir::isa<cir::DataMemberType>(srcTy))
+      loweredResult = lowerModule->getCXXABI().lowerDataMemberBitcast(
+          op, destTy, adaptor.getSrc(), rewriter);
+    else
+      loweredResult = lowerModule->getCXXABI().lowerMethodBitcast(
+          op, destTy, adaptor.getSrc(), rewriter);
+    rewriter.replaceOp(op, loweredResult);
+    return mlir::success();
+  }
+  case cir::CastKind::member_ptr_to_bool: {
+    mlir::Value loweredResult;
+    if (mlir::isa<cir::MethodType>(srcTy))
+      loweredResult = lowerModule->getCXXABI().lowerMethodToBoolCast(
+          op, adaptor.getSrc(), rewriter);
+    else
+      loweredResult = lowerModule->getCXXABI().lowerDataMemberToBoolCast(
+          op, adaptor.getSrc(), rewriter);
+    rewriter.replaceOp(op, loweredResult);
+    return mlir::success();
+  }
+  default:
+    break;
+  }
+
+  return mlir::failure();
+}
+
 mlir::LogicalResult CIRConstantOpABILowering::matchAndRewrite(
     cir::ConstantOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
index 0dedfa7221f5f..a7ff9f848fb7a 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
@@ -81,6 +81,24 @@ class CIRCXXABI {
   virtual mlir::Value lowerDataMemberCmp(cir::CmpOp op, mlir::Value loweredLhs,
                                          mlir::Value loweredRhs,
                                          mlir::OpBuilder &builder) const = 0;
+
+  virtual mlir::Value
+  lowerDataMemberBitcast(cir::CastOp op, mlir::Type loweredDstTy,
+                         mlir::Value loweredSrc,
+                         mlir::OpBuilder &builder) const = 0;
+
+  virtual mlir::Value
+  lowerDataMemberToBoolCast(cir::CastOp op, mlir::Value loweredSrc,
+                            mlir::OpBuilder &builder) const = 0;
+
+  virtual mlir::Value lowerMethodBitcast(cir::CastOp op,
+                                         mlir::Type loweredDstTy,
+                                         mlir::Value loweredSrc,
+                                         mlir::OpBuilder &builder) const = 0;
+
+  virtual mlir::Value lowerMethodToBoolCast(cir::CastOp op,
+                                            mlir::Value loweredSrc,
+                                            mlir::OpBuilder &builder) const = 
0;
 };
 
 /// Creates an Itanium-family ABI.
diff --git 
a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
index d944fa3294684..82f17340264c4 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
@@ -67,6 +67,21 @@ class LowerItaniumCXXABI : public CIRCXXABI {
   mlir::Value lowerDataMemberCmp(cir::CmpOp op, mlir::Value loweredLhs,
                                  mlir::Value loweredRhs,
                                  mlir::OpBuilder &builder) const override;
+
+  mlir::Value lowerDataMemberBitcast(cir::CastOp op, mlir::Type loweredDstTy,
+                                     mlir::Value loweredSrc,
+                                     mlir::OpBuilder &builder) const override;
+
+  mlir::Value
+  lowerDataMemberToBoolCast(cir::CastOp op, mlir::Value loweredSrc,
+                            mlir::OpBuilder &builder) const override;
+
+  mlir::Value lowerMethodBitcast(cir::CastOp op, mlir::Type loweredDstTy,
+                                 mlir::Value loweredSrc,
+                                 mlir::OpBuilder &builder) const override;
+
+  mlir::Value lowerMethodToBoolCast(cir::CastOp op, mlir::Value loweredSrc,
+                                    mlir::OpBuilder &builder) const override;
 };
 
 } // namespace
@@ -249,4 +264,50 @@ LowerItaniumCXXABI::lowerDataMemberCmp(cir::CmpOp op, 
mlir::Value loweredLhs,
                             loweredRhs);
 }
 
+mlir::Value LowerItaniumCXXABI::lowerDataMemberBitcast(
+    cir::CastOp op, mlir::Type loweredDstTy, mlir::Value loweredSrc,
+    mlir::OpBuilder &builder) const {
+  if (loweredSrc.getType() == loweredDstTy)
+    return loweredSrc;
+
+  return cir::CastOp::create(builder, op.getLoc(), loweredDstTy,
+                             cir::CastKind::bitcast, loweredSrc);
+}
+
+mlir::Value LowerItaniumCXXABI::lowerDataMemberToBoolCast(
+    cir::CastOp op, mlir::Value loweredSrc, mlir::OpBuilder &builder) const {
+  // Itanium C++ ABI 2.3:
+  //   A NULL pointer is represented as -1.
+  auto nullAttr = cir::IntAttr::get(getPtrDiffCIRTy(lm), -1);
+  auto nullValue = cir::ConstantOp::create(builder, op.getLoc(), nullAttr);
+  return cir::CmpOp::create(builder, op.getLoc(), cir::CmpOpKind::ne,
+                            loweredSrc, nullValue);
+}
+
+mlir::Value
+LowerItaniumCXXABI::lowerMethodBitcast(cir::CastOp op, mlir::Type loweredDstTy,
+                                       mlir::Value loweredSrc,
+                                       mlir::OpBuilder &builder) const {
+  if (loweredSrc.getType() == loweredDstTy)
+    return loweredSrc;
+
+  return loweredSrc;
+}
+
+mlir::Value LowerItaniumCXXABI::lowerMethodToBoolCast(
+    cir::CastOp op, mlir::Value loweredSrc, mlir::OpBuilder &builder) const {
+  // Itanium C++ ABI 2.3.2:
+  //
+  //   In the standard representation, a null member function pointer is
+  //   represented with ptr set to a null pointer. The value of adj is
+  //   unspecified for null member function pointers.
+  cir::IntType ptrdiffCIRTy = getPtrDiffCIRTy(lm);
+  mlir::Value ptrdiffZero = cir::ConstantOp::create(
+      builder, op.getLoc(), cir::IntAttr::get(ptrdiffCIRTy, 0));
+  mlir::Value ptrField = cir::ExtractMemberOp::create(
+      builder, op.getLoc(), ptrdiffCIRTy, loweredSrc, 0);
+  return cir::CmpOp::create(builder, op.getLoc(), cir::CmpOpKind::ne, ptrField,
+                            ptrdiffZero);
+}
+
 } // namespace cir
diff --git a/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp 
b/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp
index 91cf4b1ae5386..d3aca69c3914c 100644
--- a/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp
+++ b/clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp
@@ -133,3 +133,58 @@ auto derived_to_base_zero_offset(int Derived::*ptr) -> int 
Base1::* {
 // OGCG-NEXT:   store i64 %{{.*}}, ptr %[[PTR_ADDR]]
 // OGCG-NEXT:   %[[RET:.*]] = load i64, ptr %[[PTR_ADDR]]
 // OGCG-NEXT:   ret i64 %[[RET]]
+
+struct Foo {
+  int a;
+};
+
+struct Bar {
+  int a;
+};
+
+bool to_bool(int Foo::*x) {
+  return x;
+}
+
+// CIR-BEFORE: cir.func {{.*}} @_Z7to_boolM3Fooi
+// CIR-BEFORE:   %[[X:.*]] = cir.load{{.*}} %{{.*}} : 
!cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in 
!rec_Foo>
+// CIR-BEFORE:   %{{.*}} = cir.cast member_ptr_to_bool %[[X]] : 
!cir.data_member<!s32i in !rec_Foo> -> !cir.bool
+
+// CIR-AFTER: cir.func {{.*}} @_Z7to_boolM3Fooi
+// CIR-AFTER:   %[[NULL_VAL:.*]] = cir.const #cir.int<-1> : !s64i
+// CIR-AFTER:   %[[BOOL_VAL:.*]] = cir.cmp(ne, %{{.*}}, %[[NULL_VAL]]) : 
!s64i, !cir.bool
+
+// LLVM: define {{.*}} i1 @_Z7to_boolM3Fooi
+// LLVM:   %[[X:.*]] = load i64, ptr %{{.*}}
+// LLVM:   %[[IS_NULL:.*]] = icmp ne i64 %[[X]], -1
+
+// OGCG: define {{.*}} i1 @_Z7to_boolM3Fooi
+// OGCG:   %[[X:.*]] = load i64, ptr %{{.*}}
+// OGCG:   %[[IS_NULL:.*]] = icmp ne i64 %[[X]], -1
+
+auto bitcast(int Foo::*x) {
+  return reinterpret_cast<int Bar::*>(x);
+}
+
+// CIR-BEFORE: cir.func {{.*}} @_Z7bitcastM3Fooi
+// CIR-BEFORE:   %[[X:.*]] = cir.load{{.*}} %{{.*}} : 
!cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in 
!rec_Foo>
+// CIR-BEFORE:   %{{.*}} = cir.cast bitcast %[[X]] : !cir.data_member<!s32i in 
!rec_Foo> -> !cir.data_member<!s32i in !rec_Bar>
+
+// CIR-AFTER: cir.func {{.*}} @_Z7bitcastM3Fooi(%[[ARG0:.*]]: !s64i
+// CIR-AFTER:   %[[X_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, ["x", 
init] {alignment = 8 : i64}
+// CIR-AFTER:   %[[RET_ADDR:.*]] = cir.alloca !s64i, !cir.ptr<!s64i>, 
["__retval"] {alignment = 8 : i64}
+// CIR-AFTER:   cir.store %[[ARG0]], %[[X_ADDR]]
+// CIR-AFTER:   %[[X:.*]] = cir.load{{.*}} %[[X_ADDR]]
+// CIR-AFTER:   cir.store %[[X]], %[[RET_ADDR]]
+// CIR-AFTER:   %[[RET:.*]] = cir.load %[[RET_ADDR]]
+// CIR-AFTER:   cir.return %[[RET]] : !s64i
+
+// LLVM: define {{.*}} i64 @_Z7bitcastM3Fooi
+// LLVM:   %[[X:.*]] = load i64, ptr %{{.*}}
+// LLVM:   store i64 %[[X]], ptr %[[RET_ADDR:.*]]
+// LLVM:   %[[RET:.*]] = load i64, ptr %[[RET_ADDR:.*]]
+// LLVM:   ret i64 %[[RET]]
+
+// OGCG: define {{.*}} i64 @_Z7bitcastM3Fooi
+// OGCG:   %[[X:.*]] = load i64, ptr %{{.*}}
+// OGCG:   ret i64 %[[X]]
diff --git a/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp 
b/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp
new file mode 100644
index 0000000000000..4f18a6a6a9540
--- /dev/null
+++ b/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir 
-emit-cir -mmlir -mlir-print-ir-before=cir-cxxabi-lowering %s -o %t.cir 2> 
%t-before.cir
+// RUN: FileCheck --check-prefix=CIR-BEFORE --input-file=%t-before.cir %s
+// RUN: FileCheck --check-prefix=CIR-AFTER --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir 
-emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll --check-prefix=LLVM %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -emit-llvm %s 
-o %t.ll
+// RUN: FileCheck --input-file=%t.ll --check-prefix=OGCG %s
+
+struct Foo {
+  void m1(int);
+  virtual void m2(int);
+  virtual void m3(int);
+};
+
+struct Bar {
+  void m4();
+};
+
+bool memfunc_to_bool(void (Foo::*func)(int)) {
+  return func;
+}
+
+// CIR-BEFORE: cir.func {{.*}} @_Z15memfunc_to_boolM3FooFviE
+// CIR-BEFORE:   %{{.*}} = cir.cast member_ptr_to_bool %{{.*}} : 
!cir.method<!cir.func<(!s32i)> in !rec_Foo> -> !cir.bool
+
+// CIR-AFTER: cir.func {{.*}} @_Z15memfunc_to_boolM3FooFviE
+// CIR-AFTER:   %[[FUNC:.*]] = cir.load{{.*}} %{{.*}} : 
!cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER:   %[[NULL_VAL:.*]] = cir.const #cir.int<0> : !s64i
+// CIR-AFTER:   %[[FUNC_PTR:.*]] = cir.extract_member %[[FUNC]][0] : 
!rec_anon_struct -> !s64i
+// CIR-AFTER:   %[[BOOL_VAL:.*]] = cir.cmp(ne, %[[FUNC_PTR]], %[[NULL_VAL]]) : 
!s64i, !cir.bool
+
+// LLVM: define {{.*}} i1 @_Z15memfunc_to_boolM3FooFviE
+// LLVM:   %[[FUNC:.*]] = load { i64, i64 }, ptr %{{.*}}
+// LLVM:   %[[FUNC_PTR:.*]] = extractvalue { i64, i64 } %[[FUNC]], 0
+// LLVM:   %{{.*}} = icmp ne i64 %[[FUNC_PTR]], 0
+
+// Note: OGCG uses an extra temporary for the function argument because it
+//       composes it from coerced arguments. We'll do that in CIR too after
+//       calling convention lowering is implemented.
+
+// OGCG: define {{.*}} i1 @_Z15memfunc_to_boolM3FooFviE
+// OGCG:   %[[FUNC_TMP:.*]] = load { i64, i64 }, ptr %{{.*}}
+// OGCG:   store { i64, i64 } %[[FUNC_TMP]], ptr %[[FUNC_ADDR:.*]]
+// OGCG:   %[[FUNC:.*]] = load { i64, i64 }, ptr %[[FUNC_ADDR]]
+// OGCG:   %[[FUNC_PTR:.*]] = extractvalue { i64, i64 } %[[FUNC]], 0
+// OGCG:   %{{.*}} = icmp ne i64 %[[FUNC_PTR]], 0
+
+auto memfunc_reinterpret(void (Foo::*func)(int)) -> void (Bar::*)() {
+  return reinterpret_cast<void (Bar::*)()>(func);
+}
+
+// CIR-BEFORE: cir.func {{.*}} @_Z19memfunc_reinterpretM3FooFviE
+// CIR-BEFORE:   %{{.*}} = cir.cast bitcast %{{.*}} : 
!cir.method<!cir.func<(!s32i)> in !rec_Foo> -> !cir.method<!cir.func<()> in 
!rec_Bar>
+
+// CIR-AFTER: cir.func {{.*}} @_Z19memfunc_reinterpretM3FooFviE
+// CIR-AFTER:   %[[FUNC:.*]] = cir.load{{.*}} %{{.*}} : 
!cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER:   cir.store %[[FUNC]], %[[RET_ADDR:.*]] : !rec_anon_struct, 
!cir.ptr<!rec_anon_struct>
+// CIR-AFTER:   %[[RET:.*]] = cir.load{{.*}} %[[RET_ADDR]] : 
!cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER:   cir.return %[[RET]] : !rec_anon_struct
+
+// LLVM: define {{.*}} { i64, i64 } @_Z19memfunc_reinterpretM3FooFviE
+// LLVM:   %[[FUNC:.*]] = load { i64, i64 }, ptr %{{.*}}
+// LLVM:   store { i64, i64 } %[[FUNC]], ptr %[[RET_ADDR:.*]]
+// LLVM:   %[[RET:.*]] = load { i64, i64 }, ptr %[[RET_ADDR]]
+// LLVM:   ret { i64, i64 } %[[RET]]
+
+// OGCG: define {{.*}} { i64, i64 } @_Z19memfunc_reinterpretM3FooFviE
+// OGCG:   %[[FUNC:.*]] = load { i64, i64 }, ptr %{{.*}}
+// OGCG:   store { i64, i64 } %[[FUNC]], ptr %[[RET_ADDR:.*]]
+// OGCG:   %[[RET:.*]] = load { i64, i64 }, ptr %[[RET_ADDR]]
+// OGCG:   ret { i64, i64 } %[[RET]]
diff --git a/clang/test/CIR/IR/invalid-cast.cir 
b/clang/test/CIR/IR/invalid-cast.cir
new file mode 100644
index 0000000000000..321934215e84d
--- /dev/null
+++ b/clang/test/CIR/IR/invalid-cast.cir
@@ -0,0 +1,27 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!rec_Foo = !cir.record<struct "Foo" {!s32i}>
+
+module {
+  cir.func no_inline dso_local @_Z7to_boolM3Fooi(%arg0: !cir.data_member<!s32i 
in !rec_Foo>) -> !s32i {
+    // expected-error@+1 {{requires !cir.bool type for result}}
+    %0 = cir.cast member_ptr_to_bool %arg0 : !cir.data_member<!s32i in 
!rec_Foo> -> !s32i
+    cir.return %0 : !s32i
+  }
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+!rec_Foo = !cir.record<struct "Foo" {!s32i}>
+
+module {
+  cir.func no_inline dso_local @_Z7to_boolM3Fooi(%arg0: !s32i) -> !cir.bool {
+    // expected-error@+1 {{requires !cir.data_member or !cir.method type for 
source}}
+    %0 = cir.cast member_ptr_to_bool %arg0 : !s32i -> !cir.bool
+    cir.return %0 : !cir.bool
+  }
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to