[clang] 3faf1f1 - [Clang] Implement static operator[]
Roy Jacobson via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 29 02:39:59 PST 2022
Author: Roy Jacobson
Date: 2022-11-29T12:39:52+02:00
New Revision: 3faf1f17a5c30a3ff1181898f2d2c7649066323d
URL: https://github.com/llvm/llvm-project/commit/3faf1f17a5c30a3ff1181898f2d2c7649066323d
DIFF: https://github.com/llvm/llvm-project/commit/3faf1f17a5c30a3ff1181898f2d2c7649066323d.diff
LOG: [Clang] Implement static operator[]
After accepted in Kona, update the code to accept static operator[] as well.
No big code changes: accept this operator as static in SemaDeclCXX, update AST call generation in SemaOverload and update feature macros + tests accordingly.
Reviewed By: cor3ntin, erichkeane, #clang-language-wg
Differential Revision: https://reviews.llvm.org/D138387
Added:
clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Frontend/InitPreprocessor.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaOverload.cpp
clang/test/CXX/over/over.oper/p7.cpp
clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp
clang/test/Lexer/cxx-features.cpp
clang/www/cxx_status.html
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 86911bd3b1a1e..ffce71f8c38a2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -661,7 +661,7 @@ C++2b Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Support label at end of compound statement (`P2324 <https://wg21.link/p2324r2>`_).
-- Implemented `P1169R4: static operator() <https://wg21.link/P1169R4>`_.
+- Implemented `P1169R4: static operator() <https://wg21.link/P1169R4>`_ and `P2589R1: static operator[] <https://wg21.link/P2589R1>`_.
- Implemented "char8_t Compatibility and Portability Fix" (`P2513R3 <https://wg21.link/P2513R3>`_).
This change was applied to C++20 as a Defect Report.
- Implemented "Permitting static constexpr variables in constexpr functions" (`P2647R1 <https://wg21.link/P2647R1>_`).
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 71093da21b0d5..84ce58c69848c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9110,10 +9110,10 @@ def err_operator_overload_needs_class_or_enum : Error<
"or enumeration type">;
def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">;
+def warn_cxx20_compat_operator_overload_static : Warning<
+ "declaring overloaded %0 as 'static' is incompatible with C++ standards "
+ "before C++2b">, InGroup<CXXPre2bCompat>, DefaultIgnore;
def ext_operator_overload_static : ExtWarn<
- "declaring overloaded %0 as 'static' is a C++2b extension">,
- InGroup<CXXPre2bCompat>, DefaultIgnore;
-def err_call_operator_overload_static : ExtWarn<
"declaring overloaded %0 as 'static' is a C++2b extension">, InGroup<CXX2b>;
def err_operator_overload_static : Error<
"overloaded %0 cannot be a static member function">;
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 53a5f13e24afe..69480c9469262 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -695,7 +695,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_implicit_move", "202011L");
Builder.defineMacro("__cpp_size_t_suffix", "202011L");
Builder.defineMacro("__cpp_if_consteval", "202106L");
- Builder.defineMacro("__cpp_multidimensional_subscript", "202110L");
+ Builder.defineMacro("__cpp_multidimensional_subscript", "202211L");
}
// We provide those C++2b features as extensions in earlier language modes, so
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 174fe43a2cd51..194298ab5f7bf 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -16015,10 +16015,11 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// function allowed to be static is the call operator function.
if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(FnDecl)) {
if (MethodDecl->isStatic()) {
- if (Op == OO_Call)
+ if (Op == OO_Call || Op == OO_Subscript)
Diag(FnDecl->getLocation(),
- (LangOpts.CPlusPlus2b ? diag::ext_operator_overload_static
- : diag::err_call_operator_overload_static))
+ (LangOpts.CPlusPlus2b
+ ? diag::warn_cxx20_compat_operator_overload_static
+ : diag::ext_operator_overload_static))
<< FnDecl;
else
return Diag(FnDecl->getLocation(), diag::err_operator_overload_static)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index f2c897dbe882f..a20d7dda79300 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -14425,12 +14425,17 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
SmallVector<Expr *, 2> MethodArgs;
- ExprResult Arg0 = PerformObjectArgumentInitialization(
- Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method);
- if (Arg0.isInvalid())
- return ExprError();
- MethodArgs.push_back(Arg0.get());
+ // Handle 'this' parameter if the selected function is not static.
+ if (Method->isInstance()) {
+ ExprResult Arg0 = PerformObjectArgumentInitialization(
+ Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method);
+ if (Arg0.isInvalid())
+ return ExprError();
+
+ MethodArgs.push_back(Arg0.get());
+ }
+
bool IsError = PrepareArgumentsForCallToObjectOfClassType(
*this, MethodArgs, Method, ArgExpr, LLoc);
if (IsError)
@@ -14450,9 +14455,16 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
- CXXOperatorCallExpr *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();
diff --git a/clang/test/CXX/over/over.oper/p7.cpp b/clang/test/CXX/over/over.oper/p7.cpp
index c7a169de26cd2..7d304762c57f8 100644
--- a/clang/test/CXX/over/over.oper/p7.cpp
+++ b/clang/test/CXX/over/over.oper/p7.cpp
@@ -5,14 +5,19 @@
struct Functor {
static int operator()(int a, int b);
- // cxx11-warning at -1 {{is a C++2b extension}}
- // precxx2b-warning at -2 {{declaring overloaded 'operator()' as 'static' is a C++2b extension}}
+ static int operator[](int a1);
+ // cxx11-warning at -2 {{declaring overloaded 'operator()' as 'static' is a C++2b extension}}
+ // cxx11-warning at -2 {{declaring overloaded 'operator[]' as 'static' is a C++2b extension}}
+ // precxx2b-warning at -4 {{incompatible with C++ standards before C++2b}}
+ // precxx2b-warning at -4 {{incompatible with C++ standards before C++2b}}
};
struct InvalidParsing1 {
extern int operator()(int a, int b); // expected-error {{storage class specified}}
+ extern int operator[](int a1); // expected-error {{storage class specified}}
};
struct InvalidParsing2 {
extern static int operator()(int a, int b); // expected-error {{storage class specified}} // expected-error {{cannot combine with previous 'extern' declaration specifier}}
+ extern static int operator[](int a); // expected-error {{storage class specified}} // expected-error {{cannot combine with previous 'extern' declaration specifier}}
};
diff --git a/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp b/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp
index e85974d911f7c..1d0b05ba10aa3 100644
--- a/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp
+++ b/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp
@@ -28,6 +28,7 @@ void call_static_call_operator() {
f(101, 102);
f.operator()(201, 202);
Functor{}(301, 302);
+ Functor::operator()(401, 402);
}
// CHECK: define {{.*}}call_static_call_operator{{.*}}
@@ -35,6 +36,7 @@ void call_static_call_operator() {
// CHECK: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 101, i32 noundef 102)
// 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-NEXT: ret void
// CHECK-NEXT: }
diff --git a/clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp b/clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp
new file mode 100644
index 0000000000000..3d8957698f5a7
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx2b-static-subscript-operator.cpp
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -std=c++2b %s -emit-llvm -triple x86_64-linux -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++2b %s -emit-llvm -triple x86_64-windows-msvc -o - | FileCheck %s
+
+struct Functor {
+ static int operator[](int x, int y) {
+ return x + y;
+ }
+};
+
+void call_static_subscript_operator() {
+ Functor f;
+ f[101, 102];
+ f.operator[](201, 202);
+ Functor{}[301, 302];
+ Functor::operator[](401, 402);
+}
+
+// CHECK: define {{.*}}call_static_subscript_operator{{.*}}
+// CHECK-NEXT: entry:
+// CHECK: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 101, i32 noundef 102)
+// 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-NEXT: ret void
+// CHECK-NEXT: }
+
+struct FunctorConsteval {
+ consteval static int operator[](int x, int y) {
+ return x + y;
+ }
+};
+
+struct FunctorConstexpr {
+ constexpr static int operator[](int x, int y) {
+ return x + y;
+ }
+};
+
+void test_consteval_constexpr() {
+ int x = 0;
+ int y = FunctorConstexpr{}[x, 2];
+ constexpr int z1 = FunctorConsteval{}[2, 2];
+ constexpr int z2 = FunctorConstexpr{}[2, 2];
+
+ static_assert(z1 == 4);
+ static_assert(z2 == 4);
+}
+
+template <class T>
+struct DepFunctor {
+ static int operator[](T t) {
+ return int(t);
+ }
+};
+
+void test_dep_functors() {
+ int x = DepFunctor<float>{}[1.0f];
+ int y = DepFunctor<bool>{}[true];
+}
+
+// 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: ret void
+// CHECK-NEXT: }
diff --git a/clang/test/Lexer/cxx-features.cpp b/clang/test/Lexer/cxx-features.cpp
index e577801560292..67b5265d7daf0 100644
--- a/clang/test/Lexer/cxx-features.cpp
+++ b/clang/test/Lexer/cxx-features.cpp
@@ -43,7 +43,7 @@
#error "wrong value for __cpp_if_consteval"
#endif
-#if check(multidimensional_subscript, 0, 0, 0, 0, 0, 202110)
+#if check(multidimensional_subscript, 0, 0, 0, 0, 0, 202211)
#error "wrong value for __cpp_multidimensional_subscript"
#endif
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index e296d5d3c597c..9559c562bdec0 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1518,7 +1518,7 @@ <h2 id="cxx23">C++2b implementation status</h2>
<tr>
<td>static <code>operator[]</code></td>
<td><a href="https://wg21.link/P2589R1">P2589R1</a></td>
- <td class="none" align="center">No</td>
+ <td class="unreleased" align="center">16</td>
</tr>
<tr>
<td>Permitting static constexpr variables in constexpr functions (DR)</td>
More information about the cfe-commits
mailing list