atomic-statement
 
   IN_COMPOUND is true when the statement is nested inside a
-  cp_parser_compound_statement; this matters for certain pragmas.
+  cp_parser_compound_statement.
 
   If IF_P is not NULL, *IF_P is set to indicate whether the statement
   is a (possibly labeled) if statement which is not enclosed in braces
 
 static void
 cp_parser_statement (cp_parser* parser, tree in_statement_expr,
-                    bool in_compound, bool *if_p, vec<tree> *chain,
+                    const bool in_compound, bool *if_p, vec<tree> *chain,
                     location_t *loc_after_labels)
 {
   tree statement, std_attrs = NULL_TREE;
   location_t statement_location, attrs_loc;
   bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma;
   bool has_std_attrs;
+  /* A copy of IN_COMPOUND which is set to false after seeing a label.
+     This matters for certain pragmas.  */
+  bool in_compound_for_pragma = in_compound;
 
  restart:
   if (if_p != NULL)
             Parse the label, and then use tail recursion to parse
             the statement.  */
          cp_parser_label_for_labeled_statement (parser, std_attrs);
-         in_compound = false;
+         in_compound_for_pragma = false;
          in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma;
          goto restart;
 
             the statement.  */
 
          cp_parser_label_for_labeled_statement (parser, std_attrs);
-         in_compound = false;
+
+         /* If there's no statement, it's not a labeled-statement, just
+            a label.  That's allowed in C++23, but only if we're at the
+            end of a compound-statement.  */
+         if (in_compound
+             && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+           {
+             location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+             if (cxx_dialect < cxx23)
+               pedwarn (loc, OPT_Wc__23_extensions,
+                        "label at end of compound statement only available "
+                        "with %<-std=c++2b%> or %<-std=gnu++2b%>");
+             return;
+           }
+         in_compound_for_pragma = false;
          in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma;
          goto restart;
        }
         the context of a compound, accept the pragma as a "statement" and
         return so that we can check for a close brace.  Otherwise we
         require a real statement and must go back and read one.  */
-      if (in_compound)
+      if (in_compound_for_pragma)
        cp_parser_pragma (parser, pragma_compound, if_p);
       else if (!cp_parser_pragma (parser, pragma_stmt, if_p))
        do_restart = true;
 
 /* Parse the label for a labeled-statement, i.e.
 
-   identifier :
-   case constant-expression :
-   default :
+   label:
+     attribute-specifier-seq[opt] identifier :
+     attribute-specifier-seq[opt] case constant-expression :
+     attribute-specifier-seq[opt] default :
+
+   labeled-statement:
+     label statement
 
    GNU Extension:
    case constant-expression ... constant-expression : statement
 /* Parse a compound-statement.
 
    compound-statement:
-     { statement-seq [opt] }
+     { statement-seq [opt] label-seq [opt] }
+
+   label-seq:
+     label
+     label-seq label
 
    GNU extension:
 
 
--- /dev/null
+// P2324R2 - Labels at the end of compound statements
+// PR c++/103539
+// { dg-do compile }
+// Test good cases.
+
+void
+p2324 ()
+{
+first:
+  int x; 
+second:
+  x = 1;
+last:
+} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
+
+void
+fn1 ()
+{
+  l1:
+} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
+
+void
+fn2 ()
+{
+  if (1)
+    {
+l1:
+    } // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
+}
+
+void
+fn3 ()
+{
+  {
+    {
+label:
+    } // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
+  }
+}
+
+void
+fn4 ()
+{
+  switch (1)
+    {
+lab:
+    } // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
+}
+
+void
+fn5 ()
+{
+l1:
+l2:
+l3:
+} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
+
+void
+fn6 ()
+{
+  ;
+l1:
+l2:
+l3:
+} // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
+
+
+#if __cplusplus >= 201103L
+void
+fn7 ()
+{
+  auto l = [](){
+    lab:
+  }; // { dg-error "label at end of compound statement only available with" "" { target { c++20_down && c++11 } } }
+}
+#endif
+
+void
+fn8 ()
+{
+  try
+    {
+lab1:
+    } // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
+  catch (int)
+    {
+lab2:
+    } // { dg-error "label at end of compound statement only available with" "" { target c++20_down } }
+}