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
