Index: clang/docs/ClangFormatStyleOptions.rst =================================================================== --- clang/docs/ClangFormatStyleOptions.rst +++ clang/docs/ClangFormatStyleOptions.rst @@ -1973,7 +1973,18 @@ * ``BS_Custom`` (in configuration: ``Custom``) Configure each individual brace in `BraceWrapping`. +**BreakBeforeInlineASMColon** (``bool``) + If ``true``, colons in ASM parameters will be placed after line breaks. + .. code-block:: c + + true: + asm volatile("string", + : + : val); + + false: + asm volatile("string", : : val); **BreakBeforeConceptDeclarations** (``bool``) If ``true``, concept will be placed on a new line. Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -1751,6 +1751,18 @@ /// \endcode bool BreakBeforeConceptDeclarations; + /// If ``true``, colons in ASM parameters will be placed after line breaks. + /// \code + /// true: + /// asm volatile("string", + /// : + /// : val); + /// + /// false: + /// asm volatile("string", : : val); + /// \endcode + bool BreakBeforeInlineASMColon; + /// If ``true``, ternary operators will be placed after line breaks. /// \code /// true: @@ -3417,6 +3429,7 @@ BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators && BreakBeforeBraces == R.BreakBeforeBraces && BreakBeforeConceptDeclarations == R.BreakBeforeConceptDeclarations && + BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon && BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators && BreakConstructorInitializers == R.BreakConstructorInitializers && CompactNamespaces == R.CompactNamespaces && Index: clang/lib/Format/ContinuationIndenter.cpp =================================================================== --- clang/lib/Format/ContinuationIndenter.cpp +++ clang/lib/Format/ContinuationIndenter.cpp @@ -334,7 +334,8 @@ auto LambdaBodyLength = getLengthToMatchingParen(Current, State.Stack); return (LambdaBodyLength > getColumnLimit(State)); } - if (Current.MustBreakBefore || Current.is(TT_InlineASMColon)) + if (Current.MustBreakBefore || + (Current.is(TT_InlineASMColon) && Style.BreakBeforeInlineASMColon)) return true; if (State.Stack.back().BreakBeforeClosingBrace && Current.closesBlockOrBlockTypeList(Style)) Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -612,6 +612,9 @@ Style.BreakInheritanceList == FormatStyle::BILS_BeforeColon) Style.BreakInheritanceList = FormatStyle::BILS_BeforeComma; + IO.mapOptional("BreakBeforeInlineASMColon", + Style.BreakBeforeInlineASMColon); + IO.mapOptional("BreakBeforeTernaryOperators", Style.BreakBeforeTernaryOperators); @@ -1006,6 +1009,7 @@ LLVMStyle.BinPackParameters = true; LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None; LLVMStyle.BreakBeforeConceptDeclarations = true; + LLVMStyle.BreakBeforeInlineASMColon = false; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false, Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -3602,6 +3602,9 @@ const FormatToken &Left = *Right.Previous; if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0) return true; + if (Line.startsWith(tok::kw_asm) && Right.is(TT_InlineASMColon) && + Style.BreakBeforeInlineASMColon) + return true; if (Style.isCSharp()) { if (Right.is(TT_CSharpNamedArgumentColon) || Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -3795,12 +3795,16 @@ TEST_F(FormatTest, FormatsInlineASM) { verifyFormat("asm(\"xyz\" : \"=a\"(a), \"=d\"(b) : \"a\"(data));"); verifyFormat("asm(\"nop\" ::: \"memory\");"); + + FormatStyle Style = getLLVMStyle(); + Style.BreakBeforeInlineASMColon = true; verifyFormat( "asm(\"movq\\t%%rbx, %%rsi\\n\\t\"\n" " \"cpuid\\n\\t\"\n" " \"xchgq\\t%%rbx, %%rsi\\n\\t\"\n" " : \"=a\"(*rEAX), \"=S\"(*rEBX), \"=c\"(*rECX), \"=d\"(*rEDX)\n" - " : \"a\"(value));"); + " : \"a\"(value));", + Style); EXPECT_EQ( "void NS_InvokeByIndex(void *that, unsigned int methodIndex) {\n" " __asm {\n" @@ -6240,6 +6244,43 @@ format(Input, Style)); } +TEST_F(FormatTest, BreakBeforeInlineASMColon) { + FormatStyle Style = getLLVMStyle(); + Style.BreakStringLiterals = false; + Style.BreakBeforeInlineASMColon = false; + /* Test the behaviour with long lines */ + Style.ColumnLimit = 40; + verifyFormat("asm volatile(\"loooooooooooooooooooong\",\n" + " : : val);", + Style); + verifyFormat("asm volatile(\"loooooooooooooooooooong\",\n" + " : val1 : val2);", + Style); + Style.ColumnLimit = 80; + verifyFormat("asm volatile(\"string\", : : val);", Style); + verifyFormat("asm volatile(\"string\", : val1 : val2);", Style); + + Style.BreakBeforeInlineASMColon = true; + verifyFormat("asm volatile(\"string\",\n" + " :\n" + " : val);", + Style); + verifyFormat("asm volatile(\"string\",\n" + " : val1\n" + " : val2);", + Style); + /* Test the behaviour with long lines */ + Style.ColumnLimit = 40; + verifyFormat("asm volatile(\"loooooooooooooooooooong\",\n" + " :\n" + " : val);", + Style); + verifyFormat("asm volatile(\"loooooooooooooooooooong\",\n" + " : val1\n" + " : val2);", + Style); +} + TEST_F(FormatTest, BreakConstructorInitializersAfterColon) { FormatStyle Style = getLLVMStyle(); Style.BreakConstructorInitializers = FormatStyle::BCIS_AfterColon; @@ -21194,15 +21235,18 @@ // A list of several ASM symbolic names. verifyFormat(R"(asm("mov %[e], %[d]" : [d] "=rm"(d), [e] "rm"(*e));)"); + // ASM symbolic names in inline ASM with no outputs. + verifyFormat(R"(asm("mov %[e], %[d]" : : [d] "=rm"(d), [e] "rm"(*e));)"); + + format::FormatStyle Style = format::getLLVMStyle(); + Style.BreakBeforeInlineASMColon = true; // ASM symbolic names in inline ASM with inputs and outputs. verifyFormat(R"(// asm("cmoveq %1, %2, %[result]" : [result] "=r"(result) : "r"(test), "r"(new), "[result]"(old)); -)"); - - // ASM symbolic names in inline ASM with no outputs. - verifyFormat(R"(asm("mov %[e], %[d]" : : [d] "=rm"(d), [e] "rm"(*e));)"); +)", + Style); } TEST_F(FormatTest, GuessedLanguageWithInlineAsmClobbers) {