https://github.com/SuperSodaSea updated https://github.com/llvm/llvm-project/pull/68485
>From 03276260c48d9cafb2a0d80825156e77cdf02eba Mon Sep 17 00:00:00 2001 From: SuperSodaSea <bobby...@126.com> Date: Sat, 7 Oct 2023 21:05:17 +0800 Subject: [PATCH 1/6] [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 5a33e918db8e8c0..a6c81f467fbe01c 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<CXXMethodDecl>(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 54a1d300a9ac738..19406ff174dea14 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<CXXOperatorCallExpr>(E)) if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(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 2e7059cc8f5b639..a580c635998510f 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<FunctionProtoType>(); + + // 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 d5336382a2b9c95..42de125e7489911 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 446e35218bff0ad..a536f5f72811ec9 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 ce78994e6553814..82b4bfe980b7963 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<CXXMethodDecl>(FnDecl); SmallVector<Expr *, 2> 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<Expr *, 8> 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 000000000000000..87a15403e6f8b23 --- /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 {{.*}} <col:19, col:24> 'int (*)(int, int)' <FunctionToPointerDecay> + // CHECK-NEXT: | `-DeclRefExpr {{.*}} <col:19, col:24> 'int (int, int)' lvalue CXXMethod {{.*}} 'operator()' 'int (int, int)' + // CHECK-NEXT: |-DeclRefExpr {{.*}} <col:12> 'Functor':'Functor' lvalue Var {{.*}} 'functor' 'Functor':'Functor' + // CHECK-NEXT: |-IntegerLiteral {{.*}} <col:20> 'int' 1 + // CHECK-NEXT: `-IntegerLiteral {{.*}} <col:23> 'int' 2 + + int z2 = functor[1, 2]; + // CHECK: CXXOperatorCallExpr {{.*}} 'int' '[]' + // CHECK-NEXT: |-ImplicitCastExpr {{.*}} <col:19, col:24> 'int (*)(int, int)' <FunctionToPointerDecay> + // CHECK-NEXT: | `-DeclRefExpr {{.*}} <col:19, col:24> 'int (int, int)' lvalue CXXMethod {{.*}} 'operator[]' 'int (int, int)' + // CHECK-NEXT: |-DeclRefExpr {{.*}} <col:12> 'Functor':'Functor' lvalue Var {{.*}} 'functor' 'Functor':'Functor' + // CHECK-NEXT: |-IntegerLiteral {{.*}} <col:20> 'int' 1 + // CHECK-NEXT: `-IntegerLiteral {{.*}} <col:23> 'int' 2 + + int z3 = get_functor()(1, 2); + // CHECK: CXXOperatorCallExpr {{.*}} 'int' '()' + // CHECK-NEXT: |-ImplicitCastExpr {{.*}} <col:25, col:30> 'int (*)(int, int)' <FunctionToPointerDecay> + // CHECK-NEXT: | `-DeclRefExpr {{.*}} <col:25, col:30> 'int (int, int)' lvalue CXXMethod {{.*}} 'operator()' 'int (int, int)' + // CHECK-NEXT: |-CallExpr {{.*}} <col:12, col:24> 'Functor':'Functor' lvalue + // CHECK-NEXT: | `-ImplicitCastExpr {{.*}} <col:12> 'Functor &(*)()' <FunctionToPointerDecay> + // CHECK-NEXT: | `-DeclRefExpr {{.*}} <col:12> 'Functor &()' lvalue Function {{.*}} 'get_functor' 'Functor &()' + // CHECK-NEXT: |-IntegerLiteral {{.*}} <col:26> 'int' 1 + // CHECK-NEXT: `-IntegerLiteral {{.*}} <col:29> 'int' 2 + + int z4 = get_functor()[1, 2]; + // CHECK: CXXOperatorCallExpr {{.*}} 'int' '[]' + // CHECK-NEXT: |-ImplicitCastExpr {{.*}} <col:25, col:30> 'int (*)(int, int)' <FunctionToPointerDecay> + // CHECK-NEXT: | `-DeclRefExpr {{.*}} <col:25, col:30> 'int (int, int)' lvalue CXXMethod {{.*}} 'operator[]' 'int (int, int)' + // CHECK-NEXT: |-CallExpr {{.*}} <col:12, col:24> 'Functor':'Functor' lvalue + // CHECK-NEXT: | `-ImplicitCastExpr {{.*}} <col:12> 'Functor &(*)()' <FunctionToPointerDecay> + // CHECK-NEXT: | `-DeclRefExpr {{.*}} <col:12> 'Functor &()' lvalue Function {{.*}} 'get_functor' 'Functor &()' + // CHECK-NEXT: |-IntegerLiteral {{.*}} <col:26> 'int' 1 + // CHECK-NEXT: `-IntegerLiteral {{.*}} <col:29> 'int' 2 +} diff --git a/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp b/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp index fd53649c9b06186..9cf5a7e00e7b4ef 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 5dbd2c50cc56bd2..5d8258978c50d57 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 <bobby...@126.com> Date: Sun, 8 Oct 2023 21:25:44 +0800 Subject: [PATCH 2/6] 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 19406ff174dea14..427ad0f01a59ba1 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<CXXOperatorCallExpr>(E)) if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(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<CXXOperatorCallExpr>(E)) { + auto *OCE = dyn_cast<CXXOperatorCallExpr>(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<CXXMethodDecl>(OCE->getCalleeDecl()); + MD && MD->isStatic()) + StaticOperator = true; } - EmitCallArgs(Args, dyn_cast<FunctionProtoType>(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<FunctionProtoType>(FnType), + drop_begin(E->arguments(), 1), E->getDirectCallee(), + /*ParamsToSkip*/ 0, Order); + } else + EmitCallArgs(Args, dyn_cast<FunctionProtoType>(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 a580c635998510f..2e7059cc8f5b639 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<FunctionProtoType>(); - - // 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 42de125e7489911..d5336382a2b9c95 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 <bobby...@126.com> Date: Tue, 10 Oct 2023 15:37:36 +0800 Subject: [PATCH 3/6] 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 82b4bfe980b7963..c36e1b1da409b23 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<CXXMethodDecl>(FnDecl); SmallVector<Expr *, 2> 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<Expr *, 8> 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 <bobby...@126.com> Date: Tue, 10 Oct 2023 17:17:40 +0800 Subject: [PATCH 4/6] 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 427ad0f01a59ba1..cb9d26a3f2487f8 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<CXXOperatorCallExpr>(E); bool StaticOperator = false; + auto *OCE = dyn_cast<CXXOperatorCallExpr>(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<FunctionProtoType>(FnType), drop_begin(E->arguments(), 1), E->getDirectCallee(), >From 12d3ea25a0afe29bfa4f91f7f3a9b1f01026dadb Mon Sep 17 00:00:00 2001 From: Tianlan Zhou <bobby...@126.com> Date: Wed, 11 Oct 2023 17:41:02 +0800 Subject: [PATCH 5/6] Apply suggestions from shafik Co-authored-by: Shafik Yaghmour <sha...@users.noreply.github.com> --- 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 cb9d26a3f2487f8..53af5dea8d9e0fa 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<FunctionProtoType>(FnType), drop_begin(E->arguments(), 1), E->getDirectCallee(), - /*ParamsToSkip*/ 0, Order); + /*ParamsToSkip=*/0, Order); } else EmitCallArgs(Args, dyn_cast<FunctionProtoType>(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 <bobby...@126.com> Date: Thu, 12 Oct 2023 01:46:31 +0800 Subject: [PATCH 6/6] 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 a6c81f467fbe01c..31cadf5aac50108 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, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits