https://github.com/andykaylor updated 
https://github.com/llvm/llvm-project/pull/178323

>From 6c8bc7cfce8defed49279405daba825f295d454f Mon Sep 17 00:00:00 2001
From: Andy Kaylor <[email protected]>
Date: Thu, 4 Dec 2025 17:07:25 -0800
Subject: [PATCH 1/2] [CIR] Add handling for non-ODR use DeclRefLValues

This upstreams the code to handle decl ref l-values for non-odr uses.
---
 clang/lib/CIR/CodeGen/CIRGenDecl.cpp          |  61 ++++++++++
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          |  22 +++-
 clang/lib/CIR/CodeGen/CIRGenModule.h          |   4 +
 clang/lib/CIR/CodeGen/CIRGenTypes.cpp         |  15 +--
 .../CIR/Dialect/Transforms/CXXABILowering.cpp |  30 +++++
 clang/test/CIR/CodeGen/no-odr-use.cpp         | 113 ++++++++++++++++++
 6 files changed, 234 insertions(+), 11 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/no-odr-use.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
index 393633f686917..42a7d70677b61 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp
@@ -501,6 +501,67 @@ CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &d,
   return gv;
 }
 
+Address CIRGenModule::createUnnamedGlobalFrom(const VarDecl &d,
+                                              mlir::Attribute constAttr,
+                                              CharUnits align) {
+  auto functionName = [&](const DeclContext *dc) -> std::string {
+    if (const auto *fd = dyn_cast<FunctionDecl>(dc)) {
+      if (const auto *cc = dyn_cast<CXXConstructorDecl>(fd))
+        return cc->getNameAsString();
+      if (const auto *cd = dyn_cast<CXXDestructorDecl>(fd))
+        return cd->getNameAsString();
+      return std::string(getMangledName(fd));
+    } else if (const auto *om = dyn_cast<ObjCMethodDecl>(dc)) {
+      return om->getNameAsString();
+    } else if (isa<BlockDecl>(dc)) {
+      return "<block>";
+    } else if (isa<CapturedDecl>(dc)) {
+      return "<captured>";
+    } else {
+      llvm_unreachable("expected a function or method");
+    }
+  };
+
+  // Form a simple per-variable cache of these values in case we find we
+  // want to reuse them.
+  cir::GlobalOp &cacheEntry = initializerConstants[&d];
+  if (!cacheEntry || cacheEntry.getInitialValue() != constAttr) {
+    auto ty = mlir::cast<mlir::TypedAttr>(constAttr).getType();
+    bool isConstant = true;
+
+    std::string name;
+    if (d.hasGlobalStorage())
+      name = getMangledName(&d).str() + ".const";
+    else if (const DeclContext *dc = d.getParentFunctionOrMethod())
+      name = ("__const." + functionName(dc) + "." + d.getName()).str();
+    else
+      llvm_unreachable("local variable has no parent function or method");
+
+    assert(!cir::MissingFeatures::addressSpace());
+    cir::GlobalOp gv = builder.createVersionedGlobal(
+        getModule(), getLoc(d.getLocation()), name, ty, isConstant,
+        cir::GlobalLinkageKind::PrivateLinkage);
+    // TODO(cir): infer visibility from linkage in global op builder.
+    gv.setVisibility(getMLIRVisibilityFromCIRLinkage(
+        cir::GlobalLinkageKind::PrivateLinkage));
+    gv.setInitialValueAttr(constAttr);
+    gv.setAlignment(align.getAsAlign().value());
+    // TODO(cir): Set unnamed address attribute when available in CIR
+
+    cacheEntry = gv;
+  } else if (cacheEntry.getAlignment() < align.getQuantity()) {
+    cacheEntry.setAlignment(align.getAsAlign().value());
+  }
+
+  // Create a GetGlobalOp to get a pointer to the global
+  assert(!cir::MissingFeatures::addressSpace());
+  mlir::Type eltTy = mlir::cast<mlir::TypedAttr>(constAttr).getType();
+  auto ptrTy = builder.getPointerTo(cacheEntry.getSymType());
+  mlir::Value globalPtr = cir::GetGlobalOp::create(
+      builder, getLoc(d.getLocation()), ptrTy, cacheEntry.getSymName());
+  return Address(globalPtr, eltTy, align);
+}
+
 /// Add the initializer for 'd' to the global variable that has already been
 /// created for it. If the initializer has a different type than gv does, this
 /// may free gv and return a different one. Otherwise it just returns gv.
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 504f18e1a9f31..8bdf075aab695 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -883,8 +883,26 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr 
*e) {
     if (e->isNonOdrUse() == NOUR_Constant &&
         (vd->getType()->isReferenceType() ||
          !canEmitSpuriousReferenceToVariable(*this, e, vd))) {
-      cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: NonOdrUse");
-      return LValue();
+      vd->getAnyInitializer(vd);
+      mlir::Attribute val = ConstantEmitter(*this).emitAbstract(
+          e->getLocation(), *vd->evaluateValue(), vd->getType());
+      assert(val && "failed to emit constant expression");
+
+      Address addr = Address::invalid();
+      if (!vd->getType()->isReferenceType()) {
+        // Spill the constant value to a global.
+        addr = cgm.createUnnamedGlobalFrom(*vd, val,
+                                           getContext().getDeclAlign(vd));
+        mlir::Type varTy = getTypes().convertTypeForMem(vd->getType());
+        auto ptrTy = mlir::cast<cir::PointerType>(addr.getPointer().getType());
+        if (ptrTy.getPointee() != varTy) {
+          addr = addr.withElementType(builder, varTy);
+        }
+      } else {
+        cgm.errorNYI(e->getSourceRange(),
+                     "emitDeclRefLValue: non-odr reference type");
+      }
+      return makeAddrLValue(addr, ty, AlignmentSource::Decl);
     }
 
     // Check for captured variables.
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h 
b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 3c4f35bacc4f9..2f7020a54e607 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -147,6 +147,7 @@ class CIRGenModule : public CIRGenTypeCache {
   void handleCXXStaticMemberVarInstantiation(VarDecl *vd);
 
   llvm::DenseMap<const Decl *, cir::GlobalOp> staticLocalDeclMap;
+  llvm::DenseMap<const VarDecl *, cir::GlobalOp> initializerConstants;
 
   mlir::Operation *getGlobalValue(llvm::StringRef ref);
 
@@ -161,6 +162,9 @@ class CIRGenModule : public CIRGenTypeCache {
   cir::GlobalOp getOrCreateStaticVarDecl(const VarDecl &d,
                                          cir::GlobalLinkageKind linkage);
 
+  Address createUnnamedGlobalFrom(const VarDecl &d, mlir::Attribute constAttr,
+                                  CharUnits align);
+
   /// If the specified mangled name is not in the module, create and return an
   /// mlir::GlobalOp value
   cir::GlobalOp getOrCreateCIRGlobal(llvm::StringRef mangledName, mlir::Type 
ty,
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index 851119ee52096..bcbfadbac0347 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -505,15 +505,12 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
   case Type::ConstantArray: {
     const ConstantArrayType *arrTy = cast<ConstantArrayType>(ty);
     mlir::Type elemTy = convertTypeForMem(arrTy->getElementType());
-
-    // TODO(CIR): In LLVM, "lower arrays of undefined struct type to arrays of
-    // i8 just to have a concrete type"
-    if (!cir::isSized(elemTy)) {
-      cgm.errorNYI(SourceLocation(), "arrays of undefined struct type", type);
-      resultType = cgm.uInt32Ty;
-      break;
-    }
-
+    // In classic codegen, arrays of unsized types which it assumes are "arrays
+    // of undefined struct type" are lowered to arrays of i8 "just to have a
+    // concrete type", but in CIR, we can get here with abstract types like
+    // !cir.method and !cir.data_member, so let's just create an array of the
+    // type we have and handle it during lowering if we still don't have a 
sized
+    // type.
     resultType = cir::ArrayType::get(elemTy, arrTy->getSize().getZExtValue());
     break;
   }
diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index 9d977af808ee0..9ddb71c64fde9 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -270,6 +270,28 @@ mlir::LogicalResult 
CIRGlobalOpABILowering::matchAndRewrite(
         mlir::cast_if_present<cir::MethodAttr>(op.getInitialValueAttr());
     loweredInit = lowerModule->getCXXABI().lowerMethodConstant(
         init, layout, *getTypeConverter());
+  } else if (auto arrTy = mlir::dyn_cast<cir::ArrayType>(ty)) {
+    cir::ConstArrayAttr init =
+        mlir::cast_if_present<cir::ConstArrayAttr>(op.getInitialValueAttr());
+    assert(init && "array initial value must be a constant array");
+    auto arrayElts = mlir::cast<ArrayAttr>(init.getElts());
+    SmallVector<mlir::Attribute> loweredElements;
+    loweredElements.reserve(arrTy.getSize());
+    for (const mlir::Attribute &attr : arrayElts) {
+      if (auto methodAttr = mlir::dyn_cast<cir::MethodAttr>(attr)) {
+        mlir::Attribute loweredElt =
+            lowerModule->getCXXABI().lowerMethodConstant(methodAttr, layout,
+                                                         *getTypeConverter());
+        loweredElements.push_back(loweredElt);
+      } else {
+        llvm_unreachable("array of data member lowering is NYI");
+      }
+    }
+    auto loweredArrTy =
+        mlir::cast<cir::ArrayType>(getTypeConverter()->convertType(arrTy));
+    loweredInit = cir::ConstArrayAttr::get(
+        loweredArrTy,
+        mlir::ArrayAttr::get(rewriter.getContext(), loweredElements));
   } else {
     llvm_unreachable(
         "inputs to cir.global in ABI lowering must be data member or method");
@@ -363,6 +385,14 @@ static void prepareCXXABITypeConverter(mlir::TypeConverter 
&converter,
     return cir::PointerType::get(type.getContext(), loweredPointeeType,
                                  type.getAddrSpace());
   });
+  converter.addConversion([&](cir::ArrayType type) -> mlir::Type {
+    mlir::Type loweredElementType =
+        converter.convertType(type.getElementType());
+    if (!loweredElementType)
+      return {};
+    return cir::ArrayType::get(loweredElementType, type.getSize());
+  });
+
   converter.addConversion([&](cir::DataMemberType type) -> mlir::Type {
     mlir::Type abiType =
         lowerModule.getCXXABI().lowerDataMemberType(type, converter);
diff --git a/clang/test/CIR/CodeGen/no-odr-use.cpp 
b/clang/test/CIR/CodeGen/no-odr-use.cpp
new file mode 100644
index 0000000000000..0f1feb8f1e86c
--- /dev/null
+++ b/clang/test/CIR/CodeGen/no-odr-use.cpp
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 -std=c++11 -fclangir -emit-cir -o %t-cxx11.cir -triple 
x86_64-linux-gnu %s
+// RUN: FileCheck %s --input-file=%t-cxx11.cir --check-prefixes=CIR,CIR-CXX11
+// RUN: %clang_cc1 -std=c++2a -fclangir -emit-cir -o %t-cxx2a.cir -triple 
x86_64-linux-gnu %s
+// RUN: FileCheck %s --input-file=%t-cxx2a.cir --check-prefixes=CIR,CIR-CXX2A
+// RUN: %clang_cc1 -std=c++11 -fclangir -emit-llvm -o %t-cxx11-cir.ll -triple 
x86_64-linux-gnu %s
+// RUN: FileCheck %s --input-file=%t-cxx11-cir.ll 
--check-prefixes=LLVM,LLVM-CXX11
+// RUN: %clang_cc1 -std=c++2a -fclangir -emit-llvm -o %t-cxx2a-cir.ll -triple 
x86_64-linux-gnu %s
+// RUN: FileCheck %s --input-file=%t-cxx2a-cir.ll 
--check-prefixes=LLVM,LLVM-CXX2A
+// RUN: %clang_cc1 -std=c++11 -emit-llvm -o %t-cxx11.ll -triple 
x86_64-linux-gnu %s
+// RUN: FileCheck %s --input-file=%t-cxx11.ll --check-prefixes=OGCG,OGCG-CXX11
+// RUN: %clang_cc1 -std=c++2a -emit-llvm -o %t-cxx2a.ll -triple 
x86_64-linux-gnu %s
+// RUN: FileCheck %s --input-file=%t-cxx2a.ll --check-prefixes=OGCG,OGCG-CXX2A
+
+// CIR-DAG: cir.global "private" constant cir_private @__const._Z1fi.a = 
#cir.const_record<{#cir.int<1> : !s32i, #cir.const_array<[#cir.int<2> : !s32i, 
#cir.int<3> : !s32i]> : !cir.array<!s32i x 2>, #cir.const_array<[#cir.int<4> : 
!s32i, #cir.int<5> : !s32i, #cir.int<6> : !s32i]> : !cir.array<!s32i x 3>}> : 
!rec_A
+// LLVM-DAG: @__const._Z1fi.a = private constant {{.*}} { i32 1, [2 x i32] 
[i32 2, i32 3], [3 x i32] [i32 4, i32 5, i32 6] }
+// OGCG-DAG: @__const._Z1fi.a = private unnamed_addr constant {{.*}} { i32 1, 
[2 x i32] [i32 2, i32 3], [3 x i32] [i32 4, i32 5, i32 6] }
+
+// CIR-CXX11-DAG: cir.global "private" constant cir_private 
@_ZN7PR422765State1mE.const = 
#cir.const_array<[#cir.const_record<{#cir.global_view<@_ZN7PR422765State2f1Ev> 
: !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct, 
#cir.const_record<{#cir.global_view<@_ZN7PR422765State2f2Ev> : !s64i, 
#cir.int<0> : !s64i}> : !rec_anon_struct]> : !cir.array<!rec_anon_struct x 2>
+// LLVM-CXX11-DAG: @_ZN7PR422765State1mE.const = private constant [2 x { i64, 
i64 }] [{ {{.*}} @_ZN7PR422765State2f1Ev {{.*}}, i64 0 }, { {{.*}} 
@_ZN7PR422765State2f2Ev {{.*}}, i64 0 }]
+// OGCG-CXX11-DAG: @_ZN7PR422765State1mE.const = private unnamed_addr constant 
[2 x { i64, i64 }] [{ {{.*}} @_ZN7PR422765State2f1Ev {{.*}}, i64 0 }, { {{.*}} 
@_ZN7PR422765State2f2Ev {{.*}}, i64 0 }]
+
+// CIR-CXX2A-DAG: cir.global constant linkonce_odr comdat 
@_ZN7PR422765State1mE = 
#cir.const_array<[#cir.const_record<{#cir.global_view<@_ZN7PR422765State2f1Ev> 
: !s64i, #cir.int<0> : !s64i}> : !rec_anon_struct, 
#cir.const_record<{#cir.global_view<@_ZN7PR422765State2f2Ev> : !s64i, 
#cir.int<0> : !s64i}> : !rec_anon_struct]> : !cir.array<!rec_anon_struct x 2>
+// LLVM-CXX2A-DAG: @_ZN7PR422765State1mE = linkonce_odr constant [2 x { i64, 
i64 }] [{ {{.*}} @_ZN7PR422765State2f1Ev {{.*}}, i64 0 }, { {{.*}} 
@_ZN7PR422765State2f2Ev {{.*}}, i64 0 }], comdat
+// OGCG-CXX2A-DAG: @_ZN7PR422765State1mE = linkonce_odr constant [2 x { i64, 
i64 }] [{ {{.*}} @_ZN7PR422765State2f1Ev {{.*}}, i64 0 }, { {{.*}} 
@_ZN7PR422765State2f2Ev {{.*}}, i64 0 }], comdat
+
+// In OGCG, f1() is emitted before the lambda.
+// OGCG-LABEL: define{{.*}} i32 @_Z1fi(
+// OGCG:         call void {{.*}}memcpy{{.*}}({{.*}}, {{.*}} @__const._Z1fi.a
+// OGCG:         call{{.*}} i32 @"_ZZ1fiENK3$_0clEiM1Ai"(ptr {{.*}}, i32 
{{.*}}, i64 0)
+
+struct A { int x, y[2]; int arr[3]; };
+int f(int i) {
+  constexpr A a = {1, 2, 3, 4, 5, 6};
+
+  // CIR-LABEL: cir.func {{.*}}@_ZZ1fiENK3$_0clEiM1Ai(
+  // LLVM-LABEL: define {{.*}}@"_ZZ1fiENK3$_0clEiM1Ai"(
+  // OGCG-LABEL: define {{.*}}@"_ZZ1fiENK3$_0clEiM1Ai"(
+    return [] (int n, int A::*p) {
+    // CIR:  cir.ternary
+    // LLVM: br i1
+    // OGCG: br i1
+    return (n >= 0
+      // CIR:  %[[A:.*]] = cir.get_global @__const._Z1fi.a : !cir.ptr<!rec_A>
+      // CIR:  %[[ARR:.*]] = cir.get_member %[[A]][2] {name = "arr"} : 
!cir.ptr<!rec_A> -> !cir.ptr<!cir.array<!s32i x 3>>
+      // CIR:  cir.get_element %[[ARR]][%{{.*}} : !s32i] : 
!cir.ptr<!cir.array<!s32i x 3>> -> !cir.ptr<!s32i>
+      // LLVM: getelementptr [3 x i32], ptr getelementptr inbounds nuw (i8, 
ptr @__const._Z1fi.a, i64 12), i32 0, i64 %{{.*}}
+      // OGCG: getelementptr inbounds [3 x i32], ptr getelementptr inbounds 
nuw ({{.*}} @__const._Z1fi.a, i32 0, i32 2), i64 0, i64 %{{.*}}
+      ? a.arr[n]
+      // CIR:  cir.ternary
+      // LLVM: br i1
+      // OGCG: br i1
+      : (n == -1
+        // CIR: %[[A:.*]] = cir.get_global @__const._Z1fi.a : !cir.ptr<!rec_A>
+        // CIR: %[[N:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i
+        // CIR: %[[A_BYTE_PTR:.*]] = cir.cast bitcast %[[A]] : 
!cir.ptr<!rec_A> -> !cir.ptr<!s8i>
+        // CIR: cir.ptr_stride %[[A_BYTE_PTR]], %[[N]] : (!cir.ptr<!s8i>, 
!s64i) -> !cir.ptr<!s8i>
+
+        // LLVM: getelementptr i8, ptr @__const._Z1fi.a, i64 %{{.*}}
+        // LLVM: load i32
+
+        // OGCG: getelementptr inbounds i8, ptr @__const._Z1fi.a, i64 %{{.*}}
+        // OGCG: load i32
+        ? a.*p
+        // CIR: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
+        // CIR: %[[N:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i
+        // CIR: %[[SUB:.*]] = cir.binop(sub, %[[TWO]], %[[N]]) nsw : !s32i
+        // CIR: %[[A:.*]] = cir.get_global @__const._Z1fi.a : !cir.ptr<!rec_A>
+        // CIR: %[[Y:.*]] = cir.get_member %[[A]][1] {name = "y"} : 
!cir.ptr<!rec_A> -> !cir.ptr<!cir.array<!s32i x 2>>
+        // CIR: cir.get_element %[[Y]][%[[SUB]] : !s32i] : 
!cir.ptr<!cir.array<!s32i x 2>> -> !cir.ptr<!s32i>
+
+        // LLVM: getelementptr [2 x i32], ptr getelementptr inbounds nuw 
({{.*}} @__const._Z1fi.a, i64 4), i32 0, i64 %{{.*}}
+        // LLVM: load i32
+
+        // OGCG: getelementptr inbounds [2 x i32], ptr getelementptr inbounds 
nuw ({{.*}} @__const._Z1fi.a, i32 0, i32 1), i64 0, i64 %{{.*}}
+        // OGCG: load i32
+        : a.y[2 - n]));
+  }(i, &A::x);
+}
+
+// With CIR, f1() is emitted after the lambda.
+// CIR-LABEL: cir.func {{.*}} @_Z1fi(
+// CIR:         %[[A_INIT:.*]] = cir.const #cir.const_record<{#cir.int<1> : 
!s32i, #cir.const_array<[#cir.int<2> : !s32i, #cir.int<3> : !s32i]> : 
!cir.array<!s32i x 2>, #cir.const_array<[#cir.int<4> : !s32i, #cir.int<5> : 
!s32i, #cir.int<6> : !s32i]> : !cir.array<!s32i x 3>}> : !rec_A
+// CIR:         cir.store{{.*}} %[[A_INIT]], %{{.*}}
+// CIR:         %[[ZERO:.*]] = cir.const #cir.int<0> : !s64i
+// CIR:         cir.call @_ZZ1fiENK3$_0clEiM1Ai({{.*}}, {{.*}}, %[[ZERO]])
+
+// LLVM-LABEL: define{{.*}} i32 @_Z1fi(
+// LLVM:         store %struct.A { i32 1, [2 x i32] [i32 2, i32 3], [3 x i32] 
[i32 4, i32 5, i32 6] }, ptr %{{.*}}
+// LLVM:         call i32 @"_ZZ1fiENK3$_0clEiM1Ai"(ptr %{{.*}}, i32 %{{.*}}, 
i64 0)
+
+namespace PR42276 {
+  class State {
+    void syncDirtyObjects();
+    void f1(), f2();
+    using l = void (State::*)();
+    static constexpr l m[]{&State::f1, &State::f2};
+  };
+  // CIR-LABEL: cir.func {{.*}} @_ZN7PR422765State16syncDirtyObjectsEv(
+  // LLVM-LABEL: define{{.*}} void @_ZN7PR422765State16syncDirtyObjectsEv(
+  // OGCG-LABEL: define{{.*}} void @_ZN7PR422765State16syncDirtyObjectsEv(
+    void State::syncDirtyObjects() {
+    for (int i = 0; i < sizeof(m) / sizeof(m[0]); ++i)
+      // CIR-CXX11: %[[M:.*]] = cir.get_global @_ZN7PR422765State1mE.const : 
!cir.ptr<!cir.array<!rec_anon_struct x 2>>
+      // CIR-CXX2A: %[[M:.*]] = cir.get_global @_ZN7PR422765State1mE : 
!cir.ptr<!cir.array<!rec_anon_struct x 2>>
+      // CIR: %[[M_I:.*]] = cir.get_element %[[M]][%{{.*}} : !s32i] : 
!cir.ptr<!cir.array<!rec_anon_struct x 2>> -> !cir.ptr<!rec_anon_struct>
+
+      // LLVM-CXX11: getelementptr [2 x { i64, i64 }], ptr 
@_ZN7PR422765State1mE.const, i32 0, i64 %{{.*}}
+      // LLVM-CXX2A: getelementptr [2 x { i64, i64 }], ptr 
@_ZN7PR422765State1mE, i32 0, i64 %{{.*}}
+      // OGCG-CXX11: getelementptr inbounds [2 x { i64, i64 }], ptr 
@_ZN7PR422765State1mE.const, i64 0, i64 %{{.*}}
+      // OGCG-CXX2A: getelementptr inbounds [2 x { i64, i64 }], ptr 
@_ZN7PR422765State1mE, i64 0, i64 %{{.*}}
+      (this->*m[i])();
+  }
+}

