--- gcc/cp/cp-tree.h.jj	2022-09-13 18:57:29.356969560 +0200
+++ gcc/cp/cp-tree.h	2022-09-19 11:53:19.780594924 +0200
@@ -504,6 +504,7 @@ extern GTY(()) tree cp_global_trees[CPTI
       OVL_NESTED_P (in OVERLOAD)
       DECL_MODULE_EXPORT_P (in _DECL)
       PACK_EXPANSION_FORCE_EXTRA_ARGS_P (in *_PACK_EXPANSION)
+      LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR)
    4: IDENTIFIER_MARKED (IDENTIFIER_NODEs)
       TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
 	  CALL_EXPR, or FIELD_DECL).
@@ -1488,6 +1489,10 @@ enum cp_lambda_default_capture_mode_type
 #define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \
   TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE))
 
+/* Predicate tracking whether the lambda was declared 'static'.  */
+#define LAMBDA_EXPR_STATIC_P(NODE) \
+  TREE_LANG_FLAG_3 (LAMBDA_EXPR_CHECK (NODE))
+
 /* True if this TREE_LIST in LAMBDA_EXPR_CAPTURE_LIST is for an explicit
    capture.  */
 #define LAMBDA_CAPTURE_EXPLICIT_P(NODE) \
--- gcc/cp/parser.cc.jj	2022-09-19 11:52:53.140960839 +0200
+++ gcc/cp/parser.cc	2022-09-19 12:11:15.891823798 +0200
@@ -1994,7 +1994,7 @@ enum
      constexpr.  */
   CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8,
   /* When parsing a decl-specifier-seq, only allow mutable, constexpr or
-     for C++20 consteval.  */
+     for C++20 consteval or for C++23 static.  */
   CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10,
   /* When parsing a decl-specifier-seq, allow missing typename.  */
   CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20,
@@ -11719,6 +11719,18 @@ cp_parser_lambda_declarator_opt (cp_pars
       LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1;
       quals = TYPE_UNQUALIFIED;
     }
+  else if (lambda_specs.storage_class == sc_static)
+    {
+      if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) != CPLD_NONE
+	  || LAMBDA_EXPR_CAPTURE_LIST (lambda_expr))
+	error_at (lambda_specs.locations[ds_storage_class],
+		  "%<static%> lambda specifier with lambda capture");
+      else
+	{
+	  LAMBDA_EXPR_STATIC_P (lambda_expr) = 1;
+	  quals = TYPE_UNQUALIFIED;
+	}
+    }
 
   tx_qual = cp_parser_tx_qualifier_opt (parser);
   if (omitted_parms_loc && tx_qual)
