Skip to content

Commit 3faf1f1

Browse files
committed
[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
1 parent be4b494 commit 3faf1f1

File tree

10 files changed

+106
-20
lines changed

10 files changed

+106
-20
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ C++2b Feature Support
661661
^^^^^^^^^^^^^^^^^^^^^
662662

663663
- Support label at end of compound statement (`P2324 <https://wg21.link/p2324r2>`_).
664-
- Implemented `P1169R4: static operator() <https://wg21.link/P1169R4>`_.
664+
- Implemented `P1169R4: static operator() <https://wg21.link/P1169R4>`_ and `P2589R1: static operator[] <https://wg21.link/P2589R1>`_.
665665
- Implemented "char8_t Compatibility and Portability Fix" (`P2513R3 <https://wg21.link/P2513R3>`_).
666666
This change was applied to C++20 as a Defect Report.
667667
- Implemented "Permitting static constexpr variables in constexpr functions" (`P2647R1 <https://wg21.link/P2647R1>_`).

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9110,10 +9110,10 @@ def err_operator_overload_needs_class_or_enum : Error<
91109110
"or enumeration type">;
91119111

91129112
def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">;
9113+
def warn_cxx20_compat_operator_overload_static : Warning<
9114+
"declaring overloaded %0 as 'static' is incompatible with C++ standards "
9115+
"before C++2b">, InGroup<CXXPre2bCompat>, DefaultIgnore;
91139116
def ext_operator_overload_static : ExtWarn<
9114-
"declaring overloaded %0 as 'static' is a C++2b extension">,
9115-
InGroup<CXXPre2bCompat>, DefaultIgnore;
9116-
def err_call_operator_overload_static : ExtWarn<
91179117
"declaring overloaded %0 as 'static' is a C++2b extension">, InGroup<CXX2b>;
91189118
def err_operator_overload_static : Error<
91199119
"overloaded %0 cannot be a static member function">;

clang/lib/Frontend/InitPreprocessor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
695695
Builder.defineMacro("__cpp_implicit_move", "202011L");
696696
Builder.defineMacro("__cpp_size_t_suffix", "202011L");
697697
Builder.defineMacro("__cpp_if_consteval", "202106L");
698-
Builder.defineMacro("__cpp_multidimensional_subscript", "202110L");
698+
Builder.defineMacro("__cpp_multidimensional_subscript", "202211L");
699699
}
700700

701701
// We provide those C++2b features as extensions in earlier language modes, so

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16015,10 +16015,11 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
1601516015
// function allowed to be static is the call operator function.
1601616016
if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(FnDecl)) {
1601716017
if (MethodDecl->isStatic()) {
16018-
if (Op == OO_Call)
16018+
if (Op == OO_Call || Op == OO_Subscript)
1601916019
Diag(FnDecl->getLocation(),
16020-
(LangOpts.CPlusPlus2b ? diag::ext_operator_overload_static
16021-
: diag::err_call_operator_overload_static))
16020+
(LangOpts.CPlusPlus2b
16021+
? diag::warn_cxx20_compat_operator_overload_static
16022+
: diag::ext_operator_overload_static))
1602216023
<< FnDecl;
1602316024
else
1602416025
return Diag(FnDecl->getLocation(), diag::err_operator_overload_static)

clang/lib/Sema/SemaOverload.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14425,12 +14425,17 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
1442514425
// Convert the arguments.
1442614426
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
1442714427
SmallVector<Expr *, 2> MethodArgs;
14428-
ExprResult Arg0 = PerformObjectArgumentInitialization(
14429-
Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method);
14430-
if (Arg0.isInvalid())
14431-
return ExprError();
1443214428

14433-
MethodArgs.push_back(Arg0.get());
14429+
// Handle 'this' parameter if the selected function is not static.
14430+
if (Method->isInstance()) {
14431+
ExprResult Arg0 = PerformObjectArgumentInitialization(
14432+
Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method);
14433+
if (Arg0.isInvalid())
14434+
return ExprError();
14435+
14436+
MethodArgs.push_back(Arg0.get());
14437+
}
14438+
1443414439
bool IsError = PrepareArgumentsForCallToObjectOfClassType(
1443514440
*this, MethodArgs, Method, ArgExpr, LLoc);
1443614441
if (IsError)
@@ -14450,9 +14455,16 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
1445014455
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
1445114456
ResultTy = ResultTy.getNonLValueExprType(Context);
1445214457

14453-
CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
14454-
Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, RLoc,
14455-
CurFPFeatureOverrides());
14458+
CallExpr *TheCall;
14459+
if (Method->isInstance())
14460+
TheCall = CXXOperatorCallExpr::Create(
14461+
Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK,
14462+
RLoc, CurFPFeatureOverrides());
14463+
else
14464+
TheCall =
14465+
CallExpr::Create(Context, FnExpr.get(), MethodArgs, ResultTy, VK,
14466+
RLoc, CurFPFeatureOverrides());
14467+
1445614468
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
1445714469
return ExprError();
1445814470

clang/test/CXX/over/over.oper/p7.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@
55

66
struct Functor {
77
static int operator()(int a, int b);
8-
// cxx11-warning@-1 {{is a C++2b extension}}
9-
// precxx2b-warning@-2 {{declaring overloaded 'operator()' as 'static' is a C++2b extension}}
8+
static int operator[](int a1);
9+
// cxx11-warning@-2 {{declaring overloaded 'operator()' as 'static' is a C++2b extension}}
10+
// cxx11-warning@-2 {{declaring overloaded 'operator[]' as 'static' is a C++2b extension}}
11+
// precxx2b-warning@-4 {{incompatible with C++ standards before C++2b}}
12+
// precxx2b-warning@-4 {{incompatible with C++ standards before C++2b}}
1013
};
1114

1215
struct InvalidParsing1 {
1316
extern int operator()(int a, int b); // expected-error {{storage class specified}}
17+
extern int operator[](int a1); // expected-error {{storage class specified}}
1418
};
1519

1620
struct InvalidParsing2 {
1721
extern static int operator()(int a, int b); // expected-error {{storage class specified}} // expected-error {{cannot combine with previous 'extern' declaration specifier}}
22+
extern static int operator[](int a); // expected-error {{storage class specified}} // expected-error {{cannot combine with previous 'extern' declaration specifier}}
1823
};

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ void call_static_call_operator() {
2828
f(101, 102);
2929
f.operator()(201, 202);
3030
Functor{}(301, 302);
31+
Functor::operator()(401, 402);
3132
}
3233

3334
// CHECK: define {{.*}}call_static_call_operator{{.*}}
3435
// CHECK-NEXT: entry:
3536
// CHECK: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 101, i32 noundef 102)
3637
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 201, i32 noundef 202)
3738
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 301, i32 noundef 302)
39+
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 401, i32 noundef 402)
3840
// CHECK-NEXT: ret void
3941
// CHECK-NEXT: }
4042

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: %clang_cc1 -std=c++2b %s -emit-llvm -triple x86_64-linux -o - | FileCheck %s
2+
// RUN: %clang_cc1 -std=c++2b %s -emit-llvm -triple x86_64-windows-msvc -o - | FileCheck %s
3+
4+
struct Functor {
5+
static int operator[](int x, int y) {
6+
return x + y;
7+
}
8+
};
9+
10+
void call_static_subscript_operator() {
11+
Functor f;
12+
f[101, 102];
13+
f.operator[](201, 202);
14+
Functor{}[301, 302];
15+
Functor::operator[](401, 402);
16+
}
17+
18+
// CHECK: define {{.*}}call_static_subscript_operator{{.*}}
19+
// CHECK-NEXT: entry:
20+
// CHECK: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 101, i32 noundef 102)
21+
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 201, i32 noundef 202)
22+
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 301, i32 noundef 302)
23+
// CHECK-NEXT: {{.*}} = call noundef i32 {{.*}}Functor{{.*}}(i32 noundef 401, i32 noundef 402)
24+
// CHECK-NEXT: ret void
25+
// CHECK-NEXT: }
26+
27+
struct FunctorConsteval {
28+
consteval static int operator[](int x, int y) {
29+
return x + y;
30+
}
31+
};
32+
33+
struct FunctorConstexpr {
34+
constexpr static int operator[](int x, int y) {
35+
return x + y;
36+
}
37+
};
38+
39+
void test_consteval_constexpr() {
40+
int x = 0;
41+
int y = FunctorConstexpr{}[x, 2];
42+
constexpr int z1 = FunctorConsteval{}[2, 2];
43+
constexpr int z2 = FunctorConstexpr{}[2, 2];
44+
45+
static_assert(z1 == 4);
46+
static_assert(z2 == 4);
47+
}
48+
49+
template <class T>
50+
struct DepFunctor {
51+
static int operator[](T t) {
52+
return int(t);
53+
}
54+
};
55+
56+
void test_dep_functors() {
57+
int x = DepFunctor<float>{}[1.0f];
58+
int y = DepFunctor<bool>{}[true];
59+
}
60+
61+
// CHECK: define {{.*}}test_dep_functors{{.*}}
62+
// CHECK-NEXT: entry:
63+
// CHECK: %call = call noundef i32 {{.*}}DepFunctor{{.*}}(float noundef 1.000000e+00)
64+
// CHECK: %call1 = call noundef i32 {{.*}}DepFunctor{{.*}}(i1 noundef zeroext true)
65+
// CHECK: ret void
66+
// CHECK-NEXT: }

clang/test/Lexer/cxx-features.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
#error "wrong value for __cpp_if_consteval"
4444
#endif
4545

46-
#if check(multidimensional_subscript, 0, 0, 0, 0, 0, 202110)
46+
#if check(multidimensional_subscript, 0, 0, 0, 0, 0, 202211)
4747
#error "wrong value for __cpp_multidimensional_subscript"
4848
#endif
4949

clang/www/cxx_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1518,7 +1518,7 @@ <h2 id="cxx23">C++2b implementation status</h2>
15181518
<tr>
15191519
<td>static <code>operator[]</code></td>
15201520
<td><a href="https://wg21.link/P2589R1">P2589R1</a></td>
1521-
<td class="none" align="center">No</td>
1521+
<td class="unreleased" align="center">16</td>
15221522
</tr>
15231523
<tr>
15241524
<td>Permitting static constexpr variables in constexpr functions (DR)</td>

0 commit comments

Comments
 (0)