>From 64ad72424ddfb23006d0729d0943dd640e6a1f19 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <[email protected]>
Date: Wed, 28 Jan 2026 15:47:54 -0800
Subject: [PATCH 2/2] Address review feedback

---
 clang/lib/CIR/CodeGen/CIRGenTypes.cpp               | 5 ++---
 clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp | 4 +---
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index bcbfadbac0347..e6ce39cf9571f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -508,9 +508,8 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
     // In classic codegen, arrays of unsized types which it assumes are "arrays
     // of undefined struct type" are lowered to arrays of i8 "just to have a
     // concrete type", but in CIR, we can get here with abstract types like
-    // !cir.method and !cir.data_member, so let's just create an array of the
-    // type we have and handle it during lowering if we still don't have a 
sized
-    // type.
+    // !cir.method and !cir.data_member, so we just create an array of the type
+    // and handle it during lowering if we still don't have a sized type.
     resultType = cir::ArrayType::get(elemTy, arrTy->getSize().getZExtValue());
     break;
   }
diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp 
b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
index 9ddb71c64fde9..f0e473a6574c7 100644
--- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp
@@ -271,9 +271,7 @@ mlir::LogicalResult CIRGlobalOpABILowering::matchAndRewrite(
     loweredInit = lowerModule->getCXXABI().lowerMethodConstant(
         init, layout, *getTypeConverter());
   } else if (auto arrTy = mlir::dyn_cast<cir::ArrayType>(ty)) {
-    cir::ConstArrayAttr init =
-        mlir::cast_if_present<cir::ConstArrayAttr>(op.getInitialValueAttr());
-    assert(init && "array initial value must be a constant array");
+    auto init = mlir::cast<cir::ConstArrayAttr>(op.getInitialValueAttr());
     auto arrayElts = mlir::cast<ArrayAttr>(init.getElts());
     SmallVector<mlir::Attribute> loweredElements;
     loweredElements.reserve(arrTy.getSize());

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

Reply via email to