@@ -11804,6 +11816,12 @@ cp_parser_lambda_declarator_opt (cp_pars
     if (lambda_specs.locations[ds_consteval])
       return_type_specs.locations[ds_consteval]
 	= lambda_specs.locations[ds_consteval];
+    if (LAMBDA_EXPR_STATIC_P (lambda_expr))
+      {
+	return_type_specs.storage_class = sc_static;
+	return_type_specs.locations[ds_storage_class]
+	  = lambda_specs.locations[ds_storage_class];
+      }
 
     p = obstack_alloc (&declarator_obstack, 0);
 
@@ -11827,8 +11845,9 @@ cp_parser_lambda_declarator_opt (cp_pars
       {
 	DECL_INITIALIZED_IN_CLASS_P (fco) = 1;
 	DECL_ARTIFICIAL (fco) = 1;
-	/* Give the object parameter a different name.  */
-	DECL_NAME (DECL_ARGUMENTS (fco)) = closure_identifier;
+	if (!LAMBDA_EXPR_STATIC_P (lambda_expr))
+	  /* Give the object parameter a different name.  */
+	  DECL_NAME (DECL_ARGUMENTS (fco)) = closure_identifier;
 	DECL_SET_LAMBDA_FUNCTION (fco, true);
       }
     if (template_param_list)
@@ -16022,8 +16041,15 @@ cp_parser_decl_specifier_seq (cp_parser*
 	  && token->keyword != RID_MUTABLE
 	  && token->keyword != RID_CONSTEXPR
 	  && token->keyword != RID_CONSTEVAL)
-	error_at (token->location, "%qD invalid in lambda",
-		  ridpointers[token->keyword]);
+	{
+	  if (token->keyword != RID_STATIC)
+	    error_at (token->location, "%qD invalid in lambda",
+		      ridpointers[token->keyword]);
+	  else if (cxx_dialect < cxx23)
+	    pedwarn (token->location, OPT_Wc__23_extensions,
+		     "%qD only valid in lambda with %<-std=c++23%> or "
+		     "%<-std=gnu++23%>", ridpointers[token->keyword]);
+	}
 
       if (ds != ds_last)
 	set_and_check_decl_spec_loc (decl_specs, ds, token);
--- gcc/cp/decl.cc.jj	2022-09-19 11:52:53.169960441 +0200
+++ gcc/cp/decl.cc	2022-09-19 11:53:19.818594402 +0200
@@ -15294,8 +15294,25 @@ grok_op_properties (tree decl, bool comp
      an enumeration, or a reference to an enumeration.  13.4.0.6 */
   if (! methodp || DECL_STATIC_FUNCTION_P (decl))
     {
+      if (operator_code == CALL_EXPR)
+	{
+	  if (! DECL_STATIC_FUNCTION_P (decl))
+	    {
+	      error_at (loc, "%qD must be a member function", decl);
+	      return false;
+	    }
+	  if (cxx_dialect < cxx23
+	      /* For lambdas we diagnose static lambda specifier elsewhere.  */
+	      && ! LAMBDA_FUNCTION_P (decl)
+	      /* For instantiations, we have diagnosed this already.  */
+	      && ! DECL_USE_TEMPLATE (decl))
+	    pedwarn (loc, OPT_Wc__23_extensions, "%qD may be a static member "
+	      "function only with %<-std=c++23%> or %<-std=gnu++23%>", decl);
+	  /* There are no further restrictions on the arguments to an
+	     overloaded "operator ()".  */
+	  return true;
+	}
       if (operator_code == TYPE_EXPR
-	  || operator_code == CALL_EXPR
 	  || operator_code == COMPONENT_REF
 	  || operator_code == ARRAY_REF
 	  || operator_code == NOP_EXPR)
--- gcc/cp/call.cc.jj	2022-09-13 18:57:10.199226101 +0200
+++ gcc/cp/call.cc	2022-09-19 13:28:53.511058032 +0200
@@ -12133,10 +12133,14 @@ joust (struct z_candidate *cand1, struct
   len = cand1->num_convs;
   if (len != cand2->num_convs)
     {
-      int static_1 = DECL_STATIC_FUNCTION_P (cand1->fn);
-      int static_2 = DECL_STATIC_FUNCTION_P (cand2->fn);
+      int static_1 = (TREE_CODE (cand1->fn) == FUNCTION_DECL
+		      && DECL_STATIC_FUNCTION_P (cand1->fn));
+      int static_2 = (TREE_CODE (cand2->fn) == FUNCTION_DECL
+		      && DECL_STATIC_FUNCTION_P (cand2->fn));
 
-      if (DECL_CONSTRUCTOR_P (cand1->fn)
+      if (TREE_CODE (cand1->fn) == FUNCTION_DECL
+	  && TREE_CODE (cand2->fn) == FUNCTION_DECL
+	  && DECL_CONSTRUCTOR_P (cand1->fn)
 	  && is_list_ctor (cand1->fn) != is_list_ctor (cand2->fn))
 	/* We're comparing a near-match list constructor and a near-match
 	   non-list constructor.  Just treat them as unordered.  */
@@ -12145,9 +12149,20 @@ joust (struct z_candidate *cand1, struct
       gcc_assert (static_1 != static_2);
 
       if (static_1)
-	off2 = 1;
+	{
+	  /* C++23 [over.best.ics.general] says:
+	     When the parameter is the implicit object parameter of a static
+	     member function, the implicit conversion sequence is a standard
+	     conversion sequence that is neither better nor worse than any
+	     other standard conversion sequence.  */
+	  if (CONVERSION_RANK (cand2->convs[0]) >= cr_user)
+	    winner = 1;
+	  off2 = 1;
+	}
       else
 	{
+	  if (CONVERSION_RANK (cand1->convs[0]) >= cr_user)
+	    winner = -1;
 	  off1 = 1;
 	  --len;
 	}
--- gcc/cp/lambda.cc.jj	2022-09-13 18:57:10.267225191 +0200
+++ gcc/cp/lambda.cc	2022-09-19 12:34:46.638522537 +0200
@@ -1099,7 +1099,9 @@ maybe_add_lambda_conv_op (tree type)
   tree optype = TREE_TYPE (callop);
   tree fn_result = TREE_TYPE (optype);
 
-  tree thisarg = build_int_cst (TREE_TYPE (DECL_ARGUMENTS (callop)), 0);
+  tree thisarg = NULL_TREE;
+  if (TREE_CODE (optype) == METHOD_TYPE)
+    thisarg = build_int_cst (TREE_TYPE (DECL_ARGUMENTS (callop)), 0);
   if (generic_lambda_p)
     {
       ++processing_template_decl;
@@ -1109,18 +1111,22 @@ maybe_add_lambda_conv_op (tree type)
 	 return expression for a deduced return call op to allow for simple
 	 implementation of the conversion operator.  */
 
-      tree instance = cp_build_fold_indirect_ref (thisarg);
       tree objfn = lookup_template_function (DECL_NAME (callop),
 					     DECL_TI_ARGS (callop));
-      objfn = build_min (COMPONENT_REF, NULL_TREE,
-			 instance, objfn, NULL_TREE);
-      int nargs = list_length (DECL_ARGUMENTS (callop)) - 1;
+      int nargs = list_length (DECL_ARGUMENTS (callop));
+      if (thisarg)
+	{
+	  tree instance = cp_build_fold_indirect_ref (thisarg);
+	  objfn = build_min (COMPONENT_REF, NULL_TREE,
+			     instance, objfn, NULL_TREE);
+	  --nargs;
+	  call = prepare_op_call (objfn, nargs);
+	}
 
-      call = prepare_op_call (objfn, nargs);
       if (type_uses_auto (fn_result))
 	decltype_call = prepare_op_call (objfn, nargs);
     }
-  else
+  else if (thisarg)
     {
       direct_argvec = make_tree_vector ();
       direct_argvec->quick_push (thisarg);
@@ -1135,9 +1141,11 @@ maybe_add_lambda_conv_op (tree type)
   tree fn_args = NULL_TREE;
   {
     int ix = 0;
-    tree src = DECL_CHAIN (DECL_ARGUMENTS (callop));
+    tree src = FUNCTION_FIRST_USER_PARM (callop);
     tree tgt = NULL;
 
+    if (!thisarg && !decltype_call)
+      src = NULL_TREE;
     while (src)
       {
 	tree new_node = copy_node (src);
@@ -1160,12 +1168,15 @@ maybe_add_lambda_conv_op (tree type)
 	if (generic_lambda_p)
 	  {
 	    tree a = tgt;
-	    if (DECL_PACK_P (tgt))
+	    if (thisarg)
 	      {
-		a = make_pack_expansion (a);
-		PACK_EXPANSION_LOCAL_P (a) = true;
+		if (DECL_PACK_P (tgt))
+		  {
+		    a = make_pack_expansion (a);
+		    PACK_EXPANSION_LOCAL_P (a) = true;
+		  }
+		CALL_EXPR_ARG (call, ix) = a;
 	      }
-	    CALL_EXPR_ARG (call, ix) = a;
 
 	    if (decltype_call)
 	      {
@@ -1193,7 +1204,7 @@ maybe_add_lambda_conv_op (tree type)
 	     tf_warning_or_error);
 	}
     }
-  else
+  else if (thisarg)
     {
       /* Don't warn on deprecated or unavailable lambda declarations, unless
 	 the lambda is actually called.  */
@@ -1203,10 +1214,14 @@ maybe_add_lambda_conv_op (tree type)
 			   direct_argvec->address ());
     }
 
-  CALL_FROM_THUNK_P (call) = 1;
-  SET_EXPR_LOCATION (call, UNKNOWN_LOCATION);
+  if (thisarg)
+    {
+      CALL_FROM_THUNK_P (call) = 1;
+      SET_EXPR_LOCATION (call, UNKNOWN_LOCATION);
+    }
 
-  tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop));
+  tree stattype
+    = build_function_type (fn_result, FUNCTION_FIRST_USER_PARMTYPE (callop));
   stattype = (cp_build_type_attribute_variant
 	      (stattype, TYPE_ATTRIBUTES (optype)));
   if (flag_noexcept_type
@@ -1249,6 +1264,41 @@ maybe_add_lambda_conv_op (tree type)
 
   add_method (type, fn, false);
 
+  if (thisarg == NULL_TREE)
+    {
+      /* For static lambda, just return operator().  */
+      if (nested)
+	push_function_context ();
+      else
+	/* Still increment function_depth so that we don't GC in the
+	   middle of an expression.  */
+	++function_depth;
+
+      /* Generate the body of the conversion op.  */
+
+      start_preparsed_function (convfn, NULL_TREE,
+				SF_PRE_PARSED | SF_INCLASS_INLINE);
+      tree body = begin_function_body ();
+      tree compound_stmt = begin_compound_stmt (0);
+
+      /* decl_needed_p needs to see that it's used.  */
+      TREE_USED (callop) = 1;
+      finish_return_stmt (decay_conversion (callop, tf_warning_or_error));
+
+      finish_compound_stmt (compound_stmt);
+      finish_function_body (body);
+
+      fn = finish_function (/*inline_p=*/true);
+      if (!generic_lambda_p)
+	expand_or_defer_fn (fn);
+
+      if (nested)
+	pop_function_context ();
+      else
+	--function_depth;
+      return;
+    }
+
   /* Generic thunk code fails for varargs; we'll complain in mark_used if
      the conversion op is used.  */
   if (varargs_function_p (callop))
--- gcc/cp/error.cc.jj	2022-09-13 18:57:10.249225432 +0200
+++ gcc/cp/error.cc	2022-09-19 11:53:19.851593949 +0200
@@ -1692,7 +1692,13 @@ dump_lambda_function (cxx_pretty_printer
 {
   /* A lambda's signature is essentially its "type".  */
   dump_type (pp, DECL_CONTEXT (fn), flags);
-  if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST))
+  if (TREE_CODE (TREE_TYPE (fn)) == FUNCTION_TYPE)
+    {
+      pp->padding = pp_before;
+      pp_c_ws_string (pp, "static");
+    }
+  else if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn)))
+	     & TYPE_QUAL_CONST))
     {
       pp->padding = pp_before;
       pp_c_ws_string (pp, "mutable");
--- gcc/c-family/c-cppbuiltin.cc.jj	2022-09-13 18:57:10.128227052 +0200
+++ gcc/c-family/c-cppbuiltin.cc	2022-09-19 11:53:19.873593647 +0200
@@ -1081,6 +1081,7 @@ c_cpp_builtins (cpp_reader *pfile)
 	  cpp_define (pfile, "__cpp_constexpr=202110L");
 	  cpp_define (pfile, "__cpp_multidimensional_subscript=202110L");
 	  cpp_define (pfile, "__cpp_named_character_escapes=202207L");
+	  cpp_define (pfile, "__cpp_static_call_operator=202207L");
 	}
       if (flag_concepts)
         {
--- gcc/testsuite/g++.dg/template/error30.C.jj	2020-07-28 15:39:10.020756063 +0200
+++ gcc/testsuite/g++.dg/template/error30.C	2022-09-19 11:53:19.880593550 +0200
@@ -2,4 +2,4 @@
 
 template<int> struct A;
 
-template<template<typename> class B> A<B<int>::x> operator() (); // { dg-error "51:.A<B<int>::x> operator\\(\\)\\(\\). must be a non-static member function" }
+template<template<typename> class B> A<B<int>::x> operator() (); // { dg-error "51:.A<B<int>::x> operator\\(\\)\\(\\). must be a member function" }
--- gcc/testsuite/g++.dg/cpp1z/constexpr-lambda13.C.jj	2020-01-12 11:54:37.127402637 +0100
+++ gcc/testsuite/g++.dg/cpp1z/constexpr-lambda13.C	2022-09-19 12:47:20.398209828 +0200
@@ -2,4 +2,4 @@
 
 auto l1 = []() constexpr constexpr { }; // { dg-error "duplicate" }
 auto l2 = []() mutable mutable { }; // { dg-error "duplicate" }
-auto l3 = []() static { };	    // { dg-error "static" }
+auto l3 = []() static { };	    // { dg-error "static' only valid in lambda with" "" { target c++20_down } }
--- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C.jj	2022-09-13 18:57:10.408223302 +0200
+++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C	2022-09-19 11:53:19.907593180 +0200
@@ -563,3 +563,9 @@
 #elif __cpp_named_character_escapes != 202207
 #  error "__cpp_named_character_escapes != 202207"
 #endif
+
+#ifndef __cpp_static_call_operator
+#  error "__cpp_static_call_operator"
+#elif __cpp_static_call_operator != 202207
+#  error "__cpp_static_call_operator != 202207"
+#endif
--- gcc/testsuite/g++.dg/cpp23/static-operator-call1.C.jj	2022-09-19 11:53:19.908593166 +0200
+++ gcc/testsuite/g++.dg/cpp23/static-operator-call1.C	2022-09-19 13:32:10.095362732 +0200
@@ -0,0 +1,41 @@
+// P1169R4 - static operator()
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+template <typename T>
+struct S
+{
+  static constexpr bool operator () (T const &x, T const &y) { return x < y; }; // { dg-warning "may be a static member function only with" "" { target c++20_down } }
+  using P = bool (*) (T const &, T const &);
+  operator P () const { return operator (); }
+};
+
+static_assert (S<int> {} (1, 2), "");
+
+template <typename T>
+void
+bar (T &x)
+{
+  x (1, 2);
+}
+
+void
+foo ()
+{
+#if __cpp_constexpr >= 201603L
+  auto a = [](int x, int y) static constexpr { return x + y; };			// { dg-warning "'static' only valid in lambda with" "" { target { c++17 && c++20_down } } }
+  static_assert (a (1, 2) == 3, "");
+  bar (*a);
+#endif
+  auto b = []() static { return 1; };						// { dg-warning "'static' only valid in lambda with" "" { target c++20_down } }
+  b ();
+  auto c = [](int x, int y) static { return x + y; };				// { dg-warning "'static' only valid in lambda with" "" { target c++20_down } }
+  c (1, 2);
+  bar (*c);
+#if __cpp_generic_lambdas >= 201707L
+  auto d = []<typename T, typename U>(T x, U y) static { return x + y; };	// { dg-warning "'static' only valid in lambda with" "" { target c++20_only } }
+  d (1, 2L);
+#endif
+  S<long> s;
+  s(1L, 2L);
+}
--- gcc/testsuite/g++.dg/cpp23/static-operator-call2.C.jj	2022-09-19 11:53:19.908593166 +0200
+++ gcc/testsuite/g++.dg/cpp23/static-operator-call2.C	2022-09-19 12:54:54.226996543 +0200
@@ -0,0 +1,22 @@
+// P1169R4 - static operator()
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+void
+foo ()
+{
+  int u = 0;
+  auto a = [](int x, int y) mutable mutable { return x + y; };		// { dg-error "duplicate 'mutable' specifier" }
+  auto b = [](int x, int y) static static { return x + y; };		// { dg-error "duplicate 'static' specifier" }
+									// { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 }
+  auto c = [](int x, int y) static mutable { return x + y; };		// { dg-error "'mutable' specifier conflicts with 'static'" }
+									// { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 }
+  auto d = [](int x, int y) mutable static { return x + y; };		// { dg-error "'static' specifier conflicts with 'mutable'" }
+									// { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 }
+  auto e = [=](int x, int y) static { return x + y; };			// { dg-error "lambda specifier with lambda capture" }
+									// { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 }
+  auto f = [&](int x, int y) static { return x + y; };			// { dg-error "lambda specifier with lambda capture" }
+									// { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 }
+  auto g = [u](int x, int y) static { return x + y; };			// { dg-error "lambda specifier with lambda capture" }
+									// { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 }
+}
--- gcc/testsuite/g++.old-deja/g++.jason/operator.C.jj	2020-07-28 15:39:10.024756008 +0200
+++ gcc/testsuite/g++.old-deja/g++.jason/operator.C	2022-09-19 11:53:19.918593029 +0200
@@ -6,7 +6,7 @@ typedef __SIZE_TYPE__ size_t;
 
 struct A {
   int operator?:(int a, int b);	   // { dg-error "prohibits overloading" } 
-  static int operator()(int a);	   // { dg-error "14:.static int A::operator\\(\\)\\(int\\). must be a non-static member function" }
+  static int operator()(int a);	   // { dg-warning "14:.static int A::operator\\(\\)\\(int\\). may be a static member function only with" "" { target c++20_down } }
   static int operator+(A,A);	   // { dg-error "14:.static int A::operator\\+\\(A, A\\). must be either a non-static member function or a non-member function" } 
   int operator+(int a, int b = 1); // { dg-error "7:.int A::operator\\+\\(int, int\\). must have either zero or one argument" }
   int operator++(char);		   // { dg-error "7:postfix .int A::operator\\+\\+\\(char\\). must have .int. as its argument" }
