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

This adds support in CIR for handling based-to-derived and derived-to-base 
casts of pointer-to-member values that point to member functions.

Co-authored-by: Sirui Mu <[email protected]>

>From 1fc2a334e5f01e279aba6bee6bffe3487353ff8a Mon Sep 17 00:00:00 2001
From: Andy Kaylor <[email protected]>
Date: Mon, 26 Jan 2026 09:55:57 -0800
Subject: [PATCH] [CIR] Upstream support for pointer-to-method casts

This adds support in CIR for handling based-to-derived and derived-to-base
casts of pointer-to-member values that point to member functions.
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 121 +++++++++++++++
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp    |   7 +-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       |  28 ++++
 .../CIR/Dialect/Transforms/CXXABILowering.cpp |  23 ++-
 .../Transforms/TargetLowering/CIRCXXABI.h     |  12 ++
 .../TargetLowering/LowerItaniumCXXABI.cpp     |  45 ++++++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  18 +++
 .../CodeGen/pointer-to-member-func-cast.cpp   | 140 ++++++++++++++++++
 clang/test/CIR/IR/invalid-struct.cir          |  47 ++++++
 9 files changed, 436 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index fe35ab305f4ba..fe6e8f76cddb7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2797,6 +2797,55 @@ def CIR_ExtractMemberOp : CIR_Op<"extract_member", 
[Pure]> {
   let hasVerifier = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// InsertMemberOp
+//===----------------------------------------------------------------------===//
+
+def CIR_InsertMemberOp : CIR_Op<"insert_member", [
+  Pure, AllTypesMatch<["record", "result"]>
+]> {
+  let summary = "Overwrite the value of a member of a record value";
+  let description = [{
+    The `cir.insert_member` operation overwrites the value of a particular
+    member in the input record value, and returns the modified record value. 
The
+    result of this operation is equal to the input record value, except for the
+    member specified by `index_attr` whose value is equal to the given value.
+
+    This operation is named after the LLVM instruction `insertvalue`.
+
+    Currently `cir.insert_member` does not work on unions.
+
+    Example:
+
+    ```mlir
+    // Suppose we have a record with multiple members.
+    !s32i = !cir.int<s, 32>
+    !s8i = !cir.int<s, 32>
+    !record_ty = !cir.record<"struct.Bar" {!s32i, !s8i}>
+
+    // And suppose we have a value of the record type.
+    %0 = cir.const #cir.const_record<{#cir.int<1> : !s32i, #cir.int<2> : 
!s8i}> : !record_ty
+    // %0 is {1, 2}
+
+    // Overwrite the second member of the record value.
+    %1 = cir.const #cir.int<3> : !s8i
+    %2 = cir.insert_member %0[1], %1 : !record_ty, !s8i
+    // %2 is {1, 3}
+    ```
+  }];
+
+  let arguments = (ins CIRRecordType:$record, I64Attr:$index,
+                       CIR_AnyType:$value);
+  let results = (outs CIRRecordType:$result);
+
+  let assemblyFormat = [{
+    $record `[` $index `]` `,` $value attr-dict
+    `:` qualified(type($record)) `,` qualified(type($value))
+  }];
+
+  let hasVerifier = 1;
+}
+
 
//===----------------------------------------------------------------------===//
 // GetElementOp
 
//===----------------------------------------------------------------------===//
@@ -4353,6 +4402,78 @@ def CIR_DerivedDataMemberOp : 
CIR_Op<"derived_data_member", [Pure]> {
   let hasCXXABILowering = true;  
 }
 
+//===----------------------------------------------------------------------===//
+// BaseMethodOp & DerivedMethodOp
+//===----------------------------------------------------------------------===//
+
+def CIR_BaseMethodOp : CIR_Op<"base_method", [Pure]> {
+  let summary = [{
+    Cast a derived class pointer-to-member-function to a base class
+    pointer-to-member-function
+  }];
+  let description = [{
+    The `cir.base_method` operation casts a pointer-to-member-function of type
+    `Ret (Derived::*)(Args)` to a pointer-to-member-function of type
+    `Ret (Base::*)(Args)`, where `Base` is a non-virtual base class of
+    `Derived`.
+
+    The `offset` parameter gives the offset in bytes of the `Base` base class
+    subobject within a `Derived` object.
+
+    Example:
+
+    ```mlir
+    %1 = cir.base_method %0 [16] : !cir.method<!cir.func<(!s32i)> in 
!rec_Derived> -> !cir.method<!cir.func<(!s32i)> in !rec_Base>
+    ```
+  }];
+
+  let arguments = (ins CIR_MethodType:$src, IndexAttr:$offset);
+  let results = (outs CIR_MethodType:$result);
+
+  let assemblyFormat = [{
+    $src `[` $offset `]` `:` qualified(type($src))
+         `->` qualified(type($result)) attr-dict
+  }];
+
+  let hasVerifier = 1;
+  let hasLLVMLowering = false;
+  let hasCXXABILowering = true;  
+}
+
+def CIR_DerivedMethodOp : CIR_Op<"derived_method", [Pure]> {
+  let summary = [{
+    Cast a base class pointer-to-member-function to a derived class
+    pointer-to-member-function
+  }];
+  let description = [{
+    The `cir.derived_method` operation casts a pointer-to-member-function of
+    type `Ret (Base::*)(Args)` to a pointer-to-member-function of type
+    `Ret (Derived::*)(Args)`, where `Base` is a non-virtual base class of
+    `Derived`.
+
+    The `offset` parameter gives the offset in bytes of the `Base` base class
+    subobject within a `Derived` object.
+
+    Example:
+
+    ```mlir
+    %1 = cir.derived_method %0 [16] : !cir.method<!cir.func<(!s32i)> in 
!rec_Base> -> !cir.method<!cir.func<(!s32i)> in !rec_Derived>
+    ```
+  }];
+
+  let arguments = (ins CIR_MethodType:$src, IndexAttr:$offset);
+  let results = (outs CIR_MethodType:$result);
+
+  let assemblyFormat = [{
+    $src `[` $offset `]` `:` qualified(type($src))
+         `->` qualified(type($result)) attr-dict
+  }];
+
+  let hasVerifier = 1;
+  let hasLLVMLowering = false;
+  let hasCXXABILowering = true;  
+}
+
 
//===----------------------------------------------------------------------===//
 // ComplexCreateOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index a7fc36bbb5bfb..940a0cb616b27 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -2281,9 +2281,10 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr 
*ce) {
     mlir::IntegerAttr offsetAttr = builder.getIndexAttr(offset.getQuantity());
 
     if (subExpr->getType()->isMemberFunctionPointerType()) {
-      cgf.cgm.errorNYI(subExpr->getSourceRange(),
-                       "VisitCastExpr: member function pointer");
-      return {};
+      if (kind == CK_BaseToDerivedMemberPointer)
+        return cir::DerivedMethodOp::create(builder, loc, resultTy, src,
+                                            offsetAttr);
+      return cir::BaseMethodOp::create(builder, loc, resultTy, src, 
offsetAttr);
     }
 
     if (kind == CK_BaseToDerivedMemberPointer)
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 7b9fc83403f71..c1461ebda53de 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2613,6 +2613,18 @@ LogicalResult cir::DerivedDataMemberOp::verify() {
   return verifyMemberPtrCast(getOperation(), getSrc(), getType());
 }
 
+//===----------------------------------------------------------------------===//
+// BaseMethodOp & DerivedMethodOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::BaseMethodOp::verify() {
+  return verifyMemberPtrCast(getOperation(), getSrc(), getType());
+}
+
+LogicalResult cir::DerivedMethodOp::verify() {
+  return verifyMemberPtrCast(getOperation(), getSrc(), getType());
+}
+
 
//===----------------------------------------------------------------------===//
 // AwaitOp
 
//===----------------------------------------------------------------------===//
@@ -2791,6 +2803,22 @@ LogicalResult cir::ExtractMemberOp::verify() {
   return mlir::success();
 }
 
+//===----------------------------------------------------------------------===//
+// InsertMemberOp Definitions
+//===----------------------------------------------------------------------===//
+
+LogicalResult cir::InsertMemberOp::verify() {
+  auto recordTy = mlir::cast<cir::RecordType>(getRecord().getType());
+  if (recordTy.getKind() == cir::RecordType::Union)
+    return emitError() << "cir.insert_member currently does not support 
unions";
+  if (recordTy.getMembers().size() <= getIndex())
+    return emitError() << "member index out of bounds";
+  if (recordTy.getMembers()[getIndex()] != getValue().getType())
+    return emitError() << "member type mismatch";
+  // The op trait already checks that the types of $result and $record match.
+  return mlir::success();
+}
+
 
//===----------------------------------------------------------------------===//
 // VecCreateOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index c8e06fed50cf9..fbd2403c8a2b9 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -57,8 +57,9 @@ 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::CastOp, 
cir::CmpOp,
-                  cir::ConstantOp, cir::DerivedDataMemberOp, cir::FuncOp,
+    if (llvm::isa<cir::AllocaOp, cir::BaseDataMemberOp, cir::BaseMethodOp,
+                  cir::CastOp, cir::CmpOp, cir::ConstantOp,
+                  cir::DerivedDataMemberOp, cir::DerivedMethodOp, cir::FuncOp,
                   cir::GetMethodOp, cir::GetRuntimeMemberOp, 
cir::GlobalOp>(op))
       return mlir::failure();
 
@@ -285,6 +286,15 @@ mlir::LogicalResult 
CIRBaseDataMemberOpABILowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRBaseMethodOpABILowering::matchAndRewrite(
+    cir::BaseMethodOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  mlir::Value loweredResult =
+      lowerModule->getCXXABI().lowerBaseMethod(op, adaptor.getSrc(), rewriter);
+  rewriter.replaceOp(op, loweredResult);
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRDerivedDataMemberOpABILowering::matchAndRewrite(
     cir::DerivedDataMemberOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
@@ -294,6 +304,15 @@ mlir::LogicalResult 
CIRDerivedDataMemberOpABILowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRDerivedMethodOpABILowering::matchAndRewrite(
+    cir::DerivedMethodOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  mlir::Value loweredResult = lowerModule->getCXXABI().lowerDerivedMethod(
+      op, adaptor.getSrc(), rewriter);
+  rewriter.replaceOp(op, loweredResult);
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRDynamicCastOpABILowering::matchAndRewrite(
     cir::DynamicCastOp 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 108e56a107738..5be66b4bff40f 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h
@@ -86,6 +86,18 @@ class CIRCXXABI {
   lowerDerivedDataMember(cir::DerivedDataMemberOp op, mlir::Value loweredSrc,
                          mlir::OpBuilder &builder) const = 0;
 
+  /// Lower the given cir.base_method op to a sequence of more "primitive" CIR
+  /// operations that act on the ABI types.
+  virtual mlir::Value lowerBaseMethod(cir::BaseMethodOp op,
+                                      mlir::Value loweredSrc,
+                                      mlir::OpBuilder &builder) const = 0;
+
+  /// Lower the given cir.derived_method op to a sequence of more "primitive"
+  /// CIR operations that act on the ABI types.
+  virtual mlir::Value lowerDerivedMethod(cir::DerivedMethodOp op,
+                                         mlir::Value loweredSrc,
+                                         mlir::OpBuilder &builder) const = 0;
+
   virtual mlir::Value lowerDataMemberCmp(cir::CmpOp op, mlir::Value loweredLhs,
                                          mlir::Value loweredRhs,
                                          mlir::OpBuilder &builder) const = 0;
diff --git 
a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
index 10996e6b5fe29..50c481192f16b 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
@@ -74,6 +74,13 @@ class LowerItaniumCXXABI : public CIRCXXABI {
                                      mlir::Value loweredSrc,
                                      mlir::OpBuilder &builder) const override;
 
+  mlir::Value lowerBaseMethod(cir::BaseMethodOp op, mlir::Value loweredSrc,
+                              mlir::OpBuilder &builder) const override;
+
+  mlir::Value lowerDerivedMethod(cir::DerivedMethodOp op,
+                                 mlir::Value loweredSrc,
+                                 mlir::OpBuilder &builder) const override;
+
   mlir::Value lowerDataMemberCmp(cir::CmpOp op, mlir::Value loweredLhs,
                                  mlir::Value loweredRhs,
                                  mlir::OpBuilder &builder) const override;
@@ -435,6 +442,44 @@ 
LowerItaniumCXXABI::lowerDerivedDataMember(cir::DerivedDataMemberOp op,
                              /*isDerivedToBase=*/false, builder);
 }
 
+static mlir::Value lowerMethodCast(mlir::Operation *op, mlir::Value loweredSrc,
+                                   std::int64_t offset, bool isDerivedToBase,
+                                   LowerModule &lowerMod,
+                                   mlir::OpBuilder &builder) {
+  if (offset == 0)
+    return loweredSrc;
+
+  cir::IntType ptrdiffCIRTy = getPtrDiffCIRTy(lowerMod);
+  auto adjField = cir::ExtractMemberOp::create(builder, op->getLoc(),
+                                               ptrdiffCIRTy, loweredSrc, 1);
+
+  auto offsetValue = cir::ConstantOp::create(
+      builder, op->getLoc(), cir::IntAttr::get(ptrdiffCIRTy, offset));
+  auto binOpKind = isDerivedToBase ? cir::BinOpKind::Sub : cir::BinOpKind::Add;
+  auto adjustedAdjField = cir::BinOp::create(
+      builder, op->getLoc(), ptrdiffCIRTy, binOpKind, adjField, offsetValue);
+  adjustedAdjField.setNoSignedWrap(true);
+
+  return cir::InsertMemberOp::create(builder, op->getLoc(), loweredSrc, 1,
+                                     adjustedAdjField);
+}
+
+mlir::Value
+LowerItaniumCXXABI::lowerBaseMethod(cir::BaseMethodOp op,
+                                    mlir::Value loweredSrc,
+                                    mlir::OpBuilder &builder) const {
+  return lowerMethodCast(op, loweredSrc, op.getOffset().getSExtValue(),
+                         /*isDerivedToBase=*/true, lm, builder);
+}
+
+mlir::Value
+LowerItaniumCXXABI::lowerDerivedMethod(cir::DerivedMethodOp op,
+                                       mlir::Value loweredSrc,
+                                       mlir::OpBuilder &builder) const {
+  return lowerMethodCast(op, loweredSrc, op.getOffset().getSExtValue(),
+                         /*isDerivedToBase=*/false, lm, builder);
+}
+
 mlir::Value
 LowerItaniumCXXABI::lowerDataMemberCmp(cir::CmpOp op, mlir::Value loweredLhs,
                                        mlir::Value loweredRhs,
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index a774b0dcc6ba8..7ec6fce934530 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3335,6 +3335,24 @@ mlir::LogicalResult 
CIRToLLVMExtractMemberOpLowering::matchAndRewrite(
   llvm_unreachable("Unexpected record kind");
 }
 
+mlir::LogicalResult CIRToLLVMInsertMemberOpLowering::matchAndRewrite(
+    cir::InsertMemberOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  std::int64_t indecies[1] = {static_cast<std::int64_t>(op.getIndex())};
+  mlir::Type recordTy = op.getRecord().getType();
+
+  if (auto cirRecordTy = mlir::dyn_cast<cir::RecordType>(recordTy)) {
+    if (cirRecordTy.getKind() == cir::RecordType::Union) {
+      op.emitError("cir.update_member cannot update member of a union");
+      return mlir::failure();
+    }
+  }
+
+  rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
+      op, adaptor.getRecord(), adaptor.getValue(), indecies);
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRToLLVMUnreachableOpLowering::matchAndRewrite(
     cir::UnreachableOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp 
b/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp
index 4f18a6a6a9540..1abb5241f8af9 100644
--- a/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp
+++ b/clang/test/CIR/CodeGen/pointer-to-member-func-cast.cpp
@@ -69,3 +69,143 @@ auto memfunc_reinterpret(void (Foo::*func)(int)) -> void 
(Bar::*)() {
 // OGCG:   store { i64, i64 } %[[FUNC]], ptr %[[RET_ADDR:.*]]
 // OGCG:   %[[RET:.*]] = load { i64, i64 }, ptr %[[RET_ADDR]]
 // OGCG:   ret { i64, i64 } %[[RET]]
+
+struct Base1 {
+  int x;
+  virtual void m1(int);
+};
+
+struct Base2 {
+  int y;
+  virtual void m2(int);
+};
+
+struct Derived : Base1, Base2 {
+  virtual void m3(int);
+};
+
+using Base1MemFunc = void (Base1::*)(int);
+using Base2MemFunc = void (Base2::*)(int);
+using DerivedMemFunc = void (Derived::*)(int);
+
+DerivedMemFunc base_to_derived_zero_offset(Base1MemFunc ptr) {
+  return static_cast<DerivedMemFunc>(ptr);
+}
+
+// CIR-BEFORE: cir.func {{.*}} @_Z27base_to_derived_zero_offsetM5Base1FviE
+// CIR-BEFORE:   %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : 
!cir.ptr<!cir.method<!cir.func<(!s32i)> in !rec_Base1>>, 
!cir.method<!cir.func<(!s32i)> in !rec_Base1>
+// CIR-BEFORE:   %{{.*}} = cir.derived_method %[[PTR]][0] : 
!cir.method<!cir.func<(!s32i)> in !rec_Base1> -> !cir.method<!cir.func<(!s32i)> 
in !rec_Derived>
+
+// CIR-AFTER: cir.func {{.*}} @_Z27base_to_derived_zero_offsetM5Base1FviE
+// CIR-AFTER:   %[[PTR:.*]] = cir.alloca !rec_anon_struct, 
!cir.ptr<!rec_anon_struct>, ["ptr", init]
+// CIR-AFTER:   %[[RET:.*]] = cir.alloca !rec_anon_struct, 
!cir.ptr<!rec_anon_struct>, ["__retval"]
+// CIR-AFTER:   cir.store %{{.*}}, %[[PTR]] : !rec_anon_struct, 
!cir.ptr<!rec_anon_struct>
+// CIR-AFTER:   %[[TMP:.*]] = cir.load{{.*}} %[[PTR]] : 
!cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER:   cir.store %[[TMP]], %[[RET]] : !rec_anon_struct, 
!cir.ptr<!rec_anon_struct>
+// CIR-AFTER:   %[[RET_VAL:.*]] = cir.load %[[RET]] : 
!cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER:   cir.return %[[RET_VAL]] : !rec_anon_struct
+
+// LLVM: define {{.*}} { i64, i64 } @_Z27base_to_derived_zero_offsetM5Base1FviE
+// LLVM:   %[[ARG_ADDR:.*]] = alloca { i64, i64 }
+// LLVM:   %[[RET_ADDR:.*]] = alloca { i64, i64 }
+// LLVM:   store { i64, i64 } %{{.*}}, ptr %[[ARG_ADDR]]
+// LLVM:   %[[TMP:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]]
+// LLVM:   store { i64, i64 } %[[TMP]], ptr %[[RET_ADDR]]
+// LLVM:   %[[RET:.*]] = load { i64, i64 }, ptr %[[RET_ADDR]]
+// LLVM:   ret { i64, i64 } %[[RET]]
+
+// OGCG: define {{.*}} { i64, i64 } @_Z27base_to_derived_zero_offsetM5Base1FviE
+// OGCG:   %[[ARG_ADDR:.*]] = alloca { i64, i64 }
+// OGCG:   store { i64, i64 } %{{.*}}, ptr %[[ARG_ADDR]]
+// OGCG:   %[[RET:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]]
+// OGCG:   ret { i64, i64 } %[[RET]]
+
+DerivedMemFunc base_to_derived(Base2MemFunc ptr) {
+  return static_cast<DerivedMemFunc>(ptr);
+}
+
+// CIR-BEFORE: cir.func {{.*}} @_Z15base_to_derivedM5Base2FviE
+// CIR-BEFORE:   %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : 
!cir.ptr<!cir.method<!cir.func<(!s32i)> in !rec_Base2>>, 
!cir.method<!cir.func<(!s32i)> in !rec_Base2>
+// CIR-BEFORE:   %{{.*}} = cir.derived_method %[[PTR]][16] : 
!cir.method<!cir.func<(!s32i)> in !rec_Base2> -> !cir.method<!cir.func<(!s32i)> 
in !rec_Derived>
+
+// CIR-AFTER: cir.func {{.*}} @_Z15base_to_derivedM5Base2FviE
+// CIR-AFTER:   %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : 
!cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER:   %[[OFFSET:.*]] = cir.extract_member %[[PTR]][1] : 
!rec_anon_struct -> !s64i
+// CIR-AFTER:   %[[OFFSET_ADJ:.*]] = cir.const #cir.int<16> : !s64i
+// CIR-AFTER:   %[[BINOP_KIND:.*]] = cir.binop(add, %[[OFFSET]], 
%[[OFFSET_ADJ]]) nsw : !s64i
+// CIR-AFTER:   %{{.*}} = cir.insert_member %[[PTR]][1], %[[BINOP_KIND]] : 
!rec_anon_struct, !s64i
+
+// LLVM: define {{.*}} { i64, i64 } @_Z15base_to_derivedM5Base2FviE
+// LLVM:   %[[ARG:.*]] = load { i64, i64 }, ptr %{{.*}}
+// LLVM:   %[[ADJ:.*]] = extractvalue { i64, i64 } %[[ARG]], 1
+// LLVM:   %[[ADJ_ADJ:.*]] = add nsw i64 %[[ADJ]], 16
+// LLVM:   %{{.*}} = insertvalue { i64, i64 } %[[ARG]], i64 %[[ADJ_ADJ]], 1
+
+// OGCG: define {{.*}} { i64, i64 } @_Z15base_to_derivedM5Base2FviE
+// OGCG:   %[[ARG:.*]] = load { i64, i64 }, ptr %{{.*}}
+// OGCG:   store { i64, i64 } %[[ARG]], ptr %[[ARG_ADDR:.*]]
+// OGCG:   %[[ARG1:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]]
+// OGCG:   %[[ADJ:.*]] = extractvalue { i64, i64 } %[[ARG1]], 1
+// OGCG:   %[[ADJ_ADJ:.*]] = add nsw i64 %[[ADJ]], 16
+// OGCG:   %{{.*}} = insertvalue { i64, i64 } %[[ARG1]], i64 %[[ADJ_ADJ]], 1
+
+Base1MemFunc derived_to_base_zero_offset(DerivedMemFunc ptr) {
+  return static_cast<Base1MemFunc>(ptr);
+}
+
+// CIR-BEFORE: cir.func {{.*}} @_Z27derived_to_base_zero_offsetM7DerivedFviE
+// CIR-BEFORE:   %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : 
!cir.ptr<!cir.method<!cir.func<(!s32i)> in !rec_Derived>>, 
!cir.method<!cir.func<(!s32i)> in !rec_Derived>
+// CIR-BEFORE:   %{{.*}} = cir.base_method %[[PTR]][0] : 
!cir.method<!cir.func<(!s32i)> in !rec_Derived> -> 
!cir.method<!cir.func<(!s32i)> in !rec_Base1>
+
+// CIR-AFTER: cir.func {{.*}} @_Z27derived_to_base_zero_offsetM7DerivedFviE
+// CIR-AFTER:   %[[PTR:.*]] = cir.alloca !rec_anon_struct, 
!cir.ptr<!rec_anon_struct>, ["ptr", init]
+// CIR-AFTER:   %[[RET:.*]] = cir.alloca !rec_anon_struct, 
!cir.ptr<!rec_anon_struct>, ["__retval"]
+// CIR-AFTER:   cir.store %{{.*}}, %[[PTR]] : !rec_anon_struct, 
!cir.ptr<!rec_anon_struct>
+// CIR-AFTER:   %[[TMP:.*]] = cir.load{{.*}} %[[PTR]] : 
!cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER:   cir.store %[[TMP]], %[[RET]] : !rec_anon_struct, 
!cir.ptr<!rec_anon_struct>
+// CIR-AFTER:   %[[RET_VAL:.*]] = cir.load %[[RET]] : 
!cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER:   cir.return %[[RET_VAL]] : !rec_anon_struct
+
+// LLVM: define {{.*}} { i64, i64 } 
@_Z27derived_to_base_zero_offsetM7DerivedFviE
+// LLVM:   %[[ARG_ADDR:.*]] = alloca { i64, i64 }
+// LLVM:   %[[RET_ADDR:.*]] = alloca { i64, i64 }
+// LLVM:   store { i64, i64 } %{{.*}}, ptr %[[ARG_ADDR]]
+// LLVM:   %[[TMP:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]]
+// LLVM:   store { i64, i64 } %[[TMP]], ptr %[[RET_ADDR]]
+// LLVM:   %[[RET:.*]] = load { i64, i64 }, ptr %[[RET_ADDR]]
+// LLVM:   ret { i64, i64 } %[[RET]]
+
+// OGCG: define {{.*}} { i64, i64 } 
@_Z27derived_to_base_zero_offsetM7DerivedFviE
+// OGCG:   %[[ARG_ADDR:.*]] = alloca { i64, i64 }
+// OGCG:   store { i64, i64 } %{{.*}}, ptr %[[ARG_ADDR]]
+// OGCG:   %[[RET:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]]
+// OGCG:   ret { i64, i64 } %[[RET]]
+
+Base2MemFunc derived_to_base(DerivedMemFunc ptr) {
+  return static_cast<Base2MemFunc>(ptr);
+}
+
+// CIR-BEFORE: cir.func {{.*}} @_Z15derived_to_baseM7DerivedFviE
+// CIR-BEFORE:   %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : 
!cir.ptr<!cir.method<!cir.func<(!s32i)> in !rec_Derived>>, 
!cir.method<!cir.func<(!s32i)> in !rec_Derived>
+// CIR-BEFORE:   %{{.*}} = cir.base_method %[[PTR]][16] : 
!cir.method<!cir.func<(!s32i)> in !rec_Derived> -> 
!cir.method<!cir.func<(!s32i)> in !rec_Base2>
+
+// CIR-AFTER: cir.func {{.*}} @_Z15derived_to_baseM7DerivedFviE
+// CIR-AFTER:   %[[PTR:.*]] = cir.load{{.*}} %{{.*}} : 
!cir.ptr<!rec_anon_struct>, !rec_anon_struct
+// CIR-AFTER:   %[[OFFSET:.*]] = cir.extract_member %[[PTR]][1] : 
!rec_anon_struct -> !s64i
+// CIR-AFTER:   %[[OFFSET_ADJ:.*]] = cir.const #cir.int<16> : !s64i
+// CIR-AFTER:   %[[BINOP_KIND:.*]] = cir.binop(sub, %[[OFFSET]], 
%[[OFFSET_ADJ]]) nsw : !s64i
+// CIR-AFTER:   %{{.*}} = cir.insert_member %[[PTR]][1], %[[BINOP_KIND]] : 
!rec_anon_struct, !s64i
+
+// LLVM: define {{.*}} { i64, i64 } @_Z15derived_to_baseM7DerivedFviE
+// LLVM:   %[[ARG:.*]] = load { i64, i64 }, ptr %{{.*}}
+// LLVM:   %[[ADJ:.*]] = extractvalue { i64, i64 } %[[ARG]], 1
+// LLVM:   %[[ADJ_ADJ:.*]] = sub nsw i64 %[[ADJ]], 16
+// LLVM:   %{{.*}} = insertvalue { i64, i64 } %[[ARG]], i64 %[[ADJ_ADJ]], 1
+
+// OGCG: define {{.*}} { i64, i64 } @_Z15derived_to_baseM7DerivedFviE
+// OGCG:   %[[ARG:.*]] = load { i64, i64 }, ptr %{{.*}}
+// OGCG:   store { i64, i64 } %[[ARG]], ptr %[[ARG_ADDR:.*]]
+// OGCG:   %[[ARG1:.*]] = load { i64, i64 }, ptr %[[ARG_ADDR]]
+// OGCG:   %[[ADJ:.*]] = extractvalue { i64, i64 } %[[ARG1]], 1
+// OGCG:   %[[ADJ_ADJ:.*]] = sub nsw i64 %[[ADJ]], 16
+// OGCG:   %{{.*}} = insertvalue { i64, i64 } %[[ARG1]], i64 %[[ADJ_ADJ]], 1
diff --git a/clang/test/CIR/IR/invalid-struct.cir 
b/clang/test/CIR/IR/invalid-struct.cir
index 99a3969df9982..63260cf3584e0 100644
--- a/clang/test/CIR/IR/invalid-struct.cir
+++ b/clang/test/CIR/IR/invalid-struct.cir
@@ -41,3 +41,50 @@ module  {
     cir.return
   }
 }
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!u32i = !cir.int<u, 32>
+!rec_S = !cir.record<struct "S" {!u8i, !u32i}>
+
+module  {
+  cir.func @struct_insert_member_invalid_element_type() {
+    %0 = cir.const #cir.const_record<{#cir.int<1> : !u8i, #cir.int<3> : 
!u32i}> : !rec_S
+    %1 = cir.const #cir.int<3> : !u8i
+       // expected-error @below {{member type mismatch}}
+    %2 = cir.insert_member %0[1], %1 : !rec_S, !u8i
+    cir.return
+  }
+}
+
+// -----
+
+!u8i = !cir.int<u, 8>
+!u32i = !cir.int<u, 32>
+!rec_S = !cir.record<struct "S" {!u8i, !u32i}>
+
+module  {
+  cir.func @struct_extract_member_invalid_index_value() {
+    %0 = cir.const #cir.const_record<{#cir.int<1> : !u8i, #cir.int<3> : 
!u32i}> : !rec_S
+    %1 = cir.const #cir.int<3> : !u8i
+       // expected-error @below {{member index out of bounds}}
+    %2 = cir.insert_member %0[2], %1 : !rec_S, !u8i
+    cir.return
+  }
+}
+
+// -----
+
+!u32i = !cir.int<u, 32>
+!rec_U = !cir.record<union "U" {!u32i}>
+
+module  {
+  cir.func @extract_member_invalid_for_union() {
+    %0 = cir.const #cir.const_record<{#cir.int<1> : !u32i}> : !rec_U
+    %1 = cir.const #cir.int<3> : !u32i
+  // expected-error @below {{cir.insert_member currently does not support 
unions}}
+    %2 = cir.insert_member %0[1], %1 : !rec_U, !u32i
+    cir.return
+  }
+}

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

Reply via email to