From 03276260c48d9cafb2a0d80825156e77cdf02eba Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Sat, 7 Oct 2023 21:05:17 +0800 Subject: [PATCH 01/18] [clang] static operators should evaluate object argument --- clang/lib/AST/ExprConstant.cpp | 3 +- clang/lib/CodeGen/CGExpr.cpp | 2 +- clang/lib/CodeGen/CGExprCXX.cpp | 41 ++++++++++++-- clang/lib/CodeGen/CodeGenFunction.h | 3 + clang/lib/Sema/SemaChecking.cpp | 5 +- clang/lib/Sema/SemaOverload.cpp | 33 ++++------- clang/test/AST/ast-dump-static-operators.cpp | 55 +++++++++++++++++++ .../CodeGenCXX/cxx2b-static-call-operator.cpp | 26 ++++++--- .../cxx2b-static-subscript-operator.cpp | 11 +++- 9 files changed, 137 insertions(+), 42 deletions(-) create mode 100644 clang/test/AST/ast-dump-static-operators.cpp diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 5a33e918db8e8c..a6c81f467fbe01 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7806,7 +7806,8 @@ class ExprEvaluatorBase // Overloaded operator calls to member functions are represented as normal // calls with '*this' as the first argument. const CXXMethodDecl *MD = dyn_cast(FD); - if (MD && MD->isImplicitObjectMemberFunction()) { + if (MD && + (MD->isImplicitObjectMemberFunction() || (OCE && MD->isStatic()))) { // FIXME: When selecting an implicit conversion for an overloaded // operator delete, we sometimes try to evaluate calls to conversion // operators without a 'this' parameter! diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 54a1d300a9ac73..19406ff174dea1 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5070,7 +5070,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, if (const auto *CE = dyn_cast(E)) if (const auto *MD = dyn_cast_if_present(CE->getCalleeDecl()); - MD && MD->isImplicitObjectMemberFunction()) + MD && !MD->isExplicitObjectMemberFunction()) return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue); CGCallee callee = EmitCallee(E->getCallee()); diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 2e7059cc8f5b63..a580c635998510 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -489,11 +489,42 @@ RValue CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue) { - assert(MD->isImplicitObjectMemberFunction() && - "Trying to emit a member call expr on a static method!"); - return EmitCXXMemberOrOperatorMemberCallExpr( - E, MD, ReturnValue, /*HasQualifier=*/false, /*Qualifier=*/nullptr, - /*IsArrow=*/false, E->getArg(0)); + assert(!MD->isExplicitObjectMemberFunction() && + "Trying to emit a member call expr on an explicit object member " + "function!"); + + if (MD->isStatic()) + return EmitCXXStaticOperatorMemberCallExpr(E, MD, ReturnValue); + else + return EmitCXXMemberOrOperatorMemberCallExpr( + E, MD, ReturnValue, /*HasQualifier=*/false, /*Qualifier=*/nullptr, + /*IsArrow=*/false, E->getArg(0)); +} + +RValue CodeGenFunction::EmitCXXStaticOperatorMemberCallExpr( + const CXXOperatorCallExpr *E, const CXXMethodDecl *MD, + ReturnValueSlot ReturnValue) { + assert(MD->isStatic()); + + CGCallee Callee = EmitCallee(E->getCallee()); + + // Emit and ignore `this` pointer. + EmitIgnoredExpr(E->getArg(0)); + + auto ProtoType = MD->getFunctionType()->castAs(); + + // Emit the rest of the call args. + CallArgList Args; + EmitCallArgs(Args, ProtoType, drop_begin(E->arguments(), 1), + E->getDirectCallee()); + + bool Chain = E == MustTailCall; + const CGFunctionInfo &FnInfo = + CGM.getTypes().arrangeFreeFunctionCall(Args, ProtoType, Chain); + llvm::CallBase *CallOrInvoke = nullptr; + + return EmitCall(FnInfo, Callee, ReturnValue, Args, &CallOrInvoke, Chain, + E->getExprLoc()); } RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E, diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index d5336382a2b9c9..42de125e748991 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4163,6 +4163,9 @@ class CodeGenFunction : public CodeGenTypeCache { RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue); + RValue EmitCXXStaticOperatorMemberCallExpr(const CXXOperatorCallExpr *CE, + const CXXMethodDecl *MD, + ReturnValueSlot ReturnValue); RValue EmitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E); RValue EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 446e35218bff0a..a536f5f72811ec 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -6942,9 +6942,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, unsigned NumArgs = TheCall->getNumArgs(); Expr *ImplicitThis = nullptr; - if (IsMemberOperatorCall && !FDecl->isStatic() && - !FDecl->hasCXXExplicitFunctionObjectParameter()) { - // If this is a call to a non-static member operator, hide the first + if (IsMemberOperatorCall && !FDecl->hasCXXExplicitFunctionObjectParameter()) { + // If this is a call to a member operator, hide the first // argument from checkCall. // FIXME: Our choice of AST representation here is less than ideal. ImplicitThis = Args[0]; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index ce78994e655381..82b4bfe980b796 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -14935,7 +14935,7 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, CXXMethodDecl *Method = cast(FnDecl); SmallVector MethodArgs; - // Handle 'this' parameter if the selected function is not static. + // Initialize the explicit / implicit object parameter. if (Method->isExplicitObjectMemberFunction()) { ExprResult Res = InitializeExplicitObjectArgument(*this, Args[0], Method); @@ -14943,7 +14943,7 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, return ExprError(); Args[0] = Res.get(); ArgExpr = Args; - } else if (Method->isInstance()) { + } else { ExprResult Arg0 = PerformImplicitObjectArgumentInitialization( Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method); if (Arg0.isInvalid()) @@ -14971,15 +14971,9 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CallExpr *TheCall; - if (Method->isInstance()) - TheCall = CXXOperatorCallExpr::Create( - Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, - RLoc, CurFPFeatureOverrides()); - else - TheCall = - CallExpr::Create(Context, FnExpr.get(), MethodArgs, ResultTy, VK, - RLoc, CurFPFeatureOverrides()); + CallExpr *TheCall = CXXOperatorCallExpr::Create( + Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, RLoc, + CurFPFeatureOverrides()); if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl)) return ExprError(); @@ -15607,15 +15601,13 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, bool IsError = false; - // Initialize the implicit object parameter if needed. - // Since C++23, this could also be a call to a static call operator - // which we emit as a regular CallExpr. + // Initialize the explicit / implicit object parameter. llvm::SmallVector NewArgs; if (Method->isExplicitObjectMemberFunction()) { // FIXME: we should do that during the definition of the lambda when we can. DiagnoseInvalidExplicitObjectParameterInLambda(Method); PrepareExplicitObjectArgument(*this, Method, Obj, Args, NewArgs); - } else if (Method->isInstance()) { + } else { ExprResult ObjRes = PerformImplicitObjectArgumentInitialization( Object.get(), /*Qualifier=*/nullptr, Best->FoundDecl, Method); if (ObjRes.isInvalid()) @@ -15649,14 +15641,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CallExpr *TheCall; - if (Method->isInstance()) - TheCall = CXXOperatorCallExpr::Create(Context, OO_Call, NewFn.get(), - MethodArgs, ResultTy, VK, RParenLoc, - CurFPFeatureOverrides()); - else - TheCall = CallExpr::Create(Context, NewFn.get(), MethodArgs, ResultTy, VK, - RParenLoc, CurFPFeatureOverrides()); + CallExpr *TheCall = CXXOperatorCallExpr::Create( + Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, VK, RParenLoc, + CurFPFeatureOverrides()); if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method)) return true; diff --git a/clang/test/AST/ast-dump-static-operators.cpp b/clang/test/AST/ast-dump-static-operators.cpp new file mode 100644 index 00000000000000..87a15403e6f8b2 --- /dev/null +++ b/clang/test/AST/ast-dump-static-operators.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -std=c++23 %s -ast-dump -triple x86_64-unknown-unknown -o - | FileCheck -strict-whitespace %s + +struct Functor { + static int operator()(int x, int y) { + return x + y; + } + static int operator[](int x, int y) { + return x + y; + } +}; + +Functor& get_functor() { + static Functor functor; + return functor; +} + +void call_static_operators() { + Functor functor; + + int z1 = functor(1, 2); + // CHECK: CXXOperatorCallExpr {{.*}} 'int' '()' + // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int (*)(int, int)' + // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int (int, int)' lvalue CXXMethod {{.*}} 'operator()' 'int (int, int)' + // CHECK-NEXT: |-DeclRefExpr {{.*}} 'Functor':'Functor' lvalue Var {{.*}} 'functor' 'Functor':'Functor' + // CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1 + // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2 + + int z2 = functor[1, 2]; + // CHECK: CXXOperatorCallExpr {{.*}} 'int' '[]' + // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int (*)(int, int)' + // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int (int, int)' lvalue CXXMethod {{.*}} 'operator[]' 'int (int, int)' + // CHECK-NEXT: |-DeclRefExpr {{.*}} 'Functor':'Functor' lvalue Var {{.*}} 'functor' 'Functor':'Functor' + // CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1 + // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2 + + int z3 = get_functor()(1, 2); + // CHECK: CXXOperatorCallExpr {{.*}} 'int' '()' + // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int (*)(int, int)' + // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int (int, int)' lvalue CXXMethod {{.*}} 'operator()' 'int (int, int)' + // CHECK-NEXT: |-CallExpr {{.*}} 'Functor':'Functor' lvalue + // CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'Functor &(*)()' + // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'Functor &()' lvalue Function {{.*}} 'get_functor' 'Functor &()' + // CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1 + // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2 + + int z4 = get_functor()[1, 2]; + // CHECK: CXXOperatorCallExpr {{.*}} 'int' '[]' + // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int (*)(int, int)' + // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int (int, int)' lvalue CXXMethod {{.*}} 'operator[]' 'int (int, int)' + // CHECK-NEXT: |-CallExpr {{.*}} 'Functor':'Functor' lvalue + // CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'Functor &(*)()' + // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'Functor &()' lvalue Function {{.*}} 'get_functor' 'Functor &()' + // CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1 + // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2 +} diff --git a/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp b/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp index fd53649c9b0618..9cf5a7e00e7b4e 100644 --- a/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp +++ b/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp @@ -19,16 +19,22 @@ void CallsTheLambda() { // CHECK: define {{.*}}CallsTheLambda{{.*}} // CHECK-NEXT: entry: -// CHECK-NEXT: %call = call noundef i32 {{.*}}(i32 noundef 1, i32 noundef 2) +// CHECK: {{.*}}call {{.*}}GetALambda{{.*}}() +// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}(i32 noundef 1, i32 noundef 2) // CHECK-NEXT: ret void // CHECK-NEXT: } +Functor GetAFunctor() { + return {}; +} + void call_static_call_operator() { Functor f; f(101, 102); f.operator()(201, 202); Functor{}(301, 302); Functor::operator()(401, 402); + GetAFunctor()(501, 502); } // CHECK: define {{.*}}call_static_call_operator{{.*}} @@ -37,6 +43,8 @@ void call_static_call_operator() { // CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 201, i32 noundef 202) // CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 301, i32 noundef 302) // CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 401, i32 noundef 402) +// CHECK: {{.*}}call {{.*}}GetAFunctor{{.*}}() +// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 501, i32 noundef 502) // CHECK-NEXT: ret void // CHECK-NEXT: } @@ -106,12 +114,16 @@ void test_dep_functors() { // CHECK: define {{.*}}test_dep_functors{{.*}} // CHECK-NEXT: entry: -// CHECK: %call = call noundef i32 {{.*}}DepFunctor{{.*}}(float noundef 1.000000e+00) -// CHECK: %call1 = call noundef i32 {{.*}}DepFunctor{{.*}}(i1 noundef zeroext true) -// CHECK: %call2 = call noundef i32 {{.*}}dep_lambda1{{.*}}(float noundef 1.000000e+00) -// CHECK: %call3 = call noundef i32 {{.*}}dep_lambda1{{.*}}(i1 noundef zeroext true) -// CHECK: %call4 = call noundef i32 {{.*}}dep_lambda2{{.*}}(float noundef 1.000000e+00) -// CHECK: %call5 = call noundef i32 {{.*}}dep_lambda2{{.*}}(i1 noundef zeroext true) +// CHECK: {{.*}} = call noundef i32 {{.*}}DepFunctor{{.*}}(float noundef 1.000000e+00) +// CHECK: {{.*}} = call noundef i32 {{.*}}DepFunctor{{.*}}(i1 noundef zeroext true) +// CHECK: {{.*}}call {{.*}}dep_lambda1{{.*}}() +// CHECK: {{.*}} = call noundef i32 {{.*}}dep_lambda1{{.*}}(float noundef 1.000000e+00) +// CHECK: {{.*}}call {{.*}}dep_lambda1{{.*}}() +// CHECK: {{.*}} = call noundef i32 {{.*}}dep_lambda1{{.*}}(i1 noundef zeroext true) +// CHECK: {{.*}}call {{.*}}dep_lambda2{{.*}}() +// CHECK: {{.*}} = call noundef i32 {{.*}}dep_lambda2{{.*}}(float noundef 1.000000e+00) +// CHECK: {{.*}}call {{.*}}dep_lambda2{{.*}}() +// CHECK: {{.*}} = call noundef i32 {{.*}}dep_lambda2{{.*}}(i1 noundef zeroext true) // CHECK: ret void // CHECK-NEXT: } diff --git a/clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp b/clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp index 5dbd2c50cc56bd..5d8258978c50d5 100644 --- a/clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp +++ b/clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp @@ -7,12 +7,17 @@ struct Functor { } }; +Functor GetAFunctor() { + return {}; +} + void call_static_subscript_operator() { Functor f; f[101, 102]; f.operator[](201, 202); Functor{}[301, 302]; Functor::operator[](401, 402); + GetAFunctor()[501, 502]; } // CHECK: define {{.*}}call_static_subscript_operator{{.*}} @@ -21,6 +26,8 @@ void call_static_subscript_operator() { // CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 201, i32 noundef 202) // CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 301, i32 noundef 302) // CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 401, i32 noundef 402) +// CHECK: {{.*}}call {{.*}}GetAFunctor{{.*}}() +// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 501, i32 noundef 502) // CHECK-NEXT: ret void // CHECK-NEXT: } @@ -60,7 +67,7 @@ void test_dep_functors() { // CHECK: define {{.*}}test_dep_functors{{.*}} // CHECK-NEXT: entry: -// CHECK: %call = call noundef i32 {{.*}}DepFunctor{{.*}}(float noundef 1.000000e+00) -// CHECK: %call1 = call noundef i32 {{.*}}DepFunctor{{.*}}(i1 noundef zeroext true) +// CHECK: {{.*}} = call noundef i32 {{.*}}DepFunctor{{.*}}(float noundef 1.000000e+00) +// CHECK: {{.*}} = call noundef i32 {{.*}}DepFunctor{{.*}}(i1 noundef zeroext true) // CHECK: ret void // CHECK-NEXT: } From 63a3627d733477d5aa5c7add80bdece3d14eba94 Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Sun, 8 Oct 2023 21:25:44 +0800 Subject: [PATCH 02/18] Deal with static operator in EmitCall --- clang/lib/CodeGen/CGExpr.cpp | 24 ++++++++++++++--- clang/lib/CodeGen/CGExprCXX.cpp | 41 ++++------------------------- clang/lib/CodeGen/CodeGenFunction.h | 3 --- 3 files changed, 25 insertions(+), 43 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 19406ff174dea1..427ad0f01a59ba 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5070,7 +5070,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, if (const auto *CE = dyn_cast(E)) if (const auto *MD = dyn_cast_if_present(CE->getCalleeDecl()); - MD && !MD->isExplicitObjectMemberFunction()) + MD && MD->isImplicitObjectMemberFunction()) return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue); CGCallee callee = EmitCallee(E->getCallee()); @@ -5519,7 +5519,9 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee // destruction order is not necessarily reverse construction order. // FIXME: Revisit this based on C++ committee response to unimplementability. EvaluationOrder Order = EvaluationOrder::Default; - if (auto *OCE = dyn_cast(E)) { + auto *OCE = dyn_cast(E); + bool StaticOperator = false; + if (OCE) { if (OCE->isAssignmentOp()) Order = EvaluationOrder::ForceRightToLeft; else { @@ -5536,10 +5538,24 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee break; } } + + if (const auto *MD = + dyn_cast_if_present(OCE->getCalleeDecl()); + MD && MD->isStatic()) + StaticOperator = true; } - EmitCallArgs(Args, dyn_cast(FnType), E->arguments(), - E->getDirectCallee(), /*ParamsToSkip*/ 0, Order); + if (StaticOperator) { + // If we're calling a static operator, we need to emit the object argument + // and ignore it. + EmitIgnoredExpr(OCE->getArg(0)); + + EmitCallArgs(Args, dyn_cast(FnType), + drop_begin(E->arguments(), 1), E->getDirectCallee(), + /*ParamsToSkip*/ 0, Order); + } else + EmitCallArgs(Args, dyn_cast(FnType), E->arguments(), + E->getDirectCallee(), /*ParamsToSkip*/ 0, Order); const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall( Args, FnType, /*ChainCall=*/Chain); diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index a580c635998510..2e7059cc8f5b63 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -489,42 +489,11 @@ RValue CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue) { - assert(!MD->isExplicitObjectMemberFunction() && - "Trying to emit a member call expr on an explicit object member " - "function!"); - - if (MD->isStatic()) - return EmitCXXStaticOperatorMemberCallExpr(E, MD, ReturnValue); - else - return EmitCXXMemberOrOperatorMemberCallExpr( - E, MD, ReturnValue, /*HasQualifier=*/false, /*Qualifier=*/nullptr, - /*IsArrow=*/false, E->getArg(0)); -} - -RValue CodeGenFunction::EmitCXXStaticOperatorMemberCallExpr( - const CXXOperatorCallExpr *E, const CXXMethodDecl *MD, - ReturnValueSlot ReturnValue) { - assert(MD->isStatic()); - - CGCallee Callee = EmitCallee(E->getCallee()); - - // Emit and ignore `this` pointer. - EmitIgnoredExpr(E->getArg(0)); - - auto ProtoType = MD->getFunctionType()->castAs(); - - // Emit the rest of the call args. - CallArgList Args; - EmitCallArgs(Args, ProtoType, drop_begin(E->arguments(), 1), - E->getDirectCallee()); - - bool Chain = E == MustTailCall; - const CGFunctionInfo &FnInfo = - CGM.getTypes().arrangeFreeFunctionCall(Args, ProtoType, Chain); - llvm::CallBase *CallOrInvoke = nullptr; - - return EmitCall(FnInfo, Callee, ReturnValue, Args, &CallOrInvoke, Chain, - E->getExprLoc()); + assert(MD->isImplicitObjectMemberFunction() && + "Trying to emit a member call expr on a static method!"); + return EmitCXXMemberOrOperatorMemberCallExpr( + E, MD, ReturnValue, /*HasQualifier=*/false, /*Qualifier=*/nullptr, + /*IsArrow=*/false, E->getArg(0)); } RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E, diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 42de125e748991..d5336382a2b9c9 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4163,9 +4163,6 @@ class CodeGenFunction : public CodeGenTypeCache { RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue); - RValue EmitCXXStaticOperatorMemberCallExpr(const CXXOperatorCallExpr *CE, - const CXXMethodDecl *MD, - ReturnValueSlot ReturnValue); RValue EmitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E); RValue EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E, From 1269bc3dd7bfaa269a96586c263f922094aa8c8c Mon Sep 17 00:00:00 2001 From: Tianlan Zhou Date: Tue, 10 Oct 2023 15:37:36 +0800 Subject: [PATCH 03/18] Apply suggestions from cor3ntin --- clang/lib/Sema/SemaOverload.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 82b4bfe980b796..c36e1b1da409b2 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -14935,7 +14935,7 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, CXXMethodDecl *Method = cast(FnDecl); SmallVector MethodArgs; - // Initialize the explicit / implicit object parameter. + // Initialize the object parameter. if (Method->isExplicitObjectMemberFunction()) { ExprResult Res = InitializeExplicitObjectArgument(*this, Args[0], Method); @@ -15601,7 +15601,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, bool IsError = false; - // Initialize the explicit / implicit object parameter. + // Initialize the object parameter. llvm::SmallVector NewArgs; if (Method->isExplicitObjectMemberFunction()) { // FIXME: we should do that during the definition of the lambda when we can. From 755bcaaba13471204d5383dae99aaa65a305855a Mon Sep 17 00:00:00 2001 From: Tianlan Zhou Date: Tue, 10 Oct 2023 17:17:40 +0800 Subject: [PATCH 04/18] Minor changes --- clang/lib/CodeGen/CGExpr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 427ad0f01a59ba..cb9d26a3f2487f 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5519,8 +5519,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee // destruction order is not necessarily reverse construction order. // FIXME: Revisit this based on C++ committee response to unimplementability. EvaluationOrder Order = EvaluationOrder::Default; - auto *OCE = dyn_cast(E); bool StaticOperator = false; + auto *OCE = dyn_cast(E); if (OCE) { if (OCE->isAssignmentOp()) Order = EvaluationOrder::ForceRightToLeft; @@ -5548,7 +5548,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee if (StaticOperator) { // If we're calling a static operator, we need to emit the object argument // and ignore it. - EmitIgnoredExpr(OCE->getArg(0)); + EmitIgnoredExpr(E->getArg(0)); EmitCallArgs(Args, dyn_cast(FnType), drop_begin(E->arguments(), 1), E->getDirectCallee(), From 12d3ea25a0afe29bfa4f91f7f3a9b1f01026dadb Mon Sep 17 00:00:00 2001 From: Tianlan Zhou Date: Wed, 11 Oct 2023 17:41:02 +0800 Subject: [PATCH 05/18] Apply suggestions from shafik Co-authored-by: Shafik Yaghmour --- clang/lib/CodeGen/CGExpr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index cb9d26a3f2487f..53af5dea8d9e0f 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5552,10 +5552,10 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee EmitCallArgs(Args, dyn_cast(FnType), drop_begin(E->arguments(), 1), E->getDirectCallee(), - /*ParamsToSkip*/ 0, Order); + /*ParamsToSkip=*/0, Order); } else EmitCallArgs(Args, dyn_cast(FnType), E->arguments(), - E->getDirectCallee(), /*ParamsToSkip*/ 0, Order); + E->getDirectCallee(), /*ParamsToSkip=*/0, Order); const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall( Args, FnType, /*ChainCall=*/Chain); From e725a8f2000690986872ad05e5bde582967f81de Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Thu, 12 Oct 2023 01:46:31 +0800 Subject: [PATCH 06/18] Ignore `this` in constexpr evaluation --- clang/lib/AST/ExprConstant.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a6c81f467fbe01..31cadf5aac5010 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7816,7 +7816,11 @@ class ExprEvaluatorBase if (!EvaluateObjectArgument(Info, Args[0], ThisVal)) return false; - This = &ThisVal; + + // If we are calling a static operator, the 'this' argument needs to be + // ignored after being evaluated. + if (MD->isInstance()) + This = &ThisVal; // If this is syntactically a simple assignment using a trivial // assignment operator, start the lifetimes of union members as needed, From 5accc5d469d3d388eeaf2cce3b3ecb29bf05edc3 Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Thu, 4 Jan 2024 23:16:55 +0800 Subject: [PATCH 07/18] Update clang/docs/ReleaseNotes.rst --- clang/docs/ReleaseNotes.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 30cfe66703f5a9..6101046595c533 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -685,9 +685,11 @@ Bug Fixes in This Version (`#65568 `_) - Fix an issue where clang doesn't respect detault template arguments that are added in a later redeclaration for CTAD. - Fixes (#69987 `_) + Fixes (`#69987 `_) - Fix an issue where CTAD fails for explicit type conversion. - Fixes (#64347 `_) + Fixes (`#64347 `_) +- Fix an issue that the object argument of ``static operator()`` and ``static operator[]`` is not evaluate. + Fixes (`#67976 `_) Bug Fixes to Compiler Builtins From 6bcc590f206629f58360dc9d01bd88eeb5968ffa Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Fri, 5 Jan 2024 00:10:16 +0800 Subject: [PATCH 08/18] Update ast-dump-static-operators.cpp --- clang/test/AST/ast-dump-static-operators.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clang/test/AST/ast-dump-static-operators.cpp b/clang/test/AST/ast-dump-static-operators.cpp index 87a15403e6f8b2..e8454bdac02f7b 100644 --- a/clang/test/AST/ast-dump-static-operators.cpp +++ b/clang/test/AST/ast-dump-static-operators.cpp @@ -16,38 +16,38 @@ Functor& get_functor() { void call_static_operators() { Functor functor; - + int z1 = functor(1, 2); // CHECK: CXXOperatorCallExpr {{.*}} 'int' '()' // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int (*)(int, int)' // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int (int, int)' lvalue CXXMethod {{.*}} 'operator()' 'int (int, int)' - // CHECK-NEXT: |-DeclRefExpr {{.*}} 'Functor':'Functor' lvalue Var {{.*}} 'functor' 'Functor':'Functor' + // CHECK-NEXT: |-DeclRefExpr {{.*}} 'Functor' lvalue Var {{.*}} 'functor' 'Functor' // CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1 // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2 - + int z2 = functor[1, 2]; // CHECK: CXXOperatorCallExpr {{.*}} 'int' '[]' // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int (*)(int, int)' // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int (int, int)' lvalue CXXMethod {{.*}} 'operator[]' 'int (int, int)' - // CHECK-NEXT: |-DeclRefExpr {{.*}} 'Functor':'Functor' lvalue Var {{.*}} 'functor' 'Functor':'Functor' + // CHECK-NEXT: |-DeclRefExpr {{.*}} 'Functor' lvalue Var {{.*}} 'functor' 'Functor' // CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1 // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2 - + int z3 = get_functor()(1, 2); // CHECK: CXXOperatorCallExpr {{.*}} 'int' '()' // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int (*)(int, int)' // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int (int, int)' lvalue CXXMethod {{.*}} 'operator()' 'int (int, int)' - // CHECK-NEXT: |-CallExpr {{.*}} 'Functor':'Functor' lvalue + // CHECK-NEXT: |-CallExpr {{.*}} 'Functor' lvalue // CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'Functor &(*)()' // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'Functor &()' lvalue Function {{.*}} 'get_functor' 'Functor &()' // CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1 // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 2 - + int z4 = get_functor()[1, 2]; // CHECK: CXXOperatorCallExpr {{.*}} 'int' '[]' // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int (*)(int, int)' // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int (int, int)' lvalue CXXMethod {{.*}} 'operator[]' 'int (int, int)' - // CHECK-NEXT: |-CallExpr {{.*}} 'Functor':'Functor' lvalue + // CHECK-NEXT: |-CallExpr {{.*}} 'Functor' lvalue // CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'Functor &(*)()' // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'Functor &()' lvalue Function {{.*}} 'get_functor' 'Functor &()' // CHECK-NEXT: |-IntegerLiteral {{.*}} 'int' 1 From eb42407a523f9a79afca4fbf221b344330888cc6 Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Fri, 5 Jan 2024 13:17:59 +0800 Subject: [PATCH 09/18] Should work with const / volatile --- clang/lib/Sema/SemaOverload.cpp | 5 +++- clang/test/SemaCXX/cxx2b-static-operator.cpp | 31 ++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 clang/test/SemaCXX/cxx2b-static-operator.cpp diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 673f8313c2517b..1810fdd12bd444 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5680,8 +5680,11 @@ static ImplicitConversionSequence TryObjectArgumentInitialization( QualType ClassType = S.Context.getTypeDeclType(ActingContext); // [class.dtor]p2: A destructor can be invoked for a const, volatile or // const volatile object. + // Also, a static operator can be invoked for a const, volatile or const + // volatile object, apparently. + bool IsStaticOperator = Method->getDeclName().getCXXOverloadedOperator() != OO_None && Method->isStatic(); Qualifiers Quals = Method->getMethodQualifiers(); - if (isa(Method)) { + if (isa(Method) || IsStaticOperator) { Quals.addConst(); Quals.addVolatile(); } diff --git a/clang/test/SemaCXX/cxx2b-static-operator.cpp b/clang/test/SemaCXX/cxx2b-static-operator.cpp new file mode 100644 index 00000000000000..4d6f1f76d13157 --- /dev/null +++ b/clang/test/SemaCXX/cxx2b-static-operator.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++23 %s + +// expected-no-diagnostics + +namespace A { + +struct Foo { + static int operator()(int a, int b) { return a + b; } + static int operator[](int a, int b) { return a + b; } +}; + +void ok() { + // Should pass regardless of const / volatile + Foo foo; + foo(1, 2); + foo[1, 2]; + + const Foo fooC; + fooC(1, 2); + fooC[1, 2]; + + const Foo fooV; + fooV(1, 2); + fooV[1, 2]; + + const volatile Foo fooCV; + fooCV(1, 2); + fooCV[1, 2]; +} + +} From fa85d874fcf416e3eb5269fec7c6ce2f544e2b97 Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Fri, 5 Jan 2024 13:22:10 +0800 Subject: [PATCH 10/18] Format code --- clang/lib/Sema/SemaOverload.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 1810fdd12bd444..f9c7cf9b65b35c 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5682,7 +5682,9 @@ static ImplicitConversionSequence TryObjectArgumentInitialization( // const volatile object. // Also, a static operator can be invoked for a const, volatile or const // volatile object, apparently. - bool IsStaticOperator = Method->getDeclName().getCXXOverloadedOperator() != OO_None && Method->isStatic(); + bool IsStaticOperator = + Method->getDeclName().getCXXOverloadedOperator() != OO_None && + Method->isStatic(); Qualifiers Quals = Method->getMethodQualifiers(); if (isa(Method) || IsStaticOperator) { Quals.addConst(); From c679700fa5041395896dbe06a6f7675bcc4a0ddb Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Sun, 7 Jan 2024 02:40:50 +0800 Subject: [PATCH 11/18] Update clang/docs/ReleaseNotes.rst --- clang/docs/ReleaseNotes.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3873f06bde2d3f..86aa7033aefdd9 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -696,8 +696,6 @@ Bug Fixes in This Version - Clang now accepts recursive non-dependent calls to functions with deduced return type. Fixes (`#71015 `_) -- Fix an issue that the object argument of ``static operator()`` and ``static operator[]`` is not evaluate. - Fixes (`#67976 `_) Bug Fixes to Compiler Builtins @@ -860,10 +858,14 @@ Bug Fixes to C++ Support (`#64086 `_) - Fixed a regression where clang forgets how to substitute into constraints on template-template - parameters. Fixes: + parameters. Fixes: (`#57410 `_) and (`#76604 `_) +- Fix an issue that the object argument of ``static operator()`` and ``static operator[]`` is not evaluate. + Fixes (`#67976 `_) + + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an import failure of recursive friend class template. From d3edbd1e2bf1a04867ac3385cf67efc626674d56 Mon Sep 17 00:00:00 2001 From: Tianlan Zhou Date: Fri, 12 Jan 2024 00:48:02 +0800 Subject: [PATCH 12/18] Update clang/docs/ReleaseNotes.rst Co-authored-by: cor3ntin --- clang/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 86aa7033aefdd9..68b8e2603b099f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -862,7 +862,7 @@ Bug Fixes to C++ Support (`#57410 `_) and (`#76604 `_) -- Fix an issue that the object argument of ``static operator()`` and ``static operator[]`` is not evaluate. +- Fix incorrect code generation caused by the object argument of ``static operator()`` and ``static operator[]`` calls not being evaluated. Fixes (`#67976 `_) From 490fd0f910b1baa9cde08b10a7c0f7fef504421e Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Fri, 12 Jan 2024 00:55:57 +0800 Subject: [PATCH 13/18] Apply suggestions from @cor3ntin --- clang/lib/Sema/SemaOverload.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index a606070c6667b7..a5ea4f46035f7e 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5678,15 +5678,15 @@ static ImplicitConversionSequence TryObjectArgumentInitialization( assert(FromType->isRecordType()); QualType ClassType = S.Context.getTypeDeclType(ActingContext); - // [class.dtor]p2: A destructor can be invoked for a const, volatile or - // const volatile object. - // Also, a static operator can be invoked for a const, volatile or const - // volatile object, apparently. - bool IsStaticOperator = - Method->getDeclName().getCXXOverloadedOperator() != OO_None && - Method->isStatic(); + // [class.dtor]p2: + // A destructor can be invoked for a const, volatile or const volatile + // object. + // [over.match.funcs.general]p4.2: + // For static member functions, the implicit object parameter is considered + // to match any object (since if the function is selected, the object is + // discarded). Qualifiers Quals = Method->getMethodQualifiers(); - if (isa(Method) || IsStaticOperator) { + if (isa(Method) || Method->isStatic()) { Quals.addConst(); Quals.addVolatile(); } From 94195a2aa5477b033d4f02aeb00a9d838e8d2e63 Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Fri, 12 Jan 2024 01:11:38 +0800 Subject: [PATCH 14/18] Update wording --- clang/lib/Sema/SemaOverload.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 1ca6ba347b703a..14ca2388249dfe 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5678,10 +5678,10 @@ static ImplicitConversionSequence TryObjectArgumentInitialization( assert(FromType->isRecordType()); QualType ClassType = S.Context.getTypeDeclType(ActingContext); - // [class.dtor]p2: + // C++98 [class.dtor]p2: // A destructor can be invoked for a const, volatile or const volatile // object. - // [over.match.funcs.general]p4.2: + // C++98 [over.match.funcs]p4: // For static member functions, the implicit object parameter is considered // to match any object (since if the function is selected, the object is // discarded). From a14149419165abfb273610e43cc4e1c60a909cf2 Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Fri, 12 Jan 2024 01:34:10 +0800 Subject: [PATCH 15/18] Make CI happy --- clang/docs/HLSL/FunctionCalls.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/HLSL/FunctionCalls.rst b/clang/docs/HLSL/FunctionCalls.rst index 996ddd6944b1ce..7317de2163f897 100644 --- a/clang/docs/HLSL/FunctionCalls.rst +++ b/clang/docs/HLSL/FunctionCalls.rst @@ -144,7 +144,7 @@ undefined behavior in HLSL, and any use of the argument after the call is a use of an undefined value which may be illegal in the target (DXIL programs with used or potentially used ``undef`` or ``poison`` values fail validation). -Clang Implementation +Clang Implementation ==================== .. note:: From 5c3dfb342fe6030676a06aa22339050bbcca1719 Mon Sep 17 00:00:00 2001 From: Tianlan Zhou Date: Tue, 30 Jan 2024 22:02:03 +0800 Subject: [PATCH 16/18] Apply suggestion from @AaronBallman Co-authored-by: Aaron Ballman --- clang/lib/CodeGen/CGExpr.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index d0f3789dc496a4..5836862a24a894 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5849,8 +5849,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee // FIXME: Revisit this based on C++ committee response to unimplementability. EvaluationOrder Order = EvaluationOrder::Default; bool StaticOperator = false; - auto *OCE = dyn_cast(E); - if (OCE) { + if (auto *OCE = dyn_cast(E)) { if (OCE->isAssignmentOp()) Order = EvaluationOrder::ForceRightToLeft; else { From c560b388d58e3dec74d42e757555ee998a75012a Mon Sep 17 00:00:00 2001 From: Tianlan Zhou Date: Tue, 30 Jan 2024 22:28:07 +0800 Subject: [PATCH 17/18] Apply suggestion from @AaronBallman --- clang/lib/CodeGen/CGExpr.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 5836862a24a894..00055e55559ae0 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5873,17 +5873,15 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee StaticOperator = true; } + auto arguments = E->arguments(); if (StaticOperator) { // If we're calling a static operator, we need to emit the object argument // and ignore it. EmitIgnoredExpr(E->getArg(0)); - - EmitCallArgs(Args, dyn_cast(FnType), - drop_begin(E->arguments(), 1), E->getDirectCallee(), - /*ParamsToSkip=*/0, Order); - } else - EmitCallArgs(Args, dyn_cast(FnType), E->arguments(), - E->getDirectCallee(), /*ParamsToSkip=*/0, Order); + arguments = drop_begin(arguments, 1); + } + EmitCallArgs(Args, dyn_cast(FnType), arguments, + E->getDirectCallee(), /*ParamsToSkip=*/0, Order); const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall( Args, FnType, /*ChainCall=*/Chain); From 1ceaae47b2b43fd8fa5512e20e0b32a7e8f4ab5b Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Tue, 30 Jan 2024 22:38:09 +0800 Subject: [PATCH 18/18] Use upper case --- clang/lib/CodeGen/CGExpr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 00055e55559ae0..4a2f3caad6588c 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5873,14 +5873,14 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee StaticOperator = true; } - auto arguments = E->arguments(); + auto Arguments = E->arguments(); if (StaticOperator) { // If we're calling a static operator, we need to emit the object argument // and ignore it. EmitIgnoredExpr(E->getArg(0)); - arguments = drop_begin(arguments, 1); + Arguments = drop_begin(Arguments, 1); } - EmitCallArgs(Args, dyn_cast(FnType), arguments, + EmitCallArgs(Args, dyn_cast(FnType), Arguments, E->getDirectCallee(), /*ParamsToSkip=*/0, Order); const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall(