https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/203402
>From b43575ab8f1e26bb26808e38463b540bca79446e Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Mon, 8 Jun 2026 16:20:58 -0700 Subject: [PATCH 1/2] [CIR] Implement handling for CXXConstructLValue expressions This implements the handling to emit an l-value for CXXConstructExpr and CXXTemporaryObjectExpr expressions. This is a simple copy from the equivalent code in classic codegen and uses existing CIR code for most of the actual work. --- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 8 ++ clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 4 +- clang/lib/CIR/CodeGen/CIRGenFunction.h | 1 + .../test/CIR/CodeGen/cxx-construct-lvalue.cpp | 73 +++++++++++++++++++ 4 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 clang/test/CIR/CodeGen/cxx-construct-lvalue.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index e110f6e5d21a2..beaedd853f57b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -2145,6 +2145,14 @@ CIRGenFunction::emitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *e) { return makeAddrLValue(slot.getAddress(), e->getType(), AlignmentSource::Decl); } +LValue CIRGenFunction::emitCXXConstructLValue(const CXXConstructExpr *e) { + assert(e->getType()->getAsCXXRecordDecl()->hasTrivialDestructor() && + "binding l-value to type which needs a temporary"); + AggValueSlot slot = createAggTemp(e->getType(), getLoc(e->getSourceRange())); + emitCXXConstructExpr(e, slot); + return makeAddrLValue(slot.getAddress(), e->getType(), AlignmentSource::Decl); +} + LValue CIRGenFunction::emitBinaryOperatorLValue(const BinaryOperator *e) { // Comma expressions just emit their LHS then their RHS as an l-value. if (e->getOpcode() == BO_Comma) { diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 21b2640b36071..4b020c96964a7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -1220,9 +1220,7 @@ LValue CIRGenFunction::emitLValue(const Expr *e) { return emitInitListLValue(cast<InitListExpr>(e)); case Expr::CXXTemporaryObjectExprClass: case Expr::CXXConstructExprClass: - getCIRGenModule().errorNYI(e->getSourceRange(), - "emitLValue: CXXConstructExpr"); - return LValue(); + return emitCXXConstructLValue(cast<CXXConstructExpr>(e)); case Expr::CXXBindTemporaryExprClass: return emitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(e)); case Expr::CXXUuidofExprClass: diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 35112d1dd7b68..317151c8d61c6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1755,6 +1755,7 @@ class CIRGenFunction : public CIRGenTypeCache { LValue emitCallExprLValue(const clang::CallExpr *e); LValue emitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *e); + LValue emitCXXConstructLValue(const CXXConstructExpr *e); CIRGenCallee emitCallee(const clang::Expr *e); template <typename T> diff --git a/clang/test/CIR/CodeGen/cxx-construct-lvalue.cpp b/clang/test/CIR/CodeGen/cxx-construct-lvalue.cpp new file mode 100644 index 0000000000000..0ca10c15e16b9 --- /dev/null +++ b/clang/test/CIR/CodeGen/cxx-construct-lvalue.cpp @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -std=c++03 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -std=c++03 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -std=c++03 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM + +// A multi-argument constructor call written with explicit type syntax produces +// a CXXTemporaryObjectExpr. Using it as the base of a member access reaches +// emitLValue with that expression class. +struct Pt { + Pt(int a, int b); + int v; +}; + +int tempObj(int i) { return Pt(i, i).v; } + +// CIR-LABEL: cir.func {{.*}}@_Z7tempObji(%arg0: !s32i +// CIR: %[[I:.*]] = cir.alloca "i" +// CIR: %[[RET:.*]] = cir.alloca "__retval" +// CIR: %[[TMP:.*]] = cir.alloca "tmp" +// CIR: cir.store %arg0, %[[I]] +// CIR: %[[A:.*]] = cir.load align(4) %[[I]] +// CIR: %[[B:.*]] = cir.load align(4) %[[I]] +// CIR: cir.call @_ZN2PtC1Eii(%[[TMP]], %[[A]], %[[B]]) +// CIR: %[[V:.*]] = cir.get_member %[[TMP]][0] {name = "v"} : !cir.ptr<!rec_Pt> -> !cir.ptr<!s32i> +// CIR: %[[VAL:.*]] = cir.load align(4) %[[V]] +// CIR: cir.store %[[VAL]], %[[RET]] +// CIR: %[[RES:.*]] = cir.load %[[RET]] +// CIR: cir.return %[[RES]] + +// LLVM-LABEL: define {{.*}}i32 @_Z7tempObji +// LLVM: %[[I_ADDR:.*]] = alloca i32 +// LLVM: %[[TMP:.*]] = alloca %struct.Pt +// LLVM: store i32 %{{.*}}, ptr %[[I_ADDR]] +// LLVM: %[[A:.*]] = load i32, ptr %[[I_ADDR]] +// LLVM: %[[B:.*]] = load i32, ptr %[[I_ADDR]] +// LLVM: call void @_ZN2PtC1Eii(ptr {{.*}} %[[TMP]], i32 {{.*}} %[[A]], i32 {{.*}} %[[B]]) +// LLVM: %[[V:.*]] = getelementptr inbounds nuw %struct.Pt, ptr %[[TMP]], i32 0, i32 0 +// LLVM: %[[VAL:.*]] = load i32, ptr %[[V]] + +// A single-argument constructor call performs a constructor conversion, so the +// base of the member access is a CXXFunctionalCastExpr whose subexpression is a +// CXXConstructExpr. emitCastLValue forwards to the subexpression, reaching +// emitLValue with the CXXConstructExpr class. +struct Conv { + Conv(int a); + int y; +}; + +int construct(int i) { return Conv(i).y; } + +// CIR-LABEL: cir.func {{.*}}@_Z9constructi(%arg0: !s32i +// CIR: %[[I:.*]] = cir.alloca "i" +// CIR: %[[RET:.*]] = cir.alloca "__retval" +// CIR: %[[TMP:.*]] = cir.alloca "tmp" +// CIR: cir.store %arg0, %[[I]] +// CIR: %[[A:.*]] = cir.load align(4) %[[I]] +// CIR: cir.call @_ZN4ConvC1Ei(%[[TMP]], %[[A]]) +// CIR: %[[Y:.*]] = cir.get_member %[[TMP]][0] {name = "y"} : !cir.ptr<!rec_Conv> -> !cir.ptr<!s32i> +// CIR: %[[VAL:.*]] = cir.load align(4) %[[Y]] +// CIR: cir.store %[[VAL]], %[[RET]] +// CIR: %[[RES:.*]] = cir.load %[[RET]] +// CIR: cir.return %[[RES]] + +// LLVM-LABEL: define {{.*}}i32 @_Z9constructi +// LLVM: %[[I_ADDR:.*]] = alloca i32 +// LLVM: %[[TMP:.*]] = alloca %struct.Conv +// LLVM: store i32 %{{.*}}, ptr %[[I_ADDR]] +// LLVM: %[[A:.*]] = load i32, ptr %[[I_ADDR]] +// LLVM: call void @_ZN4ConvC1Ei(ptr {{.*}} %[[TMP]], i32 {{.*}} %[[A]]) +// LLVM: %[[Y:.*]] = getelementptr inbounds nuw %struct.Conv, ptr %[[TMP]], i32 0, i32 0 +// LLVM: %[[VAL:.*]] = load i32, ptr %[[Y]] >From 90ef516f5fe1c2325e60c6094c40312678bda271 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Fri, 12 Jun 2026 09:32:05 -0700 Subject: [PATCH 2/2] Address review feedback --- clang/test/CIR/CodeGen/cxx-construct-lvalue.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/clang/test/CIR/CodeGen/cxx-construct-lvalue.cpp b/clang/test/CIR/CodeGen/cxx-construct-lvalue.cpp index 0ca10c15e16b9..51d8be2b417aa 100644 --- a/clang/test/CIR/CodeGen/cxx-construct-lvalue.cpp +++ b/clang/test/CIR/CodeGen/cxx-construct-lvalue.cpp @@ -5,9 +5,6 @@ // RUN: %clang_cc1 -std=c++03 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll // RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM -// A multi-argument constructor call written with explicit type syntax produces -// a CXXTemporaryObjectExpr. Using it as the base of a member access reaches -// emitLValue with that expression class. struct Pt { Pt(int a, int b); int v; @@ -39,10 +36,6 @@ int tempObj(int i) { return Pt(i, i).v; } // LLVM: %[[V:.*]] = getelementptr inbounds nuw %struct.Pt, ptr %[[TMP]], i32 0, i32 0 // LLVM: %[[VAL:.*]] = load i32, ptr %[[V]] -// A single-argument constructor call performs a constructor conversion, so the -// base of the member access is a CXXFunctionalCastExpr whose subexpression is a -// CXXConstructExpr. emitCastLValue forwards to the subexpression, reaching -// emitLValue with the CXXConstructExpr class. struct Conv { Conv(int a); int y; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
