[clang] [CIR] Honor C++17 operator-call argument evaluation order (PR #232779)
Konstantinos Parasyris via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 16 13:45:55 PDT 2026
https://github.com/koparasy updated https://github.com/llvm/llvm-project/pull/232779
>From 62ea5396509f4449d4fc849e63e1b3a67f717c70 Mon Sep 17 00:00:00 2001
From: Konstantinos Parasyris <konstantinos.parasyris at intel.com>
Date: Fri, 16 Oct 2026 07:25:42 -0700
Subject: [PATCH 1/2] [CIR] Honor C++17 operator-call argument evaluation order
C++17 (P0145) sequences the right operand of an assignment before the
left, even when the assignment resolves to an overloaded operator. CIR
did not apply this to non-member operators.
CIRGenFunction::emitCall now selects the evaluation order by following
faithfully OG.
The OG changes target code sharing, and for OG those should be NFC.
The new test now is mostly a copy off CodeGenCXX/cxx1z-eval-order.cpp to CIR.
The MS ABI RUN lines are dropped.
---
clang/include/clang/CIR/MissingFeatures.h | 1 -
clang/include/clang/CodeGenUtils/CallUtils.h | 28 ++
clang/lib/CIR/CodeGen/CIRGenCall.cpp | 16 +-
clang/lib/CIR/CodeGen/CIRGenClass.cpp | 6 +-
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 14 +-
clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 2 +-
clang/lib/CIR/CodeGen/CIRGenFunction.h | 6 +-
clang/lib/CodeGen/CGCall.cpp | 6 +-
clang/lib/CodeGen/CGExpr.cpp | 25 +-
clang/lib/CodeGen/CodeGenFunction.h | 10 +-
clang/lib/CodeGenUtils/CallUtils.cpp | 34 ++
clang/test/CIR/CodeGen/cxx1z-eval-order.cpp | 386 +++++++++++++++++++
12 files changed, 480 insertions(+), 54 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/cxx1z-eval-order.cpp
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 0ff6c6d44d1916..570660038982a0 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -85,7 +85,6 @@ struct MissingFeatures {
static bool opCallPaddingArgs() { return false; }
static bool opCallBitcastArg() { return false; }
static bool opCallReturn() { return false; }
- static bool opCallArgEvaluationOrder() { return false; }
static bool opCallCallConv() { return false; }
static bool opCallThunkTailHint() { return false; }
static bool opCallInAlloca() { return false; }
diff --git a/clang/include/clang/CodeGenUtils/CallUtils.h b/clang/include/clang/CodeGenUtils/CallUtils.h
index 450a62a448e491..82f135f3be1e64 100644
--- a/clang/include/clang/CodeGenUtils/CallUtils.h
+++ b/clang/include/clang/CodeGenUtils/CallUtils.h
@@ -18,8 +18,36 @@
#include "clang/AST/ASTContext.h"
#include "llvm/ADT/FloatingPointMode.h"
+namespace clang {
+class CallExpr;
+class TargetCXXABI;
+} // namespace clang
+
namespace clang::CodeGenUtils {
+/// The order in which the arguments of a call must be evaluated.
+enum class EvaluationOrder {
+ ///! No language constraints on evaluation order.
+ Default,
+ ///! Language semantics require left-to-right evaluation.
+ ForceLeftToRight,
+ ///! Language semantics require right-to-left evaluation.
+ ForceRightToLeft
+};
+
+/// Returns the argument evaluation order the language requires for the given
+/// call. C++17 requires that arguments to a call using assignment syntax be
+/// evaluated right-to-left, and that arguments to certain other operators be
+/// evaluated left-to-right.
+EvaluationOrder getCallArgEvaluationOrder(const CallExpr *E);
+
+/// Returns true if call arguments should be emitted left-to-right, given the
+/// order the language requires and the C++ ABI's default. The MS C++ ABI
+/// evaluates right-to-left because arguments are destroyed left-to-right in
+/// the callee; a language-required order overrides that.
+bool shouldEvaluateArgsLeftToRight(EvaluationOrder Order,
+ const TargetCXXABI &ABI);
+
/// Returns the canonical formal type of the given C++ method.
CanQual<FunctionProtoType> getFormalType(const CXXMethodDecl *MD);
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index c562e4308c1ab0..2d9113c2789933 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -1686,7 +1686,7 @@ RValue CIRGenFunction::emitAnyExprToTemp(const Expr *e) {
void CIRGenFunction::emitCallArgs(
CallArgList &args, PrototypeWrapper prototype,
llvm::iterator_range<clang::CallExpr::const_arg_iterator> argRange,
- AbstractCallee callee, unsigned paramsToSkip) {
+ AbstractCallee callee, unsigned paramsToSkip, EvaluationOrder order) {
llvm::SmallVector<QualType, 16> argTypes;
assert(!cir::MissingFeatures::opCallCallConv());
@@ -1710,11 +1710,11 @@ void CIRGenFunction::emitCallArgs(
// We must evaluate arguments from right to left in the MS C++ ABI, because
// arguments are destroyed left to right in the callee. As a special case,
- // there are certain language constructs taht require left-to-right
+ // there are certain language constructs that require left-to-right
// evaluation, and in those cases we consider the evaluation order requirement
// to trump the "destruction order is reverse construction order" guarantee.
- auto leftToRight = true;
- assert(!cir::MissingFeatures::msabi());
+ bool leftToRight = CodeGenUtils::shouldEvaluateArgsLeftToRight(
+ order, getTarget().getCXXABI());
auto maybeEmitImplicitObjectSize = [&](size_t i, const Expr *arg,
RValue emittedArg) {
@@ -1759,9 +1759,13 @@ void CIRGenFunction::emitCallArgs(
assert(!cir::MissingFeatures::sanitizers());
maybeEmitImplicitObjectSize(idx, *currentArg, rvArg);
}
+ }
- if (!leftToRight)
- std::reverse(args.begin() + callArgsStart, args.end());
+ if (!leftToRight) {
+ // Un-reverse the arguments we just evaluated so they match up with the
+ // callee's parameter order.
+ std::reverse(args.begin() + callArgsStart, args.end());
+ assert(!cir::MissingFeatures::writebacks());
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index 9e6ff99792500a..bcf301a0b5ae20 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -1380,12 +1380,14 @@ void CIRGenFunction::emitCXXConstructorCall(const clang::CXXConstructorDecl *d,
const FunctionProtoType *fpt = d->getType()->castAs<FunctionProtoType>();
- assert(!cir::MissingFeatures::opCallArgEvaluationOrder());
+ EvaluationOrder order = e->isListInitialization()
+ ? EvaluationOrder::ForceLeftToRight
+ : EvaluationOrder::Default;
if (auto inherited = d->getInheritedConstructor();
!inherited || cgm.getTypes().inheritingCtorHasParams(inherited, type))
emitCallArgs(args, fpt, e->arguments(), e->getConstructor(),
- /*ParamsToSkip=*/0);
+ /*ParamsToSkip=*/0, order);
assert(!cir::MissingFeatures::sanitizers());
emitCXXConstructorCall(d, type, forVirtualBase, delegating, thisAddr, args,
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 321ebaaa34517c..a6b815aaea8e3f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2438,15 +2438,15 @@ RValue CIRGenFunction::emitCall(clang::QualType calleeTy,
assert(!cir::MissingFeatures::sanitizers());
CallArgList args;
- assert(!cir::MissingFeatures::opCallArgEvaluationOrder());
- // C++23 static-member operators (`static operator()` /
- // `static operator[]`) produce a CXXOperatorCallExpr whose first argument
- // is the object expression even though the operator is static. Emit the
- // object for its side effects and drop it before walking the parameter
- // arguments.
+ EvaluationOrder order = CodeGenUtils::getCallArgEvaluationOrder(e);
auto arguments = e->arguments();
if (const auto *oce = dyn_cast<CXXOperatorCallExpr>(e)) {
+ // C++23 static-member operators (`static operator()` /
+ // `static operator[]`) produce a CXXOperatorCallExpr whose first argument
+ // is the object expression even though the operator is static. Emit the
+ // object for its side effects and drop it before walking the parameter
+ // arguments.
if (const auto *md =
dyn_cast_if_present<CXXMethodDecl>(oce->getCalleeDecl());
md && md->isStatic()) {
@@ -2456,7 +2456,7 @@ RValue CIRGenFunction::emitCall(clang::QualType calleeTy,
}
emitCallArgs(args, dyn_cast<FunctionProtoType>(fnType), arguments,
- e->getDirectCallee());
+ e->getDirectCallee(), /*paramsToSkip=*/0, order);
const CIRGenFunctionInfo &funcInfo =
cgm.getTypes().arrangeFreeFunctionCall(args, fnType);
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
index decddca749d835..f30a8be15bc2bb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
@@ -186,7 +186,7 @@ RValue CIRGenFunction::emitCXXMemberOrOperatorMemberCallExpr(
rtlArgs = &rtlArgStorage;
emitCallArgs(*rtlArgs, md->getType()->castAs<FunctionProtoType>(),
drop_begin(ce->arguments(), 1), ce->getDirectCallee(),
- /*ParamsToSkip*/ 0);
+ /*ParamsToSkip*/ 0, EvaluationOrder::ForceRightToLeft);
}
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 90da139c0f19c7..966a5ae62228b3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -36,6 +36,7 @@
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/MissingFeatures.h"
#include "clang/CIR/TypeEvaluationKind.h"
+#include "clang/CodeGenUtils/CallUtils.h"
#include "clang/CodeGenUtils/StmtUtils.h"
#include "llvm/ADT/ScopedHashTable.h"
#include "llvm/IR/Instructions.h"
@@ -711,6 +712,8 @@ class CIRGenFunction : public CIRGenTypeCache {
PrototypeWrapper(const clang::ObjCMethodDecl *md) : p(md) {}
};
+ using EvaluationOrder = CodeGenUtils::EvaluationOrder;
+
bool isLValueSuitableForInlineAtomic(LValue lv);
RValue emitAtomicLoad(LValue lvalue, SourceLocation loc,
@@ -2055,7 +2058,8 @@ class CIRGenFunction : public CIRGenTypeCache {
void emitCallArgs(
CallArgList &args, PrototypeWrapper prototype,
llvm::iterator_range<clang::CallExpr::const_arg_iterator> argRange,
- AbstractCallee callee = AbstractCallee(), unsigned paramsToSkip = 0);
+ AbstractCallee callee = AbstractCallee(), unsigned paramsToSkip = 0,
+ EvaluationOrder order = EvaluationOrder::Default);
RValue emitCallExpr(const clang::CallExpr *e,
ReturnValueSlot returnValue = ReturnValueSlot());
LValue emitCallExprLValue(const clang::CallExpr *e);
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 1f4fd55060d39d..ee7ad6c2f1252f 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -5145,10 +5145,8 @@ void CodeGenFunction::EmitCallArgs(
// case, there are certain language constructs that require left-to-right
// evaluation, and in those cases we consider the evaluation order requirement
// to trump the "destruction order is reverse construction order" guarantee.
- bool LeftToRight =
- CGM.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()
- ? Order == EvaluationOrder::ForceLeftToRight
- : Order != EvaluationOrder::ForceRightToLeft;
+ bool LeftToRight = CodeGenUtils::shouldEvaluateArgsLeftToRight(
+ Order, CGM.getTarget().getCXXABI());
auto MaybeEmitImplicitObjectSize = [&](unsigned I, const Expr *Arg,
RValue EmittedArg) {
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 96c6022f599b77..bc113538122bfe 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -7230,32 +7230,9 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
if (Chain)
Args.add(RValue::get(Chain), CGM.getContext().VoidPtrTy);
- // C++17 requires that we evaluate arguments to a call using assignment syntax
- // right-to-left, and that we evaluate arguments to certain other operators
- // left-to-right. Note that we allow this to override the order dictated by
- // the calling convention on the MS ABI, which means that parameter
- // destruction order is not necessarily reverse construction order.
- // FIXME: Revisit this based on C++ committee response to unimplementability.
- EvaluationOrder Order = EvaluationOrder::Default;
+ EvaluationOrder Order = CodeGenUtils::getCallArgEvaluationOrder(E);
bool StaticOperator = false;
if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) {
- if (OCE->isAssignmentOp())
- Order = EvaluationOrder::ForceRightToLeft;
- else {
- switch (OCE->getOperator()) {
- case OO_LessLess:
- case OO_GreaterGreater:
- case OO_AmpAmp:
- case OO_PipePipe:
- case OO_Comma:
- case OO_ArrowStar:
- Order = EvaluationOrder::ForceLeftToRight;
- break;
- default:
- break;
- }
- }
-
if (const auto *MD =
dyn_cast_if_present<CXXMethodDecl>(OCE->getCalleeDecl());
MD && MD->isStatic())
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 00294ad547d5ec..0417e9cac067cb 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -35,6 +35,7 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGenUtils/CallUtils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
@@ -5647,14 +5648,7 @@ class CodeGenFunction : public CodeGenTypeCache {
const VarDecl &D);
public:
- enum class EvaluationOrder {
- ///! No language constraints on evaluation order.
- Default,
- ///! Language semantics require left-to-right evaluation.
- ForceLeftToRight,
- ///! Language semantics require right-to-left evaluation.
- ForceRightToLeft
- };
+ using EvaluationOrder = CodeGenUtils::EvaluationOrder;
// Wrapper for function prototype sources. Wraps either a FunctionProtoType or
// an ObjCMethodDecl.
diff --git a/clang/lib/CodeGenUtils/CallUtils.cpp b/clang/lib/CodeGenUtils/CallUtils.cpp
index 9eb3c7cf0bc041..06747f04955e9f 100644
--- a/clang/lib/CodeGenUtils/CallUtils.cpp
+++ b/clang/lib/CodeGenUtils/CallUtils.cpp
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "clang/CodeGenUtils/CallUtils.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/TargetCXXABI.h"
namespace clang::CodeGenUtils {
@@ -25,4 +27,36 @@ llvm::FPClassTest getNoFPClassTestMask(const LangOptions &LangOpts) {
return Mask;
}
+EvaluationOrder getCallArgEvaluationOrder(const CallExpr *E) {
+ // Note that we allow this to override the order dictated by the calling
+ // convention on the MS ABI, which means that parameter destruction order is
+ // not necessarily reverse construction order.
+ // FIXME: Revisit this based on C++ committee response to unimplementability.
+ const auto *OCE = dyn_cast<CXXOperatorCallExpr>(E);
+ if (!OCE)
+ return EvaluationOrder::Default;
+
+ if (OCE->isAssignmentOp())
+ return EvaluationOrder::ForceRightToLeft;
+
+ switch (OCE->getOperator()) {
+ case OO_LessLess:
+ case OO_GreaterGreater:
+ case OO_AmpAmp:
+ case OO_PipePipe:
+ case OO_Comma:
+ case OO_ArrowStar:
+ return EvaluationOrder::ForceLeftToRight;
+ default:
+ return EvaluationOrder::Default;
+ }
+}
+
+bool shouldEvaluateArgsLeftToRight(EvaluationOrder Order,
+ const TargetCXXABI &ABI) {
+ return ABI.areArgsDestroyedLeftToRightInCallee()
+ ? Order == EvaluationOrder::ForceLeftToRight
+ : Order != EvaluationOrder::ForceRightToLeft;
+}
+
} // namespace clang::CodeGenUtils
diff --git a/clang/test/CIR/CodeGen/cxx1z-eval-order.cpp b/clang/test/CIR/CodeGen/cxx1z-eval-order.cpp
new file mode 100644
index 00000000000000..3dc9b2666923aa
--- /dev/null
+++ b/clang/test/CIR/CodeGen/cxx1z-eval-order.cpp
@@ -0,0 +1,386 @@
+// RUN: %clang_cc1 -std=c++1z -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++1z -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++1z -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+// Port of clang/test/CodeGenCXX/cxx1z-eval-order.cpp. The MS ABI RUN lines
+// are not ported because ClangIR does not support the MS ABI yet.
+
+struct B;
+struct A {
+ A();
+ A(const A&);
+
+ void operator[](B b);
+
+ int a_member_f(B);
+};
+struct B {
+ B();
+ ~B();
+};
+
+struct C {
+ operator int *();
+ A *operator->();
+ void operator->*(A);
+ friend void operator->*(C, B);
+
+ friend void operator<<(C, B);
+ friend void operator>>(C, B);
+ void operator<<(A);
+ void operator>>(A);
+
+ void operator=(A);
+ void operator+=(A);
+ friend void operator+=(C, B);
+
+ void operator,(A);
+ friend void operator,(C, B);
+
+ void operator&&(A);
+ void operator||(A);
+ friend void operator&&(C, B);
+ friend void operator||(C, B);
+};
+
+A make_a();
+A *make_a_ptr();
+int A::*make_mem_ptr_a();
+void (A::*make_mem_fn_ptr_a())();
+B make_b();
+C make_c();
+void side_effect();
+
+void callee(A);
+void (*get_f())(A);
+
+
+// CIR-LABEL: cir.func {{.*}} @_Z19postfix_before_argsv(
+// LLVM-LABEL: define {{.*}} @_Z19postfix_before_argsv(
+void postfix_before_args() {
+ // CIR: cir.call @_Z5get_fv(
+ // CIR: cir.call @_ZN1AC1Ev(
+ // CIR: cir.call %{{.+}}(
+ // LLVM: call {{.*}} @_Z5get_fv(
+ // LLVM: call {{.*}} @_ZN1AC1Ev(
+ // LLVM: call void %{{.+}}(
+ get_f()(A{});
+
+ // CIR: cir.call @_Z11side_effectv(
+ // CIR: cir.call @_ZN1AC1Ev(
+ // CIR: cir.call @_Z6callee1A(
+ // LLVM: call {{.*}} @_Z11side_effectv(
+ // LLVM: call {{.*}} @_ZN1AC1Ev(
+ // LLVM: call {{.*}} @_Z6callee1A(
+ (side_effect(), callee)(A{});
+}
+
+
+// CIR-LABEL: cir.func {{.*}} @_Z18dot_lhs_before_rhsv(
+// LLVM-LABEL: define {{.*}} @_Z18dot_lhs_before_rhsv(
+void dot_lhs_before_rhs() {
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_Z6make_bv(
+ // CIR: cir.call @_ZN1A10a_member_fE1B(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_Z6make_bv(
+ // LLVM: call {{.*}} @_ZN1A10a_member_fE1B(
+ make_a().a_member_f(make_b());
+
+ // CIR: cir.call @_Z10make_a_ptrv(
+ // CIR: cir.call @_Z6make_bv(
+ // CIR: cir.call @_ZN1A10a_member_fE1B(
+ // LLVM: call {{.*}} @_Z10make_a_ptrv(
+ // LLVM: call {{.*}} @_Z6make_bv(
+ // LLVM: call {{.*}} @_ZN1A10a_member_fE1B(
+ make_a_ptr()->a_member_f(make_b());
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_ZN1CptEv(
+ // CIR: cir.call @_Z6make_bv(
+ // CIR: cir.call @_ZN1A10a_member_fE1B(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_ZN1CptEv(
+ // LLVM: call {{.*}} @_Z6make_bv(
+ // LLVM: call {{.*}} @_ZN1A10a_member_fE1B(
+ make_c()->a_member_f(make_b());
+}
+
+
+// CIR-LABEL: cir.func {{.*}} @_Z20array_lhs_before_rhsv(
+// LLVM-LABEL: define {{.*}} @_Z20array_lhs_before_rhsv(
+void array_lhs_before_rhs() {
+ int (&get_arr())[10];
+ extern int get_index();
+
+ // CIR: cir.call @_Z7get_arrv(
+ // CIR: cir.call @_Z9get_indexv(
+ // LLVM: call {{.*}} @_Z7get_arrv(
+ // LLVM: call {{.*}} @_Z9get_indexv(
+ get_arr()[get_index()] = 0;
+
+ // CIR: cir.call @_Z9get_indexv(
+ // CIR: cir.call @_Z7get_arrv(
+ // LLVM: call {{.*}} @_Z9get_indexv(
+ // LLVM: call {{.*}} @_Z7get_arrv(
+ get_index()[get_arr()] = 0;
+
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_Z6make_bv(
+ // CIR: cir.call @_ZN1AixE1B(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_Z6make_bv(
+ // LLVM: call {{.*}} @_ZN1AixE1B(
+ make_a()[make_b()];
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_ZN1CcvPiEv(
+ // CIR: cir.call @_Z9get_indexv(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_ZN1CcvPiEv(
+ // LLVM: call {{.*}} @_Z9get_indexv(
+ make_c()[get_index()] = 0;
+
+ // CIR: cir.call @_Z9get_indexv(
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_ZN1CcvPiEv(
+ // LLVM: call {{.*}} @_Z9get_indexv(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_ZN1CcvPiEv(
+ get_index()[make_c()] = 0;
+}
+
+
+void *operator new(decltype(sizeof(0)), C);
+
+// CIR-LABEL: cir.func {{.*}} @_Z17alloc_before_initv(
+// LLVM-LABEL: define {{.*}} @_Z17alloc_before_initv(
+void alloc_before_init() {
+ struct Q { Q(A) {} };
+ // CIR: cir.call @_Znwm(
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_ZZ17alloc_before_initvEN1QC1E1A(
+ // LLVM: call {{.*}} @_Znwm(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_ZZ17alloc_before_initvEN1QC1E1A(
+ delete new Q(make_a());
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Znwm1C(
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_ZZ17alloc_before_initvEN1QC1E1A(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Znwm1C(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_ZZ17alloc_before_initvEN1QC1E1A(
+ new (make_c()) Q(make_a());
+}
+
+
+// CIR-LABEL: cir.func {{.*}} @_Z22dotstar_lhs_before_rhsv(
+// LLVM-LABEL: define {{.*}} @_Z22dotstar_lhs_before_rhsv(
+int dotstar_lhs_before_rhs() {
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_Z14make_mem_ptr_av(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_Z14make_mem_ptr_av(
+ int a = make_a().*make_mem_ptr_a();
+
+ // CIR: cir.call @_Z10make_a_ptrv(
+ // CIR: cir.call @_Z14make_mem_ptr_av(
+ // LLVM: call {{.*}} @_Z10make_a_ptrv(
+ // LLVM: call {{.*}} @_Z14make_mem_ptr_av(
+ int b = make_a_ptr()->*make_mem_ptr_a();
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_ZN1CpmE1A(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_ZN1CpmE1A(
+ make_c()->*make_a();
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_bv(
+ // CIR: cir.call @_Zpm1C1B(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_bv(
+ // LLVM: call {{.*}} @_Zpm1C1B(
+ make_c()->*make_b();
+
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_Z17make_mem_fn_ptr_av(
+ // CIR: cir.call %{{.+}}(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_Z17make_mem_fn_ptr_av(
+ // LLVM: call void %{{.+}}(
+ (make_a().*make_mem_fn_ptr_a())();
+
+ // CIR: cir.call @_Z10make_a_ptrv(
+ // CIR: cir.call @_Z17make_mem_fn_ptr_av(
+ // CIR: cir.call %{{.+}}(
+ // LLVM: call {{.*}} @_Z10make_a_ptrv(
+ // LLVM: call {{.*}} @_Z17make_mem_fn_ptr_av(
+ // LLVM: call void %{{.+}}(
+ (make_a_ptr()->*make_mem_fn_ptr_a())();
+
+ return a + b;
+}
+
+
+// CIR-LABEL: cir.func {{.*}} @_Z21assign_rhs_before_lhsv(
+// LLVM-LABEL: define {{.*}} @_Z21assign_rhs_before_lhsv(
+void assign_rhs_before_lhs() {
+ extern int &lhs_ref(), rhs();
+
+ // CIR: cir.call @_Z3rhsv(
+ // CIR: cir.call @_Z7lhs_refv(
+ // LLVM: call {{.*}} @_Z3rhsv(
+ // LLVM: call {{.*}} @_Z7lhs_refv(
+ lhs_ref() = rhs();
+
+ // CIR: cir.call @_Z3rhsv(
+ // CIR: cir.call @_Z7lhs_refv(
+ // LLVM: call {{.*}} @_Z3rhsv(
+ // LLVM: call {{.*}} @_Z7lhs_refv(
+ lhs_ref() += rhs();
+
+ // CIR: cir.call @_Z3rhsv(
+ // CIR: cir.call @_Z7lhs_refv(
+ // LLVM: call {{.*}} @_Z3rhsv(
+ // LLVM: call {{.*}} @_Z7lhs_refv(
+ lhs_ref() %= rhs();
+
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_ZN1CaSE1A(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_ZN1CaSE1A(
+ make_c() = make_a();
+
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_ZN1CpLE1A(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_ZN1CpLE1A(
+ make_c() += make_a();
+
+ // CIR: cir.call @_Z6make_bv(
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_ZpL1C1B(
+ // LLVM: call {{.*}} @_Z6make_bv(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_ZpL1C1B(
+ make_c() += make_b();
+}
+
+// CIR-LABEL: cir.func {{.*}} @_Z20shift_lhs_before_rhsv(
+// LLVM-LABEL: define {{.*}} @_Z20shift_lhs_before_rhsv(
+void shift_lhs_before_rhs() {
+ extern int lhs(), rhs();
+
+ // CIR: cir.call @_Z3lhsv(
+ // CIR: cir.call @_Z3rhsv(
+ // LLVM: call {{.*}} @_Z3lhsv(
+ // LLVM: call {{.*}} @_Z3rhsv(
+ (void)(lhs() << rhs());
+
+ // CIR: cir.call @_Z3lhsv(
+ // CIR: cir.call @_Z3rhsv(
+ // LLVM: call {{.*}} @_Z3lhsv(
+ // LLVM: call {{.*}} @_Z3rhsv(
+ (void)(lhs() >> rhs());
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_ZN1ClsE1A(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_ZN1ClsE1A(
+ make_c() << make_a();
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_ZN1CrsE1A(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_ZN1CrsE1A(
+ make_c() >> make_a();
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_bv(
+ // CIR: cir.call @_Zls1C1B(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_bv(
+ // LLVM: call {{.*}} @_Zls1C1B(
+ make_c() << make_b();
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_bv(
+ // CIR: cir.call @_Zrs1C1B(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_bv(
+ // LLVM: call {{.*}} @_Zrs1C1B(
+ make_c() >> make_b();
+}
+
+// CIR-LABEL: cir.func {{.*}} @_Z20comma_lhs_before_rhsv(
+// LLVM-LABEL: define {{.*}} @_Z20comma_lhs_before_rhsv(
+void comma_lhs_before_rhs() {
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_ZN1CcmE1A(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_ZN1CcmE1A(
+ make_c() , make_a();
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_bv(
+ // CIR: cir.call @_Zcm1C1B(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_bv(
+ // LLVM: call {{.*}} @_Zcm1C1B(
+ make_c() , make_b();
+}
+
+// CIR-LABEL: cir.func {{.*}} @_Z20andor_lhs_before_rhsv(
+// LLVM-LABEL: define {{.*}} @_Z20andor_lhs_before_rhsv(
+void andor_lhs_before_rhs() {
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_ZN1CaaE1A(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_ZN1CaaE1A(
+ make_c() && make_a();
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_av(
+ // CIR: cir.call @_ZN1CooE1A(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_av(
+ // LLVM: call {{.*}} @_ZN1CooE1A(
+ make_c() || make_a();
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_bv(
+ // CIR: cir.call @_Zaa1C1B(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_bv(
+ // LLVM: call {{.*}} @_Zaa1C1B(
+ make_c() && make_b();
+
+ // CIR: cir.call @_Z6make_cv(
+ // CIR: cir.call @_Z6make_bv(
+ // CIR: cir.call @_Zoo1C1B(
+ // LLVM: call {{.*}} @_Z6make_cv(
+ // LLVM: call {{.*}} @_Z6make_bv(
+ // LLVM: call {{.*}} @_Zoo1C1B(
+ make_c() || make_b();
+}
>From c22efe32fb29111598e5e0a39a4ea75be67413bf Mon Sep 17 00:00:00 2001
From: Konstantinos Parasyris <konstantinos.parasyris at intel.com>
Date: Fri, 16 Oct 2026 07:33:49 -0700
Subject: [PATCH 2/2] Move comment to original position
---
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index a6b815aaea8e3f..f65b85f7952d3e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -2438,15 +2438,15 @@ RValue CIRGenFunction::emitCall(clang::QualType calleeTy,
assert(!cir::MissingFeatures::sanitizers());
CallArgList args;
-
EvaluationOrder order = CodeGenUtils::getCallArgEvaluationOrder(e);
+
+ // C++23 static-member operators (`static operator()` /
+ // `static operator[]`) produce a CXXOperatorCallExpr whose first argument
+ // is the object expression even though the operator is static. Emit the
+ // object for its side effects and drop it before walking the parameter
+ // arguments.
auto arguments = e->arguments();
if (const auto *oce = dyn_cast<CXXOperatorCallExpr>(e)) {
- // C++23 static-member operators (`static operator()` /
- // `static operator[]`) produce a CXXOperatorCallExpr whose first argument
- // is the object expression even though the operator is static. Emit the
- // object for its side effects and drop it before walking the parameter
- // arguments.
if (const auto *md =
dyn_cast_if_present<CXXMethodDecl>(oce->getCalleeDecl());
md && md->isStatic()) {
More information about the cfe-commits
mailing list