Skip to content

Commit 201eb2b

Browse files
committed
Revert "[clang] static operators should evaluate object argument (#68485)"
This reverts commit 30155fc. It seems to have broken some tests in clangd: http://45.33.8.238/linux/129484/step_9.txt
1 parent 3477bcf commit 201eb2b

9 files changed

+42
-158
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,6 @@ Bug Fixes to C++ Support
180180
- Fix for crash when using a erroneous type in a return statement.
181181
Fixes (`#63244 <https://github.com/llvm/llvm-project/issues/63244>`_)
182182
and (`#79745 <https://github.com/llvm/llvm-project/issues/79745>`_)
183-
- Fix incorrect code generation caused by the object argument of ``static operator()`` and ``static operator[]`` calls not being evaluated.
184-
Fixes (`#67976 <https://github.com/llvm/llvm-project/issues/67976>`_)
185183

186184
Bug Fixes to AST Handling
187185
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/AST/ExprConstant.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7951,8 +7951,7 @@ class ExprEvaluatorBase
79517951
// Overloaded operator calls to member functions are represented as normal
79527952
// calls with '*this' as the first argument.
79537953
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
7954-
if (MD &&
7955-
(MD->isImplicitObjectMemberFunction() || (OCE && MD->isStatic()))) {
7954+
if (MD && MD->isImplicitObjectMemberFunction()) {
79567955
// FIXME: When selecting an implicit conversion for an overloaded
79577956
// operator delete, we sometimes try to evaluate calls to conversion
79587957
// operators without a 'this' parameter!
@@ -7961,11 +7960,7 @@ class ExprEvaluatorBase
79617960

79627961
if (!EvaluateObjectArgument(Info, Args[0], ThisVal))
79637962
return false;
7964-
7965-
// If we are calling a static operator, the 'this' argument needs to be
7966-
// ignored after being evaluated.
7967-
if (MD->isInstance())
7968-
This = &ThisVal;
7963+
This = &ThisVal;
79697964

79707965
// If this is syntactically a simple assignment using a trivial
79717966
// assignment operator, start the lifetimes of union members as needed,

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5848,7 +5848,6 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
58485848
// destruction order is not necessarily reverse construction order.
58495849
// FIXME: Revisit this based on C++ committee response to unimplementability.
58505850
EvaluationOrder Order = EvaluationOrder::Default;
5851-
bool StaticOperator = false;
58525851
if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) {
58535852
if (OCE->isAssignmentOp())
58545853
Order = EvaluationOrder::ForceRightToLeft;
@@ -5866,22 +5865,10 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
58665865
break;
58675866
}
58685867
}
5869-
5870-
if (const auto *MD =
5871-
dyn_cast_if_present<CXXMethodDecl>(OCE->getCalleeDecl());
5872-
MD && MD->isStatic())
5873-
StaticOperator = true;
58745868
}
58755869

5876-
auto Arguments = E->arguments();
5877-
if (StaticOperator) {
5878-
// If we're calling a static operator, we need to emit the object argument
5879-
// and ignore it.
5880-
EmitIgnoredExpr(E->getArg(0));
5881-
Arguments = drop_begin(Arguments, 1);
5882-
}
5883-
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), Arguments,
5884-
E->getDirectCallee(), /*ParamsToSkip=*/0, Order);
5870+
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), E->arguments(),
5871+
E->getDirectCallee(), /*ParamsToSkip*/ 0, Order);
58855872

58865873
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall(
58875874
Args, FnType, /*ChainCall=*/Chain);

clang/lib/Sema/SemaChecking.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7611,8 +7611,9 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
76117611
unsigned NumArgs = TheCall->getNumArgs();
76127612

76137613
Expr *ImplicitThis = nullptr;
7614-
if (IsMemberOperatorCall && !FDecl->hasCXXExplicitFunctionObjectParameter()) {
7615-
// If this is a call to a member operator, hide the first
7614+
if (IsMemberOperatorCall && !FDecl->isStatic() &&
7615+
!FDecl->hasCXXExplicitFunctionObjectParameter()) {
7616+
// If this is a call to a non-static member operator, hide the first
76167617
// argument from checkCall.
76177618
// FIXME: Our choice of AST representation here is less than ideal.
76187619
ImplicitThis = Args[0];

clang/lib/Sema/SemaOverload.cpp

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5664,15 +5664,10 @@ static ImplicitConversionSequence TryObjectArgumentInitialization(
56645664
assert(FromType->isRecordType());
56655665

56665666
QualType ClassType = S.Context.getTypeDeclType(ActingContext);
5667-
// C++98 [class.dtor]p2:
5668-
// A destructor can be invoked for a const, volatile or const volatile
5669-
// object.
5670-
// C++98 [over.match.funcs]p4:
5671-
// For static member functions, the implicit object parameter is considered
5672-
// to match any object (since if the function is selected, the object is
5673-
// discarded).
5667+
// [class.dtor]p2: A destructor can be invoked for a const, volatile or
5668+
// const volatile object.
56745669
Qualifiers Quals = Method->getMethodQualifiers();
5675-
if (isa<CXXDestructorDecl>(Method) || Method->isStatic()) {
5670+
if (isa<CXXDestructorDecl>(Method)) {
56765671
Quals.addConst();
56775672
Quals.addVolatile();
56785673
}
@@ -15066,15 +15061,15 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
1506615061
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
1506715062
SmallVector<Expr *, 2> MethodArgs;
1506815063

15069-
// Initialize the object parameter.
15064+
// Handle 'this' parameter if the selected function is not static.
1507015065
if (Method->isExplicitObjectMemberFunction()) {
1507115066
ExprResult Res =
1507215067
InitializeExplicitObjectArgument(*this, Args[0], Method);
1507315068
if (Res.isInvalid())
1507415069
return ExprError();
1507515070
Args[0] = Res.get();
1507615071
ArgExpr = Args;
15077-
} else {
15072+
} else if (Method->isInstance()) {
1507815073
ExprResult Arg0 = PerformImplicitObjectArgumentInitialization(
1507915074
Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method);
1508015075
if (Arg0.isInvalid())
@@ -15102,9 +15097,15 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
1510215097
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
1510315098
ResultTy = ResultTy.getNonLValueExprType(Context);
1510415099

15105-
CallExpr *TheCall = CXXOperatorCallExpr::Create(
15106-
Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, RLoc,
15107-
CurFPFeatureOverrides());
15100+
CallExpr *TheCall;
15101+
if (Method->isInstance())
15102+
TheCall = CXXOperatorCallExpr::Create(
15103+
Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK,
15104+
RLoc, CurFPFeatureOverrides());
15105+
else
15106+
TheCall =
15107+
CallExpr::Create(Context, FnExpr.get(), MethodArgs, ResultTy, VK,
15108+
RLoc, CurFPFeatureOverrides());
1510815109

1510915110
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
1511015111
return ExprError();
@@ -15732,13 +15733,15 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
1573215733

1573315734
bool IsError = false;
1573415735

15735-
// Initialize the object parameter.
15736+
// Initialize the implicit object parameter if needed.
15737+
// Since C++23, this could also be a call to a static call operator
15738+
// which we emit as a regular CallExpr.
1573615739
llvm::SmallVector<Expr *, 8> NewArgs;
1573715740
if (Method->isExplicitObjectMemberFunction()) {
1573815741
// FIXME: we should do that during the definition of the lambda when we can.
1573915742
DiagnoseInvalidExplicitObjectParameterInLambda(Method);
1574015743
PrepareExplicitObjectArgument(*this, Method, Obj, Args, NewArgs);
15741-
} else {
15744+
} else if (Method->isInstance()) {
1574215745
ExprResult ObjRes = PerformImplicitObjectArgumentInitialization(
1574315746
Object.get(), /*Qualifier=*/nullptr, Best->FoundDecl, Method);
1574415747
if (ObjRes.isInvalid())
@@ -15772,9 +15775,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
1577215775
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
1577315776
ResultTy = ResultTy.getNonLValueExprType(Context);
1577415777

15775-
CallExpr *TheCall = CXXOperatorCallExpr::Create(
15776-
Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, VK, RParenLoc,
15777-
CurFPFeatureOverrides());
15778+
CallExpr *TheCall;
15779+
if (Method->isInstance())
15780+
TheCall = CXXOperatorCallExpr::Create(Context, OO_Call, NewFn.get(),
15781+
MethodArgs, ResultTy, VK, RParenLoc,
15782+
CurFPFeatureOverrides());
15783+
else
15784+
TheCall = CallExpr::Create(Context, NewFn.get(), MethodArgs, ResultTy, VK,
15785+
RParenLoc, CurFPFeatureOverrides());
1577815786

1577915787
if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method))
1578015788
return true;

clang/test/AST/ast-dump-static-operators.cpp

Lines changed: 0 additions & 55 deletions
This file was deleted.

clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,16 @@ void CallsTheLambda() {
1919

2020
// CHECK: define {{.*}}CallsTheLambda{{.*}}
2121
// CHECK-NEXT: entry:
22-
// CHECK: {{.*}}call {{.*}}GetALambda{{.*}}()
23-
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}(i32 noundef 1, i32 noundef 2)
22+
// CHECK-NEXT: %call = call noundef i32 {{.*}}(i32 noundef 1, i32 noundef 2)
2423
// CHECK-NEXT: ret void
2524
// CHECK-NEXT: }
2625

27-
Functor GetAFunctor() {
28-
return {};
29-
}
30-
3126
void call_static_call_operator() {
3227
Functor f;
3328
f(101, 102);
3429
f.operator()(201, 202);
3530
Functor{}(301, 302);
3631
Functor::operator()(401, 402);
37-
GetAFunctor()(501, 502);
3832
}
3933

4034
// CHECK: define {{.*}}call_static_call_operator{{.*}}
@@ -43,8 +37,6 @@ void call_static_call_operator() {
4337
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 201, i32 noundef 202)
4438
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 301, i32 noundef 302)
4539
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 401, i32 noundef 402)
46-
// CHECK: {{.*}}call {{.*}}GetAFunctor{{.*}}()
47-
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 501, i32 noundef 502)
4840
// CHECK-NEXT: ret void
4941
// CHECK-NEXT: }
5042

@@ -114,16 +106,12 @@ void test_dep_functors() {
114106

115107
// CHECK: define {{.*}}test_dep_functors{{.*}}
116108
// CHECK-NEXT: entry:
117-
// CHECK: {{.*}} = call noundef i32 {{.*}}DepFunctor{{.*}}(float noundef 1.000000e+00)
118-
// CHECK: {{.*}} = call noundef i32 {{.*}}DepFunctor{{.*}}(i1 noundef zeroext true)
119-
// CHECK: {{.*}}call {{.*}}dep_lambda1{{.*}}()
120-
// CHECK: {{.*}} = call noundef i32 {{.*}}dep_lambda1{{.*}}(float noundef 1.000000e+00)
121-
// CHECK: {{.*}}call {{.*}}dep_lambda1{{.*}}()
122-
// CHECK: {{.*}} = call noundef i32 {{.*}}dep_lambda1{{.*}}(i1 noundef zeroext true)
123-
// CHECK: {{.*}}call {{.*}}dep_lambda2{{.*}}()
124-
// CHECK: {{.*}} = call noundef i32 {{.*}}dep_lambda2{{.*}}(float noundef 1.000000e+00)
125-
// CHECK: {{.*}}call {{.*}}dep_lambda2{{.*}}()
126-
// CHECK: {{.*}} = call noundef i32 {{.*}}dep_lambda2{{.*}}(i1 noundef zeroext true)
109+
// CHECK: %call = call noundef i32 {{.*}}DepFunctor{{.*}}(float noundef 1.000000e+00)
110+
// CHECK: %call1 = call noundef i32 {{.*}}DepFunctor{{.*}}(i1 noundef zeroext true)
111+
// CHECK: %call2 = call noundef i32 {{.*}}dep_lambda1{{.*}}(float noundef 1.000000e+00)
112+
// CHECK: %call3 = call noundef i32 {{.*}}dep_lambda1{{.*}}(i1 noundef zeroext true)
113+
// CHECK: %call4 = call noundef i32 {{.*}}dep_lambda2{{.*}}(float noundef 1.000000e+00)
114+
// CHECK: %call5 = call noundef i32 {{.*}}dep_lambda2{{.*}}(i1 noundef zeroext true)
127115
// CHECK: ret void
128116
// CHECK-NEXT: }
129117

clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,12 @@ struct Functor {
77
}
88
};
99

10-
Functor GetAFunctor() {
11-
return {};
12-
}
13-
1410
void call_static_subscript_operator() {
1511
Functor f;
1612
f[101, 102];
1713
f.operator[](201, 202);
1814
Functor{}[301, 302];
1915
Functor::operator[](401, 402);
20-
GetAFunctor()[501, 502];
2116
}
2217

2318
// CHECK: define {{.*}}call_static_subscript_operator{{.*}}
@@ -26,8 +21,6 @@ void call_static_subscript_operator() {
2621
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 201, i32 noundef 202)
2722
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 301, i32 noundef 302)
2823
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 401, i32 noundef 402)
29-
// CHECK: {{.*}}call {{.*}}GetAFunctor{{.*}}()
30-
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 501, i32 noundef 502)
3124
// CHECK-NEXT: ret void
3225
// CHECK-NEXT: }
3326

@@ -67,7 +60,7 @@ void test_dep_functors() {
6760

6861
// CHECK: define {{.*}}test_dep_functors{{.*}}
6962
// CHECK-NEXT: entry:
70-
// CHECK: {{.*}} = call noundef i32 {{.*}}DepFunctor{{.*}}(float noundef 1.000000e+00)
71-
// CHECK: {{.*}} = call noundef i32 {{.*}}DepFunctor{{.*}}(i1 noundef zeroext true)
63+
// CHECK: %call = call noundef i32 {{.*}}DepFunctor{{.*}}(float noundef 1.000000e+00)
64+
// CHECK: %call1 = call noundef i32 {{.*}}DepFunctor{{.*}}(i1 noundef zeroext true)
7265
// CHECK: ret void
7366
// CHECK-NEXT: }

clang/test/SemaCXX/cxx2b-static-operator.cpp

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)