modocache created this revision. modocache added reviewers: rsmith, sammccall, Typz, klimek. Herald added a project: clang.
When C++ coroutines were adopted as part of the C++20 standard, a change was committed in https://github.com/llvm/llvm-project/commit/10ab78e854f: coroutine keywords such as `co_yield` went from being gated on the presence of the `-fcoroutines-ts` flag, to instead being gated on `-std=c++2a`. This resulted, perhaps unexpectedly to some users, in a change in how coroutine keywords were formatted. Because libclangFormat has only 3 options for formatting according to a language standard -- C++03, C++11, or "auto" -- and because it enabled C++20 keywords for all settings aside from C++03, users who specified a standard of C++11 in their style options would have their C++ formatted as if `co_yield` were a keyword: - Before, C++03: `co_yield ++i` would be formatted as `co_yield++ i` - Before, C++11: `co_yield ++i` would be formatted as `co_yield++ i` - After, C++03: `co_yield ++i` would be formatted as `co_yield++ i` - After, C++11: `co_yield ++i` would be formatted as `co_yield ++i` Although the "after" examples above appear like correct formatting choices to those who are used to seeing coroutine keywords, I would argue that they aren't technically correct, because a user may define a variable in C++11 named `co_yield`, and they could increment that variable by typing `co_yield++`. In this case, clang-format would change the formatting, despite the user never opting-in to treating `co_yield` as a keyword. (There are other examples of clang-format suddenly formatting C++11 code according to C++20 standards differently as a result of changes like https://github.com/llvm/llvm-project/commit/10ab78e854f, and I've included them as tests in this commit, but I won't go into detail explaining them here.) To give users the option of formatting according to the C++11 standard, without the use of coroutines, I've added a style option for the C++20 standard (and, similarly to how the C++11 standard enables C++14, 17, and 1z, I've written the documentation to indicate using the C++20 option enables any future C++2a standards). In a future commit, I add a boolean style option to enable coroutines, so that users may specify they wish to format according to the C++11 standard, but with coroutine keywords enabled. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D65043 Files: clang/docs/ClangFormatStyleOptions.rst clang/include/clang/Format/Format.h clang/lib/Format/Format.cpp clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/FormatTest.cpp
Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -3713,10 +3713,20 @@ "if (aaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaa(\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) == 5) {\n" "}"); + + // Only in C++20 and above is <=> treated as as operator. verifyFormat( "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" - " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) <=> 5) {\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) <= >\n" + " 5) {\n" "}"); + FormatStyle Cpp20 = getLLVMStyle(); + Cpp20.Standard = FormatStyle::LS_Cpp20; + verifyFormat( + "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) <=> 5) {\n" + "}", Cpp20); + // Even explicit parentheses stress the precedence enough to make the // additional break unnecessary. verifyFormat("if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n" @@ -3736,10 +3746,15 @@ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ==\n" " 5) {\n" "}"); + // Only in C++20 and above is <=> treated as as operator. + verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <=\n" + " > 5) {\n" + "}"); verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <=>\n" " 5) {\n" - "}"); + "}", Cpp20); FormatStyle OnePerLine = getLLVMStyle(); OnePerLine.BinPackParameters = false; @@ -13792,6 +13807,18 @@ verifyFormat("STACK_OF(int*)* a;", Macros); } +TEST_F(FormatTest, Coroutines) { + FormatStyle Cpp20 = getLLVMStyle(); + Cpp20.Standard = FormatStyle::LS_Cpp20; + + verifyFormat("co_yield++ i;"); + verifyFormat("co_yield ++i;", Cpp20); + + verifyFormat("co_await[]() { co_return; }\n" + "();"); + verifyFormat("co_await []() { co_return; }();", Cpp20); +} + } // end namespace } // end namespace format } // end namespace clang Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -2859,7 +2859,8 @@ (Style.Language == FormatStyle::LK_Proto && Left.is(TT_DictLiteral))) return !Style.Cpp11BracedListStyle; return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) && - (Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles); + (Style.Standard == FormatStyle::LS_Cpp03 || + Style.Standard == FormatStyle::LS_Auto || Style.SpacesInAngles); } if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) || Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) || Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -71,6 +71,8 @@ IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03); IO.enumCase(Value, "Cpp11", FormatStyle::LS_Cpp11); IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11); + IO.enumCase(Value, "Cpp20", FormatStyle::LS_Cpp20); + IO.enumCase(Value, "C++20", FormatStyle::LS_Cpp20); IO.enumCase(Value, "Auto", FormatStyle::LS_Auto); } }; @@ -2368,7 +2370,7 @@ LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; - LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; + LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp20 ? 1 : 0; LangOpts.LineComment = 1; bool AlternativeOperators = Style.isCpp(); LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0; Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -1875,6 +1875,10 @@ /// Use features of C++11, C++14 and C++1z (e.g. ``A<A<int>>`` instead of /// ``A<A<int> >``). LS_Cpp11, + /// Use features of C++20 and C++2a (e.g.: treating ``co_yield`` as a + /// keyword, not an identifier, so ``co_yield++ i`` is formatted as + /// ``co_yield ++i``). + LS_Cpp20, /// Automatic detection based on the input. LS_Auto }; Index: clang/docs/ClangFormatStyleOptions.rst =================================================================== --- clang/docs/ClangFormatStyleOptions.rst +++ clang/docs/ClangFormatStyleOptions.rst @@ -2223,6 +2223,10 @@ Use features of C++11, C++14 and C++1z (e.g. ``A<A<int>>`` instead of ``A<A<int> >``). + * ``LS_Cpp20`` (in configuration: ``Cpp20``) + Use features of C++20 and C++2a (e.g.: treating ``co_yield`` as a keyword, + not an identifier, so ``co_yield++ i`` is formatted as ``co_yield ++i``). + * ``LS_Auto`` (in configuration: ``Auto``) Automatic detection based on the input.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits