[clang] 7bee6c1 - [CIR] Upstream handling for member pointer bool and reinterpret casts (#175996)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 20 10:59:21 PST 2026
Author: Andy Kaylor
Date: 2026-01-20T18:59:16Z
New Revision: 7bee6c16e645fa5844917a11a1217255e11f01e0
URL: https://github.com/llvm/llvm-project/commit/7bee6c16e645fa5844917a11a1217255e11f01e0
DIFF: https://github.com/llvm/llvm-project/commit/7bee6c16e645fa5844917a11a1217255e11f01e0.diff
LOG: [CIR] Upstream handling for member pointer bool and reinterpret casts (#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.
Added:
clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp
clang/test/CIR/IR/invalid-cast.cir
Modified:
clang/include/clang/CIR/Dialect/IR/CIROps.td
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
clang/lib/CIR/Dialect/IR/CIRDialect.cpp
clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
clang/test/CIR/CodeGen/pointer-to-data-member-cast.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 958947230290b..27e6a650fde27 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 4ce38f4e0a1f9..72429591a11bb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -2244,6 +2244,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 302a5ae1255fd..7b9fc83403f71 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 4429ca10415d8..57a7cdc4f27a0 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::GetMethodOp, 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 a7d733afd18c6..07d60ae6fb018 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
@@ -93,6 +93,24 @@ class CIRCXXABI {
virtual mlir::Value lowerMethodCmp(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 94342f864fca6..03fbfb2ec8554 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
@@ -81,6 +81,21 @@ class LowerItaniumCXXABI : public CIRCXXABI {
mlir::Value lowerMethodCmp(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
@@ -450,4 +465,50 @@ mlir::Value LowerItaniumCXXABI::lowerMethodCmp(cir::CmpOp op,
return result;
}
+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 ptr
diff CIRTy = getPtrDiffCIRTy(lm);
+ mlir::Value ptr
diff Zero = cir::ConstantOp::create(
+ builder, op.getLoc(), cir::IntAttr::get(ptr
diff CIRTy, 0));
+ mlir::Value ptrField = cir::ExtractMemberOp::create(
+ builder, op.getLoc(), ptr
diff CIRTy, loweredSrc, 0);
+ return cir::CmpOp::create(builder, op.getLoc(), cir::CmpOpKind::ne, ptrField,
+ ptr
diff Zero);
+}
+
} // 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 at +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 at +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
+ }
+}
More information about the cfe-commits
mailing list