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 <[email protected]>
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 <[email protected]>
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()) {

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

Reply via email to