royjacobson updated this revision to Diff 459413.
royjacobson added a comment.
Fix test after warning text change
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D133659/new/
https://reviews.llvm.org/D133659
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/OperatorKinds.def
clang/include/clang/Sema/DeclSpec.h
clang/include/clang/Sema/Sema.h
clang/lib/Frontend/InitPreprocessor.cpp
clang/lib/Parse/ParseExprCXX.cpp
clang/lib/Sema/SemaChecking.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaLambda.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/TreeTransform.h
clang/test/CXX/over/over.match/over.match.best/over.best.ics/p6.cpp
clang/test/CXX/over/over.oper/p7.cpp
clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp
clang/test/Parser/cxx2b-lambdas-ext-warns.cpp
clang/test/Parser/cxx2b-lambdas.cpp
clang/test/SemaCXX/overloaded-operator-decl.cpp
clang/www/cxx_status.html
Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1481,7 +1481,7 @@
<tr>
<td>static <code>operator()</code></td>
<td><a href="https://wg21.link/P1169R4">P1169R4</a></td>
- <td class="none" align="center">No</td>
+ <td class="unreleased" align="center">Clang 16</td>
</tr>
<tr>
<td>Extended floating-point types and standard names</td>
Index: clang/test/SemaCXX/overloaded-operator-decl.cpp
===================================================================
--- clang/test/SemaCXX/overloaded-operator-decl.cpp
+++ clang/test/SemaCXX/overloaded-operator-decl.cpp
@@ -51,7 +51,7 @@
namespace PR14120 {
struct A {
- static void operator()(int& i) { ++i; } // expected-error{{overloaded 'operator()' cannot be a static member function}}
+ static void operator()(int& i) { ++i; } // expected-error{{overloaded 'operator()' cannot be declared static}}
};
void f() {
int i = 0;
Index: clang/test/Parser/cxx2b-lambdas.cpp
===================================================================
--- clang/test/Parser/cxx2b-lambdas.cpp
+++ clang/test/Parser/cxx2b-lambdas.cpp
@@ -38,3 +38,16 @@
auto XL4 = [] requires true {}; // expected-error{{expected body}}
auto XL5 = []<auto> requires true requires true {}; // expected-error{{expected body}}
auto XL6 = []<auto> requires true noexcept requires true {}; // expected-error{{expected body}}
+
+auto XL7 = []() static static {}; // expected-error {{cannot appear multiple times}}
+auto XL8 = []() static mutable {}; // expected-error {{cannot be both mutable and static}}
+
+auto XL9 = [] static {};
+auto XL10 = []() static {};
+
+void static_captures() {
+ int x;
+ auto SC1 = [&]() static {}; // expected-error {{a static lambda cannot have any captures}}
+ auto SC2 = [&x]() static {}; // expected-error {{a static lambda cannot have any captures}}
+ auto SC3 = [=]() static {}; // expected-error {{a static lambda cannot have any captures}}
+}
Index: clang/test/Parser/cxx2b-lambdas-ext-warns.cpp
===================================================================
--- /dev/null
+++ clang/test/Parser/cxx2b-lambdas-ext-warns.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++20 %s -verify=expected,cxx20
+// RUN: %clang_cc1 -std=c++2b %s -verify=expected,cxx2b
+
+//cxx2b-no-diagnostics
+
+auto L1 = [] constexpr {}; // cxx20-warning {{lambda without a parameter clause is a C++2b extension}}
+auto L2 = []() static {}; // cxx20-error {{static lambdas is a C++2b extension}}
+auto L3 = [] static {}; // cxx20-error {{static lambdas is a C++2b extension}} // cxx20-warning {{lambda without a parameter clause is a C++2b extension}}
Index: clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/cxx2b-static-call-operator.cpp
@@ -0,0 +1,129 @@
+// 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;
+ }
+};
+
+auto GetALambda() {
+ return [](int x, int y) static {
+ return x + y;
+ };
+}
+
+void CallsTheLambda() {
+ GetALambda()(1, 2);
+}
+
+// CHECK: define {{.*}}CallsTheLambda{{.*}}
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %call = call noundef i32 {{.*}}(i32 noundef 1, i32 noundef 2)
+// CHECK-NEXT: ret void
+// CHECK-NEXT: }
+
+void call_static_call_operator() {
+ Functor f;
+ f(101, 102);
+ f.operator()(201, 202);
+ Functor{}(301, 302);
+}
+
+// CHECK: define {{.*}}call_static_call_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: 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;
+ }
+};
+
+constexpr auto my_lambda = []() constexpr {
+ return 3;
+};
+
+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);
+
+ constexpr auto my_lambda = []() constexpr static {
+ return 3;
+ };
+ constexpr int (*f)(void) = my_lambda;
+ constexpr int k = f();
+ static_assert(k == 3);
+}
+
+template <class T>
+struct DepFunctor {
+ static int operator()(T t) {
+ return int(t);
+ }
+};
+
+template<class T>
+auto dep_lambda1() {
+ return [](T t) static -> int {
+ return t;
+ };
+}
+
+auto dep_lambda2() {
+ return [](auto t) static -> int {
+ return t;
+ };
+}
+
+void test_dep_functors() {
+ int x = DepFunctor<float>{}(1.0f);
+ int y = DepFunctor<bool>{}(true);
+
+ int a = dep_lambda1<float>()(1.0f);
+ int b = dep_lambda1<bool>()(true);
+
+ int h = dep_lambda2()(1.0f);
+ int i = dep_lambda2()(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: %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: ret void
+// CHECK-NEXT: }
+
+
+struct __unique {
+ static constexpr auto operator()() { return 4; };
+
+ using P = int();
+ constexpr operator P*() { return operator(); }
+};
+
+__unique four{};
+
+int test_four() {
+ // Checks that overload resolution works.
+ return four();
+}
Index: clang/test/CXX/over/over.oper/p7.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/over/over.oper/p7.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx11
+// RUN: %clang_cc1 -std=c++2b %s -verify=expected,cxx2b
+//cxx2b-no-diagnostics
+
+
+struct Functor {
+ static int operator()(int a, int b); // cxx11-error {{cannot be declared static}}
+};
Index: clang/test/CXX/over/over.match/over.match.best/over.best.ics/p6.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/over/over.match/over.match.best/over.best.ics/p6.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=cxx2b -std=c++2b %s
+// RUN: %clang_cc1 -fsyntax-only -verify=cxx20 -std=c++20 %s
+// cxx2b-no-diagnostics
+
+struct __unique {
+ static constexpr auto operator()() { return 4; }; // cxx20-error {{cannot be declared static}} // cxx20-note {{candidate}}
+
+ using P = int();
+ constexpr operator P*() { return operator(); } // cxx20-note {{conversion candidate}}
+};
+
+__unique four{};
+
+int test_four() {
+ // Checks that overload resolution works.
+ return four(); // cxx20-error {{call to object of type '__unique' is ambiguous}}
+}
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -13120,7 +13120,7 @@
E->getCallOperator()->getEndLoc(),
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
E->getCallOperator()->getConstexprKind(),
- NewTrailingRequiresClause.get());
+ E->getCallOperator()->getStorageClass(), NewTrailingRequiresClause.get());
LSI->CallOperator = NewCallOperator;
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -6999,8 +6999,10 @@
Candidate.Viable = true;
- if (Method->isStatic() || ObjectType.isNull())
- // The implicit object argument is ignored.
+ // The implicit object argument is ignored in <= C++20 for static member
+ // functions. Since C++23 it is used to break ties between static call
+ // operators and implicit conversions to function pointers (See P1169R4).
+ if ((!LangOpts.CPlusPlus2b && Method->isStatic()) || ObjectType.isNull())
Candidate.IgnoreObjectArgument = true;
else {
unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
@@ -9772,7 +9774,7 @@
}
}
- // C++ [over.match.best]p1:
+ // C++ [over.match.best]p1: (Changed in C++2b)
//
// -- if F is a static member function, ICS1(F) is defined such
// that ICS1(F) is neither better nor worse than ICS1(G) for
@@ -14879,15 +14881,18 @@
bool IsError = false;
- // Initialize the implicit object parameter.
- ExprResult ObjRes =
- PerformObjectArgumentInitialization(Object.get(), /*Qualifier=*/nullptr,
- Best->FoundDecl, Method);
- if (ObjRes.isInvalid())
- IsError = true;
- else
- Object = ObjRes;
- MethodArgs.push_back(Object.get());
+ // Initialize the implicit object parameter if needed.
+ // Since C++2b, this could also be a call to a static call operator
+ // which we emit as a regular CallExpr.
+ if (Method->isInstance()) {
+ ExprResult ObjRes = PerformObjectArgumentInitialization(
+ Object.get(), /*Qualifier=*/nullptr, Best->FoundDecl, Method);
+ if (ObjRes.isInvalid())
+ IsError = true;
+ else
+ Object = ObjRes;
+ MethodArgs.push_back(Object.get());
+ }
IsError |= PrepareArgumentsForCallToObjectOfClassType(
*this, MethodArgs, Method, Args, LParenLoc);
@@ -14913,9 +14918,14 @@
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
- CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
- Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, VK, RParenLoc,
- CurFPFeatureOverrides());
+ 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());
if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method))
return true;
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -354,13 +354,11 @@
llvm_unreachable("unexpected context");
}
-CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
- SourceRange IntroducerRange,
- TypeSourceInfo *MethodTypeInfo,
- SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params,
- ConstexprSpecKind ConstexprKind,
- Expr *TrailingRequiresClause) {
+CXXMethodDecl *Sema::startLambdaDefinition(
+ CXXRecordDecl *Class, SourceRange IntroducerRange,
+ TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params, ConstexprSpecKind ConstexprKind,
+ StorageClass SC, Expr *TrailingRequiresClause) {
QualType MethodType = MethodTypeInfo->getType();
TemplateParameterList *TemplateParams =
getGenericLambdaTemplateParameterList(getCurLambda(), *this);
@@ -390,7 +388,7 @@
Context, Class, EndLoc,
DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
MethodNameLoc),
- MethodType, MethodTypeInfo, SC_None, getCurFPFeatures().isFPConstrained(),
+ MethodType, MethodTypeInfo, SC, getCurFPFeatures().isFPConstrained(),
/*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause);
Method->setAccess(AS_public);
if (!TemplateParams)
@@ -917,6 +915,15 @@
bool ContainsUnexpandedParameterPack = false;
SourceLocation EndLoc;
SmallVector<ParmVarDecl *, 8> Params;
+
+ assert(ParamInfo.getDeclSpec().getStorageClassSpec() ==
+ DeclSpec::SCS_unspecified ||
+ ParamInfo.getDeclSpec().getStorageClassSpec() ==
+ DeclSpec::SCS_static &&
+ "Unexpected storage specifier");
+ bool IsLambdaStatic =
+ ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static;
+
if (ParamInfo.getNumTypeObjects() == 0) {
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a lambda-declarator, it is as
@@ -953,7 +960,7 @@
// This function call operator is declared const (9.3.1) if and only if
// the lambda-expression's parameter-declaration-clause is not followed
// by mutable. It is neither virtual nor declared volatile. [...]
- if (!FTI.hasMutableQualifier()) {
+ if (!FTI.hasMutableQualifier() && !IsLambdaStatic) {
FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const,
SourceLocation());
}
@@ -981,6 +988,7 @@
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
ParamInfo.getDeclSpec().getConstexprSpecifier(),
+ IsLambdaStatic ? SC_Static : SC_None,
ParamInfo.getTrailingRequiresClause());
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
@@ -1479,45 +1487,50 @@
Class->addDecl(ConversionTemplate);
} else
Class->addDecl(Conversion);
- // Add a non-static member function that will be the result of
- // the conversion with a certain unique ID.
- DeclarationName InvokerName = &S.Context.Idents.get(
- getLambdaStaticInvokerName());
- // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
- // we should get a prebuilt TrivialTypeSourceInfo from Context
- // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
- // then rewire the parameters accordingly, by hoisting up the InvokeParams
- // loop below and then use its Params to set Invoke->setParams(...) below.
- // This would avoid the 'const' qualifier of the calloperator from
- // contaminating the type of the invoker, which is currently adjusted
- // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the
- // trailing return type of the invoker would require a visitor to rebuild
- // the trailing return type and adjusting all back DeclRefExpr's to refer
- // to the new static invoker parameters - not the call operator's.
- CXXMethodDecl *Invoke = CXXMethodDecl::Create(
- S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
- InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
- S.getCurFPFeatures().isFPConstrained(),
- /*isInline=*/true, ConstexprSpecKind::Unspecified,
- CallOperator->getBody()->getEndLoc());
- for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
- InvokerParams[I]->setOwningFunction(Invoke);
- Invoke->setParams(InvokerParams);
- Invoke->setAccess(AS_private);
- Invoke->setImplicit(true);
- if (Class->isGenericLambda()) {
- FunctionTemplateDecl *TemplateCallOperator =
- CallOperator->getDescribedFunctionTemplate();
- FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create(
- S.Context, Class, Loc, InvokerName,
- TemplateCallOperator->getTemplateParameters(),
- Invoke);
- StaticInvokerTemplate->setAccess(AS_private);
- StaticInvokerTemplate->setImplicit(true);
- Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
- Class->addDecl(StaticInvokerTemplate);
- } else
- Class->addDecl(Invoke);
+
+ // If the lambda is not static, we need to add a static member
+ // function that will be the result of the conversion with a
+ // certain unique ID.
+ // When it is static we just return the static call operator instead.
+ if (CallOperator->isInstance()) {
+ DeclarationName InvokerName =
+ &S.Context.Idents.get(getLambdaStaticInvokerName());
+ // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
+ // we should get a prebuilt TrivialTypeSourceInfo from Context
+ // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
+ // then rewire the parameters accordingly, by hoisting up the InvokeParams
+ // loop below and then use its Params to set Invoke->setParams(...) below.
+ // This would avoid the 'const' qualifier of the calloperator from
+ // contaminating the type of the invoker, which is currently adjusted
+ // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the
+ // trailing return type of the invoker would require a visitor to rebuild
+ // the trailing return type and adjusting all back DeclRefExpr's to refer
+ // to the new static invoker parameters - not the call operator's.
+ CXXMethodDecl *Invoke = CXXMethodDecl::Create(
+ S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
+ InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
+ S.getCurFPFeatures().isFPConstrained(),
+ /*isInline=*/true, ConstexprSpecKind::Unspecified,
+ CallOperator->getBody()->getEndLoc());
+ for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
+ InvokerParams[I]->setOwningFunction(Invoke);
+ Invoke->setParams(InvokerParams);
+ Invoke->setAccess(AS_private);
+ Invoke->setImplicit(true);
+ if (Class->isGenericLambda()) {
+ FunctionTemplateDecl *TemplateCallOperator =
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *StaticInvokerTemplate =
+ FunctionTemplateDecl::Create(
+ S.Context, Class, Loc, InvokerName,
+ TemplateCallOperator->getTemplateParameters(), Invoke);
+ StaticInvokerTemplate->setAccess(AS_private);
+ StaticInvokerTemplate->setImplicit(true);
+ Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
+ Class->addDecl(StaticInvokerTemplate);
+ } else
+ Class->addDecl(Invoke);
+ }
}
/// Add a lambda's conversion to function pointers, as described in
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -15337,7 +15337,7 @@
CXXRecordDecl *Lambda = Conv->getParent();
FunctionDecl *CallOp = Lambda->getLambdaCallOperator();
- FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker(CC);
+ FunctionDecl *Invoker = CallOp->isStatic() ? CallOp : Lambda->getLambdaStaticInvoker(CC);
if (auto *TemplateArgs = Conv->getTemplateSpecializationArgs()) {
CallOp = InstantiateFunctionDeclaration(
@@ -15345,10 +15345,13 @@
if (!CallOp)
return;
- Invoker = InstantiateFunctionDeclaration(
- Invoker->getDescribedFunctionTemplate(), TemplateArgs, CurrentLocation);
- if (!Invoker)
- return;
+ if (CallOp != Invoker) {
+ Invoker = InstantiateFunctionDeclaration(
+ Invoker->getDescribedFunctionTemplate(), TemplateArgs,
+ CurrentLocation);
+ if (!Invoker)
+ return;
+ }
}
if (CallOp->isInvalidDecl())
@@ -15361,17 +15364,19 @@
// to the PendingInstantiations.
MarkFunctionReferenced(CurrentLocation, CallOp);
- // Fill in the __invoke function with a dummy implementation. IR generation
- // will fill in the actual details. Update its type in case it contained
- // an 'auto'.
- Invoker->markUsed(Context);
- Invoker->setReferenced();
- Invoker->setType(Conv->getReturnType()->getPointeeType());
- Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
+ if (Invoker != CallOp) {
+ // Fill in the __invoke function with a dummy implementation. IR generation
+ // will fill in the actual details. Update its type in case it contained
+ // an 'auto'.
+ Invoker->markUsed(Context);
+ Invoker->setReferenced();
+ Invoker->setType(Conv->getReturnType()->getPointeeType());
+ Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
+ }
// Construct the body of the conversion function { return __invoke; }.
- Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(),
- VK_LValue, Conv->getLocation());
+ Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(), VK_LValue,
+ Conv->getLocation());
assert(FunctionRef && "Can't refer to __invoke function?");
Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get();
Conv->setBody(CompoundStmt::Create(Context, Return, FPOptionsOverride(),
@@ -15381,16 +15386,14 @@
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
- L->CompletedImplicitDefinition(Invoker);
+ if (Invoker != CallOp) {
+ L->CompletedImplicitDefinition(Invoker);
+ }
}
}
-
-
void Sema::DefineImplicitLambdaToBlockPointerConversion(
- SourceLocation CurrentLocation,
- CXXConversionDecl *Conv)
-{
+ SourceLocation CurrentLocation, CXXConversionDecl *Conv) {
assert(!Conv->getParent()->isGenericLambda());
SynthesizedFunctionScope Scope(*this, Conv);
@@ -15922,15 +15925,23 @@
if (Op == OO_New || Op == OO_Array_New)
return CheckOperatorNewDeclaration(*this, FnDecl);
- // C++ [over.oper]p6:
- // An operator function shall either be a non-static member
- // function or be a non-member function and have at least one
- // parameter whose type is a class, a reference to a class, an
- // enumeration, or a reference to an enumeration.
+ // C++ [over.oper]p7:
+ // An operator function shall either be a member function or
+ // be a non-member function and have at least one parameter
+ // whose type is a class, a reference to a class, an enumeration,
+ // or a reference to an enumeration.
+ // Note: Before C++23, a member function also has to not be static.
if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(FnDecl)) {
- if (MethodDecl->isStatic())
- return Diag(FnDecl->getLocation(),
- diag::err_operator_overload_static) << FnDecl->getDeclName();
+ if (MethodDecl->isStatic()) {
+ if (Op == OO_Call)
+ Diag(FnDecl->getLocation(),
+ (LangOpts.CPlusPlus2b ? diag::ext_operator_overload_static
+ : diag::err_call_operator_overload_static))
+ << FnDecl->getDeclName();
+ else
+ return Diag(FnDecl->getLocation(), diag::err_operator_overload_static)
+ << FnDecl->getDeclName();
+ }
} else {
bool ClassOrEnumParam = false;
for (auto *Param : FnDecl->parameters()) {
@@ -16029,7 +16040,7 @@
<< FnDecl->getDeclName();
}
- // Some operators must be non-static member functions.
+ // Some operators must be member functions.
if (MustBeMemberOperator && !isa<CXXMethodDecl>(FnDecl)) {
return Diag(FnDecl->getLocation(),
diag::err_operator_overload_must_be_member)
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -5836,14 +5836,14 @@
unsigned NumArgs = TheCall->getNumArgs();
Expr *ImplicitThis = nullptr;
- if (IsMemberOperatorCall) {
- // If this is a call to a member operator, hide the first argument
+ if (IsMemberOperatorCall && !FDecl->isStatic()) {
+ // If this is a call to a non-static member operator, hide the first argument
// from checkCall.
// FIXME: Our choice of AST representation here is less than ideal.
ImplicitThis = Args[0];
++Args;
--NumArgs;
- } else if (IsMemberFunction)
+ } else if (IsMemberFunction && !FDecl->isStatic())
ImplicitThis =
cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument();
Index: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -1158,51 +1158,66 @@
static void tryConsumeLambdaSpecifierToken(Parser &P,
SourceLocation &MutableLoc,
+ SourceLocation &StaticLoc,
SourceLocation &ConstexprLoc,
SourceLocation &ConstevalLoc,
SourceLocation &DeclEndLoc) {
assert(MutableLoc.isInvalid());
+ assert(StaticLoc.isInvalid());
assert(ConstexprLoc.isInvalid());
+ assert(ConstevalLoc.isInvalid());
// Consume constexpr-opt mutable-opt in any sequence, and set the DeclEndLoc
// to the final of those locations. Emit an error if we have multiple
// copies of those keywords and recover.
+ auto ConsumeLocation = [&P, &DeclEndLoc](SourceLocation &SpecifierLoc,
+ int diag_index) {
+ if (SpecifierLoc.isValid()) {
+ P.Diag(P.getCurToken().getLocation(),
+ diag::err_lambda_decl_specifier_repeated)
+ << diag_index
+ << FixItHint::CreateRemoval(P.getCurToken().getLocation());
+ }
+ SpecifierLoc = P.ConsumeToken();
+ DeclEndLoc = SpecifierLoc;
+ };
+
while (true) {
switch (P.getCurToken().getKind()) {
- case tok::kw_mutable: {
- if (MutableLoc.isValid()) {
- P.Diag(P.getCurToken().getLocation(),
- diag::err_lambda_decl_specifier_repeated)
- << 0 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
- }
- MutableLoc = P.ConsumeToken();
- DeclEndLoc = MutableLoc;
- break /*switch*/;
- }
+ case tok::kw_mutable:
+ ConsumeLocation(MutableLoc, 0);
+ break;
+ case tok::kw_static:
+ ConsumeLocation(StaticLoc, 1);
+ break;
case tok::kw_constexpr:
- if (ConstexprLoc.isValid()) {
- P.Diag(P.getCurToken().getLocation(),
- diag::err_lambda_decl_specifier_repeated)
- << 1 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
- }
- ConstexprLoc = P.ConsumeToken();
- DeclEndLoc = ConstexprLoc;
- break /*switch*/;
+ ConsumeLocation(ConstexprLoc, 2);
+ break;
case tok::kw_consteval:
- if (ConstevalLoc.isValid()) {
- P.Diag(P.getCurToken().getLocation(),
- diag::err_lambda_decl_specifier_repeated)
- << 2 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
- }
- ConstevalLoc = P.ConsumeToken();
- DeclEndLoc = ConstevalLoc;
- break /*switch*/;
+ ConsumeLocation(ConstevalLoc, 3);
+ break;
default:
return;
}
}
}
+static void addStaticToLambdaDeclSpecifier(Parser &P, SourceLocation StaticLoc,
+ DeclSpec &DS) {
+ if (StaticLoc.isValid()) {
+ P.Diag(StaticLoc, !P.getLangOpts().CPlusPlus2b
+ ? diag::err_static_lambda
+ : diag::warn_cxx20_compat_static_lambda);
+ const char *PrevSpec = nullptr;
+ unsigned DiagID = 0;
+ DS.SetStorageClassSpec(P.getActions(), DeclSpec::SCS_static, StaticLoc,
+ PrevSpec, DiagID,
+ P.getActions().getASTContext().getPrintingPolicy());
+ assert(PrevSpec == nullptr && DiagID == 0 &&
+ "Static cannot have been set previously!");
+ }
+}
+
static void
addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc,
DeclSpec &DS) {
@@ -1233,6 +1248,23 @@
}
}
+static void DiagnoseStaticSpecifierRestrictions(Parser &P,
+ SourceLocation StaticLoc,
+ SourceLocation MutableLoc,
+ const LambdaIntroducer &Intro) {
+ if (StaticLoc.isInvalid())
+ return;
+
+ // [expr.prim.lambda.general] p4
+ // The lambda-specifier-seq shall not contain both mutable and static.
+ // If the lambda-specifier-seq contains static, there shall be no
+ // lambda-capture.
+ if (MutableLoc.isValid())
+ P.Diag(StaticLoc, diag::err_static_mutable_lambda);
+ if (Intro.hasLambdaCapture())
+ P.Diag(StaticLoc, diag::err_static_lambda_captures);
+}
+
/// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda
/// expression.
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
@@ -1332,14 +1364,18 @@
// the mutable specifier to be compatible with MSVC.
MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr);
- // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update
- // the DeclEndLoc.
+ // Parse lambda specifiers and update the DeclEndLoc.
SourceLocation MutableLoc;
+ SourceLocation StaticLoc;
SourceLocation ConstexprLoc;
SourceLocation ConstevalLoc;
- tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
- ConstevalLoc, DeclEndLoc);
+ tryConsumeLambdaSpecifierToken(*this, MutableLoc, StaticLoc,
+ ConstexprLoc, ConstevalLoc, DeclEndLoc);
+
+ DiagnoseStaticSpecifierRestrictions(*this, StaticLoc, MutableLoc,
+ Intro);
+ addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS);
addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
// Parse exception-specification[opt].
@@ -1435,7 +1471,7 @@
if (Tok.is(tok::kw_requires))
ParseTrailingRequiresClause(D);
} else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
- tok::kw_constexpr, tok::kw_consteval,
+ tok::kw_constexpr, tok::kw_consteval, tok::kw_static,
tok::kw___private, tok::kw___global, tok::kw___local,
tok::kw___constant, tok::kw___generic,
tok::kw_requires, tok::kw_noexcept) ||
Index: clang/lib/Frontend/InitPreprocessor.cpp
===================================================================
--- clang/lib/Frontend/InitPreprocessor.cpp
+++ clang/lib/Frontend/InitPreprocessor.cpp
@@ -695,6 +695,7 @@
Builder.defineMacro("__cpp_size_t_suffix", "202011L");
Builder.defineMacro("__cpp_if_consteval", "202106L");
Builder.defineMacro("__cpp_multidimensional_subscript", "202110L");
+ Builder.defineMacro("__cpp_static_call_operator", "202207L");
}
if (LangOpts.Char8)
Builder.defineMacro("__cpp_char8_t", "201811L");
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -6966,13 +6966,12 @@
LambdaCaptureDefault CaptureDefault);
/// Start the definition of a lambda expression.
- CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,
- SourceRange IntroducerRange,
- TypeSourceInfo *MethodType,
- SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params,
- ConstexprSpecKind ConstexprKind,
- Expr *TrailingRequiresClause);
+ CXXMethodDecl *
+ startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange,
+ TypeSourceInfo *MethodType, SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params,
+ ConstexprSpecKind ConstexprKind, StorageClass SC,
+ Expr *TrailingRequiresClause);
/// Number lambda for linkage purposes if necessary.
void handleLambdaNumbering(
Index: clang/include/clang/Sema/DeclSpec.h
===================================================================
--- clang/include/clang/Sema/DeclSpec.h
+++ clang/include/clang/Sema/DeclSpec.h
@@ -2748,6 +2748,10 @@
LambdaIntroducer()
: Default(LCD_None) {}
+ bool hasLambdaCapture() const {
+ return Captures.size() > 0 || Default != LCD_None;
+ }
+
/// Append a capture in a lambda introducer.
void addCapture(LambdaCaptureKind Kind,
SourceLocation Loc,
Index: clang/include/clang/Basic/OperatorKinds.def
===================================================================
--- clang/include/clang/Basic/OperatorKinds.def
+++ clang/include/clang/Basic/OperatorKinds.def
@@ -38,8 +38,8 @@
/// "operator*") can be both unary and binary.
///
/// MemberOnly: True if this operator can only be declared as a
-/// non-static member function. False if the operator can be both a
-/// non-member function and a non-static member function.
+/// member function. False if the operator can be both a
+/// non-member function and a member function.
///
/// OVERLOADED_OPERATOR_MULTI is used to enumerate the multi-token
/// overloaded operator names, e.g., "operator delete []". The macro
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9071,6 +9071,10 @@
"or enumeration type">;
def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">;
+def ext_operator_overload_static : ExtWarn<
+ "making static overloaded %0 is a C++2b extension">, InGroup<CXXPre2bCompat>, DefaultIgnore;
+def err_call_operator_overload_static : Error<
+ "overloaded %0 cannot be declared static before C++2b">;
def err_operator_overload_static : Error<
"overloaded %0 cannot be a static member function">;
def err_operator_overload_default_arg : Error<
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -988,7 +988,8 @@
"lambda expressions are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_lambda_decl_specifier_repeated : Error<
- "%select{'mutable'|'constexpr'|'consteval'}0 cannot appear multiple times in a lambda declarator">;
+ "%select{'mutable'|'static'|'constexpr'|'consteval'}0 cannot "
+ "appear multiple times in a lambda declarator">;
def err_lambda_capture_misplaced_ellipsis : Error<
"ellipsis in pack %select{|init-}0capture must appear %select{after|before}0 "
"the name of the capture">;
@@ -1027,6 +1028,17 @@
def err_lambda_template_parameter_list_empty : Error<
"lambda template parameter list cannot be empty">;
+// C++2b static lambdas
+def err_static_lambda: Error<
+ "static lambdas is a C++2b extension">;
+def warn_cxx20_compat_static_lambda: Warning<
+ "static lambdas are incompatible with C++ standards before C++2b">,
+ InGroup<CXXPre2bCompat>, DefaultIgnore;
+def err_static_mutable_lambda : Error<
+ "lambda cannot be both mutable and static">;
+def err_static_lambda_captures : Error<
+ "a static lambda cannot have any captures">;
+
// Availability attribute
def err_expected_version : Error<
"expected a version of the form 'major[.minor[.subminor]]'">;
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -249,6 +249,8 @@
C++2b Feature Support
^^^^^^^^^^^^^^^^^^^^^
+- Implemented `P1169R4: static operator() <https://wg21.link/P1169R4>`_.
+
CUDA/HIP Language Changes in Clang
----------------------------------
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits