Author: ahmed mohamed kamel
Date: 2026-08-25T19:02:47Z
New Revision: f1363c60faea7c903683339c8c4f0d824f7cd9d7

URL: 
https://github.com/llvm/llvm-project/commit/f1363c60faea7c903683339c8c4f0d824f7cd9d7
DIFF: 
https://github.com/llvm/llvm-project/commit/f1363c60faea7c903683339c8c4f0d824f7cd9d7.diff

LOG: [clang-format] Add BraceWrapping.AfterExportBlock option (#216892)

### Summary
Adds the `BraceWrapping.AfterExportBlock` option to `clang-format`. This
allows users configuring `BreakBeforeBraces: Custom` to specify whether
the opening brace of a C++20 `export` block should be wrapped onto a new
line.
Fixes #216785

### Examples
```c++
// BraceWrapping.AfterExportBlock = true
export
{
  int foo();
}

// BraceWrapping.AfterExportBlock = false
export {
  int foo();
}

Added: 
    

Modified: 
    clang/docs/ClangFormatStyleOptions.md
    clang/include/clang/Format/Format.h
    clang/lib/Format/Format.cpp
    clang/lib/Format/FormatToken.h
    clang/lib/Format/TokenAnnotator.h
    clang/lib/Format/UnwrappedLineFormatter.cpp
    clang/lib/Format/UnwrappedLineParser.cpp
    clang/unittests/Format/ConfigParseTest.cpp
    clang/unittests/Format/FormatTest.cpp
    clang/unittests/Format/TokenAnnotatorTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ClangFormatStyleOptions.md 
b/clang/docs/ClangFormatStyleOptions.md
index 5ee06983036c9..ee239f768cf2b 100644
--- a/clang/docs/ClangFormatStyleOptions.md
+++ b/clang/docs/ClangFormatStyleOptions.md
@@ -2582,6 +2582,16 @@ the configuration (without a prefix: `Auto`).
     }
     ```
 
+  - `bool AfterExportBlock` Wrap export blocks.
+
+    ```c++
+    true:                            false:
+    export             vs.           export {
+    {                                  int foo();
+      int foo();                     }
+    }
+    ```
+
   - `bool AfterExternBlock` Wrap extern blocks.
 
     ```c++

diff  --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index 554ebdab09442..0f91df5b1b32d 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1535,6 +1535,15 @@ struct FormatStyle {
     ///   }
     /// \endcode
     bool AfterUnion;
+    /// Wrap export blocks.
+    /// \code
+    ///   true:                            false:
+    ///   export             vs.           export {
+    ///   {                                  int foo();
+    ///     int foo();                     }
+    ///   }
+    /// \endcode
+    bool AfterExportBlock;
     /// Wrap extern blocks.
     /// \code
     ///   true:

diff  --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index fa308086da5b5..e5533c32899a3 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -221,6 +221,7 @@ template <> struct 
MappingTraits<FormatStyle::BraceWrappingFlags> {
     IO.mapOptional("AfterClass", Wrapping.AfterClass);
     IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement);
     IO.mapOptional("AfterEnum", Wrapping.AfterEnum);
+    IO.mapOptional("AfterExportBlock", Wrapping.AfterExportBlock);
     IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock);
     IO.mapOptional("AfterFunction", Wrapping.AfterFunction);
     IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace);
@@ -1726,6 +1727,7 @@ static void expandPresetsBraceWrapping(FormatStyle 
&Expanded) {
                             /*AfterObjCDeclaration=*/false,
                             /*AfterStruct=*/false,
                             /*AfterUnion=*/false,
+                            /*AfterExportBlock=*/false,
                             /*AfterExternBlock=*/false,
                             /*BeforeCatch=*/false,
                             /*BeforeElse=*/false,
@@ -1747,6 +1749,7 @@ static void expandPresetsBraceWrapping(FormatStyle 
&Expanded) {
     Expanded.BraceWrapping.AfterFunction = true;
     Expanded.BraceWrapping.AfterStruct = true;
     Expanded.BraceWrapping.AfterUnion = true;
+    Expanded.BraceWrapping.AfterExportBlock = true;
     Expanded.BraceWrapping.AfterExternBlock = true;
     Expanded.BraceWrapping.SplitEmptyFunction = true;
     Expanded.BraceWrapping.SplitEmptyRecord = false;
@@ -1766,6 +1769,7 @@ static void expandPresetsBraceWrapping(FormatStyle 
&Expanded) {
     Expanded.BraceWrapping.AfterObjCDeclaration = true;
     Expanded.BraceWrapping.AfterStruct = true;
     Expanded.BraceWrapping.AfterUnion = true;
+    Expanded.BraceWrapping.AfterExportBlock = true;
     Expanded.BraceWrapping.AfterExternBlock = true;
     Expanded.BraceWrapping.BeforeCatch = true;
     Expanded.BraceWrapping.BeforeElse = true;
@@ -1796,6 +1800,7 @@ static void expandPresetsBraceWrapping(FormatStyle 
&Expanded) {
         /*AfterObjCDeclaration=*/true,
         /*AfterStruct=*/true,
         /*AfterUnion=*/true,
+        /*AfterExportBlock=*/true,
         /*AfterExternBlock=*/true,
         /*BeforeCatch=*/true,
         /*BeforeElse=*/true,
@@ -1898,6 +1903,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind 
Language) {
                              /*AfterObjCDeclaration=*/false,
                              /*AfterStruct=*/false,
                              /*AfterUnion=*/false,
+                             /*AfterExportBlock=*/false,
                              /*AfterExternBlock=*/false,
                              /*BeforeCatch=*/false,
                              /*BeforeElse=*/false,

diff  --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index 4a2982eaa3a17..691ecdd24f448 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -80,6 +80,7 @@ namespace format {
   TYPE(EnumLBrace)                                                             
\
   TYPE(EnumRBrace)                                                             
\
   TYPE(EnumUnderlyingTypeColon)                                                
\
+  TYPE(ExportLBrace)                                                           
\
   TYPE(FatArrow)                                                               
\
   TYPE(ForEachMacro)                                                           
\
   TYPE(FunctionAnnotationRParen)                                               
\

diff  --git a/clang/lib/Format/TokenAnnotator.h 
b/clang/lib/Format/TokenAnnotator.h
index 264f39b7b1d60..c909c39e92ea3 100644
--- a/clang/lib/Format/TokenAnnotator.h
+++ b/clang/lib/Format/TokenAnnotator.h
@@ -157,11 +157,6 @@ class AnnotatedLine {
            startsWith(tok::kw_export, tok::kw_namespace);
   }
 
-  /// \c true if this line starts a C++ export block.
-  bool startsWithExportBlock() const {
-    return startsWith(tok::kw_export, tok::l_brace);
-  }
-
   FormatToken *getFirstNonComment() const {
     assert(First);
     return First->is(tok::comment) ? First->getNextNonComment() : First;

diff  --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index b783876b6da8f..33e6807dfe7dd 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -444,7 +444,8 @@ class LineJoiner {
     if (TheLine->Last->is(tok::l_brace) && FirstNonComment != TheLine->Last &&
         (FirstNonComment->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for,
                                   TT_ForEachMacro) ||
-         TheLine->startsWithExportBlock())) {
+         (TheLine->Last->is(TT_ExportLBrace) &&
+          !Style.BraceWrapping.AfterExportBlock))) {
       return Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never
                  ? tryMergeSimpleBlock(I, E, Limit)
                  : 0;
@@ -892,7 +893,7 @@ class LineJoiner {
         Line.First->isOneOf(tok::kw_try, tok::kw___try, tok::kw_catch,
                             tok::kw___finally, tok::r_brace,
                             Keywords.kw___except) ||
-        Line.startsWithExportBlock()) {
+        Line.Last->is(TT_ExportLBrace)) {
       if (IsSplitBlock)
         return 0;
       // Don't merge when we can't except the case when
@@ -937,6 +938,11 @@ class LineJoiner {
     }
 
     if (Line.endsWith(tok::l_brace)) {
+      if (Style.BraceWrapping.AfterExportBlock &&
+          Line.First->is(TT_ExportLBrace)) {
+        return 0;
+      }
+
       if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never &&
           Line.First->is(TT_BlockLBrace)) {
         return 0;

diff  --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index da6465548bb3e..621804b060fad 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -3311,6 +3311,11 @@ void UnwrappedLineParser::parseNamespace() {
 }
 
 void UnwrappedLineParser::parseCppExportBlock() {
+  if (FormatTok->is(tok::l_brace)) {
+    FormatTok->setFinalizedType(TT_ExportLBrace);
+    if (Style.BraceWrapping.AfterExportBlock)
+      addUnwrappedLine();
+  }
   parseNamespaceOrExportBlock(/*AddLevels=*/Style.IndentExportBlock ? 1 : 0);
 }
 

diff  --git a/clang/unittests/Format/ConfigParseTest.cpp 
b/clang/unittests/Format/ConfigParseTest.cpp
index 9350ba7eb3de4..53fbec9806ca4 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -238,6 +238,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
   CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterCaseLabel);
   CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterClass);
   CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterEnum);
+  CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterExportBlock);
   CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterFunction);
   CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterNamespace);
   CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterObjCDeclaration);

diff  --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index 99561f12c51c8..ca9312ae40f1d 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -4931,6 +4931,26 @@ TEST_F(FormatTest, IndentExternBlockStyle) {
                Style);
 }
 
+TEST_F(FormatTest, BraceWrappingAfterExportBlock) {
+  FormatStyle Style = getLLVMStyle();
+  Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+  Style.BraceWrapping.AfterExportBlock = true;
+  verifyFormat("export\n"
+               "{\n"
+               "  int foo();\n"
+               "}",
+               "export {\n"
+               "  int foo();\n"
+               "}",
+               Style);
+
+  Style.BraceWrapping.AfterExportBlock = false;
+  verifyFormat("export {\n"
+               "  int foo();\n"
+               "}",
+               Style);
+}
+
 TEST_F(FormatTest, FormatsInlineASM) {
   verifyFormat("asm(\"xyz\" : \"=a\"(a), \"=d\"(b) : \"a\"(data));");
   verifyFormat("asm(\"nop\" ::: \"memory\");");

diff  --git a/clang/unittests/Format/TokenAnnotatorTest.cpp 
b/clang/unittests/Format/TokenAnnotatorTest.cpp
index ae9e0b6b8e74c..b71147aaf1bc2 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -694,6 +694,14 @@ TEST_F(TokenAnnotatorTest, UnderstandsEnums) {
   EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_EnumRBrace);
 }
 
+TEST_F(TokenAnnotatorTest, UnderstandsExportBlock) {
+  auto Tokens = annotate("export {\n"
+                         "int foo();\n"
+                         "}");
+  ASSERT_EQ(Tokens.size(), 9u) << Tokens;
+  EXPECT_TOKEN(Tokens[1], tok::l_brace, TT_ExportLBrace);
+}
+
 TEST_F(TokenAnnotatorTest, UnderstandsDefaultedAndDeletedFunctions) {
   auto Tokens = annotate("auto operator<=>(const T &) const & = default;");
   ASSERT_EQ(Tokens.size(), 14u) << Tokens;


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to