diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -661,7 +661,7 @@ ^^^^^^^^^^^^^^^^^^^^^ - Support label at end of compound statement (`P2324 `_). -- Implemented `P1169R4: static operator() `_. +- Implemented `P1169R4: static operator() `_ and `P2589R1: static operator[] `_. - Implemented "char8_t Compatibility and Portability Fix" (`P2513R3 `_). This change was applied to C++20 as a Defect Report. - Implemented "Permitting static constexpr variables in constexpr functions" (`P2647R1 _`). diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9110,10 +9110,10 @@ "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, DefaultIgnore; def ext_operator_overload_static : ExtWarn< - "declaring overloaded %0 as 'static' is a C++2b extension">, - InGroup, DefaultIgnore; -def err_call_operator_overload_static : ExtWarn< "declaring overloaded %0 as 'static' is a C++2b extension">, InGroup; 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 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -695,7 +695,7 @@ 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 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -16015,10 +16015,11 @@ // function allowed to be static is the call operator function. if (CXXMethodDecl *MethodDecl = dyn_cast(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 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -14425,12 +14425,17 @@ // Convert the arguments. CXXMethodDecl *Method = cast(FnDecl); SmallVector 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 @@ 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 --- 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@-1 {{is a C++2b extension}} - // precxx2b-warning@-2 {{declaring overloaded 'operator()' as 'static' is a C++2b extension}} + static int operator[](int a1); + // cxx11-warning@-2 {{declaring overloaded 'operator()' as 'static' is a C++2b extension}} + // cxx11-warning@-2 {{declaring overloaded 'operator[]' as 'static' is a C++2b extension}} + // precxx2b-warning@-4 {{incompatible with C++ standards before C++2b}} + // precxx2b-warning@-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 --- a/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp +++ b/clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp @@ -28,6 +28,7 @@ f(101, 102); f.operator()(201, 202); Functor{}(301, 302); + Functor::operator()(401, 402); } // CHECK: define {{.*}}call_static_call_operator{{.*}} @@ -35,6 +36,7 @@ // 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 --- /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 +struct DepFunctor { + static int operator[](T t) { + return int(t); + } +}; + +void test_dep_functors() { + int x = DepFunctor{}[1.0f]; + int y = DepFunctor{}[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 --- 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 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -1518,7 +1518,7 @@ static operator[] P2589R1 - No + 16 Permitting static constexpr variables in constexpr functions (DR)