Author: Aaron Ballman Date: 2024-01-30T13:38:18-05:00 New Revision: 201eb2b5775cf193c97c60a5eb790003a1e6bedb
URL: https://github.com/llvm/llvm-project/commit/201eb2b5775cf193c97c60a5eb790003a1e6bedb DIFF: https://github.com/llvm/llvm-project/commit/201eb2b5775cf193c97c60a5eb790003a1e6bedb.diff LOG: Revert "[clang] static operators should evaluate object argument (#68485)" This reverts commit 30155fc0ef4fbdce2d79434aaae8d58b2fabb20a. It seems to have broken some tests in clangd: http://45.33.8.238/linux/129484/step_9.txt Added: Modified: clang/docs/ReleaseNotes.rst clang/lib/AST/ExprConstant.cpp clang/lib/CodeGen/CGExpr.cpp clang/lib/Sema/SemaChecking.cpp clang/lib/Sema/SemaOverload.cpp clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp Removed: clang/test/AST/ast-dump-static-operators.cpp clang/test/SemaCXX/cxx2b-static-operator.cpp ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 95ad23fb04d44..323157c4db1f1 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -180,8 +180,6 @@ Bug Fixes to C++ Support - Fix for crash when using a erroneous type in a return statement. Fixes (`#63244 <https://github.com/llvm/llvm-project/issues/63244>`_) and (`#79745 <https://github.com/llvm/llvm-project/issues/79745>`_) -- Fix incorrect code generation caused by the object argument of ``static operator()`` and ``static operator[]`` calls not being evaluated. - Fixes (`#67976 <https://github.com/llvm/llvm-project/issues/67976>`_) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 63453890d9879..a41bdac46c814 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7951,8 +7951,7 @@ 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() || (OCE && MD->isStatic()))) { + if (MD && MD->isImplicitObjectMemberFunction()) { // FIXME: When selecting an implicit conversion for an overloaded // operator delete, we sometimes try to evaluate calls to conversion // operators without a 'this' parameter! @@ -7961,11 +7960,7 @@ class ExprEvaluatorBase if (!EvaluateObjectArgument(Info, Args[0], ThisVal)) return false; - - // If we are calling a static operator, the 'this' argument needs to be - // ignored after being evaluated. - if (MD->isInstance()) - This = &ThisVal; + This = &ThisVal; // If this is syntactically a simple assignment using a trivial // assignment operator, start the lifetimes of union members as needed, diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 4a2f3caad6588..8c8c937b512ac 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5848,7 +5848,6 @@ 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; - bool StaticOperator = false; if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) { if (OCE->isAssignmentOp()) Order = EvaluationOrder::ForceRightToLeft; @@ -5866,22 +5865,10 @@ 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; } - 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); - } - EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), Arguments, - E->getDirectCallee(), /*ParamsToSkip=*/0, Order); + 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/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 7b877da1a928f..a9f08354b3497 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -7611,8 +7611,9 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, unsigned NumArgs = TheCall->getNumArgs(); Expr *ImplicitThis = nullptr; - if (IsMemberOperatorCall && !FDecl->hasCXXExplicitFunctionObjectParameter()) { - // If this is a call to a member operator, hide the first + if (IsMemberOperatorCall && !FDecl->isStatic() && + !FDecl->hasCXXExplicitFunctionObjectParameter()) { + // If this is a call to a non-static 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 940bcccb9e261..c9eb678983563 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5664,15 +5664,10 @@ static ImplicitConversionSequence TryObjectArgumentInitialization( assert(FromType->isRecordType()); QualType ClassType = S.Context.getTypeDeclType(ActingContext); - // C++98 [class.dtor]p2: - // A destructor can be invoked for a const, volatile or const volatile - // object. - // 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). + // [class.dtor]p2: A destructor can be invoked for a const, volatile or + // const volatile object. Qualifiers Quals = Method->getMethodQualifiers(); - if (isa<CXXDestructorDecl>(Method) || Method->isStatic()) { + if (isa<CXXDestructorDecl>(Method)) { Quals.addConst(); Quals.addVolatile(); } @@ -15066,7 +15061,7 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); SmallVector<Expr *, 2> MethodArgs; - // Initialize the object parameter. + // Handle 'this' parameter if the selected function is not static. if (Method->isExplicitObjectMemberFunction()) { ExprResult Res = InitializeExplicitObjectArgument(*this, Args[0], Method); @@ -15074,7 +15069,7 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, return ExprError(); Args[0] = Res.get(); ArgExpr = Args; - } else { + } else if (Method->isInstance()) { ExprResult Arg0 = PerformImplicitObjectArgumentInitialization( Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method); if (Arg0.isInvalid()) @@ -15102,9 +15097,15 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CallExpr *TheCall = CXXOperatorCallExpr::Create( - Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, RLoc, - CurFPFeatureOverrides()); + 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()); if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl)) return ExprError(); @@ -15732,13 +15733,15 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, bool IsError = false; - // Initialize the object parameter. + // 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. 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 { + } else if (Method->isInstance()) { ExprResult ObjRes = PerformImplicitObjectArgumentInitialization( Object.get(), /*Qualifier=*/nullptr, Best->FoundDecl, Method); if (ObjRes.isInvalid()) @@ -15772,9 +15775,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CallExpr *TheCall = CXXOperatorCallExpr::Create( - Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, VK, RParenLoc, - CurFPFeatureOverrides()); + 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()); 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 deleted file mode 100644 index e8454bdac02f7..0000000000000 --- a/clang/test/AST/ast-dump-static-operators.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// 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' lvalue Var {{.*}} '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' lvalue Var {{.*}} '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' 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' 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 9cf5a7e00e7b4..fd53649c9b061 100644 --- a/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp +++ b/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp @@ -19,22 +19,16 @@ void CallsTheLambda() { // CHECK: define {{.*}}CallsTheLambda{{.*}} // CHECK-NEXT: entry: -// CHECK: {{.*}}call {{.*}}GetALambda{{.*}}() -// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}(i32 noundef 1, i32 noundef 2) +// CHECK-NEXT: %call = 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{{.*}} @@ -43,8 +37,6 @@ 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: } @@ -114,16 +106,12 @@ void test_dep_functors() { // CHECK: define {{.*}}test_dep_functors{{.*}} // CHECK-NEXT: entry: -// 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: %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: 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 5d8258978c50d..5dbd2c50cc56b 100644 --- a/clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp +++ b/clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp @@ -7,17 +7,12 @@ 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{{.*}} @@ -26,8 +21,6 @@ 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: } @@ -67,7 +60,7 @@ void test_dep_functors() { // CHECK: define {{.*}}test_dep_functors{{.*}} // CHECK-NEXT: entry: -// CHECK: {{.*}} = call noundef i32 {{.*}}DepFunctor{{.*}}(float noundef 1.000000e+00) -// CHECK: {{.*}} = call noundef i32 {{.*}}DepFunctor{{.*}}(i1 noundef zeroext true) +// CHECK: %call = call noundef i32 {{.*}}DepFunctor{{.*}}(float noundef 1.000000e+00) +// CHECK: %call1 = call noundef i32 {{.*}}DepFunctor{{.*}}(i1 noundef zeroext true) // CHECK: ret void // CHECK-NEXT: } diff --git a/clang/test/SemaCXX/cxx2b-static-operator.cpp b/clang/test/SemaCXX/cxx2b-static-operator.cpp deleted file mode 100644 index 4d6f1f76d1315..0000000000000 --- a/clang/test/SemaCXX/cxx2b-static-operator.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// 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]; -} - -} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits