[flang-commits] [openmp] [lld] [compiler-rt] [flang] [lldb] [libunwind] [libcxxabi] [llvm] [libcxx] [mlir] [clang-tools-extra] [clang] [libc] [clang] static operators should evaluate object argument (reland) (PR #80108)
Tianlan Zhou via flang-commits
flang-commits at lists.llvm.org
Tue Jan 30 23:04:33 PST 2024
https://github.com/SuperSodaSea created https://github.com/llvm/llvm-project/pull/80108
### Description
clang don't evaluate the object argument of `static operator()` and `static operator[]` currently, for example:
```cpp
#include <iostream>
struct Foo {
static int operator()(int x, int y) {
std::cout << "Foo::operator()" << std::endl;
return x + y;
}
static int operator[](int x, int y) {
std::cout << "Foo::operator[]" << std::endl;
return x + y;
}
};
Foo getFoo() {
std::cout << "getFoo()" << std::endl;
return {};
}
int main() {
std::cout << getFoo()(1, 2) << std::endl;
std::cout << getFoo()[1, 2] << std::endl;
}
```
`getFoo()` is expected to be called, but clang don't call it currently (17.0.6). This PR fixes this issue.
Fixes #67976, reland #68485.
### Walkthrough
- **clang/lib/Sema/SemaOverload.cpp**
- **`Sema::CreateOverloadedArraySubscriptExpr` & `Sema::BuildCallToObjectOfClassType`**
Previously clang generate `CallExpr` for static operators, ignoring the object argument. In this PR `CXXOperatorCallExpr` is generated for static operators instead, with the object argument as the first argument.
- **`TryObjectArgumentInitialization`**
`const` / `volatile` objects are allowed for static methods, so that we can call static operators on them.
- **clang/lib/CodeGen/CGExpr.cpp**
- **`CodeGenFunction::EmitCall`**
CodeGen changes for `CXXOperatorCallExpr` with static operators: emit and ignore the object argument first, then emit the operator call.
- **clang/lib/AST/ExprConstant.cpp**
- **`‎ExprEvaluatorBase::handleCallExpr‎`**
Evaluation of static operators in constexpr also need some small changes to work, so that the arguments won't be out of position.
- **clang/lib/Sema/SemaChecking.cpp**
- **`Sema::CheckFunctionCall`**
Code for argument checking also need to be modify, or it will fail the test `clang/test/SemaCXX/overloaded-operator-decl.cpp`.
- **clang-tools-extra/clangd/InlayHints.cpp**
- **`InlayHintVisitor::VisitCallExpr`**
Now that the `CXXOperatorCallExpr` for static operators also have object argument, we should also take care of this situation in clangd.
### Tests
- **Added:**
- **clang/test/AST/ast-dump-static-operators.cpp**
Verify the AST generated for static operators.
- **clang/test/SemaCXX/cxx2b-static-operator.cpp**
Static operators should be able to be called on const / volatile objects.
- **Modified:**
- **clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp**
- **clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp**
Matching the new CodeGen.
### Documentation
- **clang/docs/ReleaseNotes.rst**
Update release notes.
>From 03276260c48d9cafb2a0d80825156e77cdf02eba Mon Sep 17 00:00:00 2001
From: SuperSodaSea <bobby825 at 126.com>
Date: Sat, 7 Oct 2023 21:05:17 +0800
Subject: [PATCH 01/20] [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 5a33e918db8e8..a6c81f467fbe0 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 54a1d300a9ac7..19406ff174dea 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 2e7059cc8f5b6..a580c63599851 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 d5336382a2b9c..42de125e74899 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 446e35218bff0..a536f5f72811e 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 ce78994e65538..82b4bfe980b79 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 0000000000000..87a15403e6f8b
--- /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 fd53649c9b061..9cf5a7e00e7b4 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 5dbd2c50cc56b..5d8258978c50d 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 <bobby825 at 126.com>
Date: Sun, 8 Oct 2023 21:25:44 +0800
Subject: [PATCH 02/20] 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 19406ff174dea..427ad0f01a59b 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 a580c63599851..2e7059cc8f5b6 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 42de125e74899..d5336382a2b9c 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 <bobby825 at 126.com>
Date: Tue, 10 Oct 2023 15:37:36 +0800
Subject: [PATCH 03/20] 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 82b4bfe980b79..c36e1b1da409b 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 <bobby825 at 126.com>
Date: Tue, 10 Oct 2023 17:17:40 +0800
Subject: [PATCH 04/20] 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 427ad0f01a59b..cb9d26a3f2487 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 <bobby825 at 126.com>
Date: Wed, 11 Oct 2023 17:41:02 +0800
Subject: [PATCH 05/20] Apply suggestions from shafik
Co-authored-by: Shafik Yaghmour <shafik at 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 cb9d26a3f2487..53af5dea8d9e0 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 <bobby825 at 126.com>
Date: Thu, 12 Oct 2023 01:46:31 +0800
Subject: [PATCH 06/20] 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 a6c81f467fbe0..31cadf5aac501 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 <bobby825 at 126.com>
Date: Thu, 4 Jan 2024 23:16:55 +0800
Subject: [PATCH 07/20] 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 30cfe66703f5a..6101046595c53 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -685,9 +685,11 @@ Bug Fixes in This Version
(`#65568 <https://github.com/llvm/llvm-project/issues/65568>`_)
- Fix an issue where clang doesn't respect detault template arguments that
are added in a later redeclaration for CTAD.
- Fixes (#69987 <https://github.com/llvm/llvm-project/issues/69987>`_)
+ Fixes (`#69987 <https://github.com/llvm/llvm-project/issues/69987>`_)
- Fix an issue where CTAD fails for explicit type conversion.
- Fixes (#64347 <https://github.com/llvm/llvm-project/issues/64347>`_)
+ Fixes (`#64347 <https://github.com/llvm/llvm-project/issues/64347>`_)
+- Fix an issue that the object argument of ``static operator()`` and ``static operator[]`` is not evaluate.
+ Fixes (`#67976 <https://github.com/llvm/llvm-project/issues/67976>`_)
Bug Fixes to Compiler Builtins
>From 6bcc590f206629f58360dc9d01bd88eeb5968ffa Mon Sep 17 00:00:00 2001
From: SuperSodaSea <bobby825 at 126.com>
Date: Fri, 5 Jan 2024 00:10:16 +0800
Subject: [PATCH 08/20] 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 87a15403e6f8b..e8454bdac02f7 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 {{.*}} <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: |-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':'Functor' lvalue Var {{.*}} 'functor' 'Functor':'Functor'
+ // 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':'Functor' lvalue
+ // 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':'Functor' lvalue
+ // 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
>From eb42407a523f9a79afca4fbf221b344330888cc6 Mon Sep 17 00:00:00 2001
From: SuperSodaSea <bobby825 at 126.com>
Date: Fri, 5 Jan 2024 13:17:59 +0800
Subject: [PATCH 09/20] 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 673f8313c2517..1810fdd12bd44 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<CXXDestructorDecl>(Method)) {
+ if (isa<CXXDestructorDecl>(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 0000000000000..4d6f1f76d1315
--- /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 <bobby825 at 126.com>
Date: Fri, 5 Jan 2024 13:22:10 +0800
Subject: [PATCH 10/20] 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 1810fdd12bd44..f9c7cf9b65b35 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<CXXDestructorDecl>(Method) || IsStaticOperator) {
Quals.addConst();
>From c679700fa5041395896dbe06a6f7675bcc4a0ddb Mon Sep 17 00:00:00 2001
From: SuperSodaSea <bobby825 at 126.com>
Date: Sun, 7 Jan 2024 02:40:50 +0800
Subject: [PATCH 11/20] 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 3873f06bde2d3..86aa7033aefdd 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 <https://github.com/llvm/llvm-project/issues/71015>`_)
-- Fix an issue that the object argument of ``static operator()`` and ``static operator[]`` is not evaluate.
- Fixes (`#67976 <https://github.com/llvm/llvm-project/issues/67976>`_)
Bug Fixes to Compiler Builtins
@@ -860,10 +858,14 @@ Bug Fixes to C++ Support
(`#64086 <https://github.com/llvm/llvm-project/issues/64086>`_)
- Fixed a regression where clang forgets how to substitute into constraints on template-template
- parameters. Fixes:
+ parameters. Fixes:
(`#57410 <https://github.com/llvm/llvm-project/issues/57410>`_) and
(`#76604 <https://github.com/llvm/llvm-project/issues/57410>`_)
+- Fix an issue that the object argument of ``static operator()`` and ``static operator[]`` is not evaluate.
+ Fixes (`#67976 <https://github.com/llvm/llvm-project/issues/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 <bobby825 at 126.com>
Date: Fri, 12 Jan 2024 00:48:02 +0800
Subject: [PATCH 12/20] Update clang/docs/ReleaseNotes.rst
Co-authored-by: cor3ntin <corentinjabot at gmail.com>
---
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 86aa7033aefdd..68b8e2603b099 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -862,7 +862,7 @@ Bug Fixes to C++ Support
(`#57410 <https://github.com/llvm/llvm-project/issues/57410>`_) and
(`#76604 <https://github.com/llvm/llvm-project/issues/57410>`_)
-- 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 <https://github.com/llvm/llvm-project/issues/67976>`_)
>From 490fd0f910b1baa9cde08b10a7c0f7fef504421e Mon Sep 17 00:00:00 2001
From: SuperSodaSea <bobby825 at 126.com>
Date: Fri, 12 Jan 2024 00:55:57 +0800
Subject: [PATCH 13/20] 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 a606070c6667b..a5ea4f46035f7 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<CXXDestructorDecl>(Method) || IsStaticOperator) {
+ if (isa<CXXDestructorDecl>(Method) || Method->isStatic()) {
Quals.addConst();
Quals.addVolatile();
}
>From 94195a2aa5477b033d4f02aeb00a9d838e8d2e63 Mon Sep 17 00:00:00 2001
From: SuperSodaSea <bobby825 at 126.com>
Date: Fri, 12 Jan 2024 01:11:38 +0800
Subject: [PATCH 14/20] 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 1ca6ba347b703..14ca2388249df 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 <bobby825 at 126.com>
Date: Fri, 12 Jan 2024 01:34:10 +0800
Subject: [PATCH 15/20] 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 996ddd6944b1c..7317de2163f89 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 <bobby825 at 126.com>
Date: Tue, 30 Jan 2024 22:02:03 +0800
Subject: [PATCH 16/20] Apply suggestion from @AaronBallman
Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
---
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 d0f3789dc496a..5836862a24a89 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<CXXOperatorCallExpr>(E);
- if (OCE) {
+ if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) {
if (OCE->isAssignmentOp())
Order = EvaluationOrder::ForceRightToLeft;
else {
>From c560b388d58e3dec74d42e757555ee998a75012a Mon Sep 17 00:00:00 2001
From: Tianlan Zhou <bobby825 at 126.com>
Date: Tue, 30 Jan 2024 22:28:07 +0800
Subject: [PATCH 17/20] 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 5836862a24a89..00055e55559ae 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<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);
+ arguments = drop_begin(arguments, 1);
+ }
+ EmitCallArgs(Args, dyn_cast<FunctionProtoType>(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 <bobby825 at 126.com>
Date: Tue, 30 Jan 2024 22:38:09 +0800
Subject: [PATCH 18/20] 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 00055e55559ae..4a2f3caad6588 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<FunctionProtoType>(FnType), arguments,
+ EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), Arguments,
E->getDirectCallee(), /*ParamsToSkip=*/0, Order);
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionCall(
>From dea08ecc0d9caf47f7e9bdac113844b8b2bfb68e Mon Sep 17 00:00:00 2001
From: SuperSodaSea <bobby825 at 126.com>
Date: Wed, 31 Jan 2024 03:30:27 +0800
Subject: [PATCH 19/20] Fix clangd test break
---
clang-tools-extra/clangd/InlayHints.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index c7dce041474a1..855621a32a0c0 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -659,8 +659,8 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
// either.
if (const CXXMethodDecl *Method =
dyn_cast_or_null<CXXMethodDecl>(Callee.Decl))
- if (Method->isInstance() &&
- (IsFunctor || Method->hasCXXExplicitFunctionObjectParameter()))
+ if (IsFunctor || (Method->isInstance() &&
+ Method->hasCXXExplicitFunctionObjectParameter()))
Args = Args.drop_front(1);
processCall(Callee, Args);
return true;
>From 910ae406c88efd5cc97894dc1408606094bc0b82 Mon Sep 17 00:00:00 2001
From: Tianlan Zhou <bobby825 at 126.com>
Date: Wed, 31 Jan 2024 13:02:03 +0800
Subject: [PATCH 20/20] Apply suggestion from @zyn0217
---
clang-tools-extra/clangd/InlayHints.cpp | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 855621a32a0c0..671a9c30ffa95 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -651,16 +651,12 @@ class InlayHintVisitor : public RecursiveASTVisitor<InlayHintVisitor> {
// implied object argument ([over.call.func]), the list of provided
// arguments is preceded by the implied object argument for the purposes of
// this correspondence...
- //
- // However, we don't have the implied object argument
- // for static operator() per clang::Sema::BuildCallToObjectOfClassType.
llvm::ArrayRef<const Expr *> Args = {E->getArgs(), E->getNumArgs()};
// We don't have the implied object argument through a function pointer
// either.
if (const CXXMethodDecl *Method =
dyn_cast_or_null<CXXMethodDecl>(Callee.Decl))
- if (IsFunctor || (Method->isInstance() &&
- Method->hasCXXExplicitFunctionObjectParameter()))
+ if (IsFunctor || Method->hasCXXExplicitFunctionObjectParameter())
Args = Args.drop_front(1);
processCall(Callee, Args);
return true;
More information about the flang-commits
mailing list