diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2220,8 +2220,18 @@ Use C++03-compatible syntax. * ``LS_Cpp11`` (in configuration: ``Cpp11``) - Use features of C++11, C++14 and C++1z (e.g. ``A>`` instead of - ``A >``). + Use C++11-compatible syntax. For backwards-compatibility with older + versions of clang-format, this option implies C++14- and C++17-compatible + syntax as well. + + * ``LS_Cpp14`` (in configuration: ``Cpp14``) + Use C++14-compatible syntax. + + * ``LS_Cpp17`` (in configuration: ``Cpp17``) + Use C++17-compatible syntax. + + * ``LS_Cpp2a`` (in configuration: ``Cpp2a``) + Use C++2a-compatible syntax. * ``LS_Auto`` (in configuration: ``Auto``) Automatic detection based on the input. diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -1872,9 +1872,16 @@ enum LanguageStandard { /// Use C++03-compatible syntax. LS_Cpp03, - /// Use features of C++11, C++14 and C++1z (e.g. ``A>`` instead of - /// ``A >``). + /// Use C++11-compatible syntax. For backwards-compatibility with older + /// versions of clang-format, this option implies C++14- and + /// C++17-compatible syntax as well. LS_Cpp11, + /// Use C++14-compatible syntax. + LS_Cpp14, + /// Use C++17-compatible syntax. + LS_Cpp17, + /// Use C++2a-compatible syntax. + LS_Cpp2a, /// Automatic detection based on the input. LS_Auto }; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -71,6 +71,12 @@ 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, "Cpp14", FormatStyle::LS_Cpp14); + IO.enumCase(Value, "C++14", FormatStyle::LS_Cpp14); + IO.enumCase(Value, "Cpp17", FormatStyle::LS_Cpp17); + IO.enumCase(Value, "C++17", FormatStyle::LS_Cpp17); + IO.enumCase(Value, "Cpp2a", FormatStyle::LS_Cpp2a); + IO.enumCase(Value, "C++2a", FormatStyle::LS_Cpp2a); IO.enumCase(Value, "Auto", FormatStyle::LS_Auto); } }; @@ -2370,10 +2376,15 @@ Style.Standard == FormatStyle::LS_Auto ? FormatStyle::LS_Cpp11 : Style.Standard; LangOpts.CPlusPlus = 1; + // N.B.: For many years clang-format provided the option LS_Cpp11 to mean + // "a modern C++ standard" or "a standard newer than C++03". As a + // result, many users may still be using LS_Cpp11, and they expect + // formatting to occur as if they were using C++14 or C++17. So for + // now, we enable all C++14 and C++17 features for those users. LangOpts.CPlusPlus11 = LexingStd >= FormatStyle::LS_Cpp11; LangOpts.CPlusPlus14 = LexingStd >= FormatStyle::LS_Cpp11; LangOpts.CPlusPlus17 = LexingStd >= FormatStyle::LS_Cpp11; - LangOpts.CPlusPlus2a = LexingStd >= FormatStyle::LS_Cpp11; + LangOpts.CPlusPlus2a = LexingStd >= FormatStyle::LS_Cpp2a; LangOpts.LineComment = 1; bool AlternativeOperators = Style.isCpp(); LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -2862,7 +2862,7 @@ (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.SpacesInAngles); } if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) || Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) || @@ -2881,7 +2881,7 @@ return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment)) return (Left.is(TT_TemplateOpener) && - Style.Standard < FormatStyle::LS_Cpp11) || + Style.Standard == FormatStyle::LS_Cpp03) || !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square, tok::kw___super, TT_TemplateCloser, TT_TemplateOpener)) || diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -3803,10 +3803,13 @@ "if (aaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaa(\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) == 5) {\n" "}"); + + FormatStyle Cpp2a = getLLVMStyle(); + Cpp2a.Standard = FormatStyle::LS_Cpp2a; verifyFormat( "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) <=> 5) {\n" - "}"); + "}", Cpp2a); // Even explicit parentheses stress the precedence enough to make the // additional break unnecessary. verifyFormat("if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n" @@ -3829,7 +3832,7 @@ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <=>\n" " 5) {\n" - "}"); + "}", Cpp2a); FormatStyle OnePerLine = getLLVMStyle(); OnePerLine.BinPackParameters = false; @@ -11839,8 +11842,14 @@ Style.Standard = FormatStyle::LS_Auto; CHECK_PARSE("Standard: Cpp03", Standard, FormatStyle::LS_Cpp03); CHECK_PARSE("Standard: Cpp11", Standard, FormatStyle::LS_Cpp11); + CHECK_PARSE("Standard: Cpp14", Standard, FormatStyle::LS_Cpp14); + CHECK_PARSE("Standard: Cpp17", Standard, FormatStyle::LS_Cpp17); + CHECK_PARSE("Standard: Cpp2a", Standard, FormatStyle::LS_Cpp2a); CHECK_PARSE("Standard: C++03", Standard, FormatStyle::LS_Cpp03); CHECK_PARSE("Standard: C++11", Standard, FormatStyle::LS_Cpp11); + CHECK_PARSE("Standard: C++14", Standard, FormatStyle::LS_Cpp14); + CHECK_PARSE("Standard: C++17", Standard, FormatStyle::LS_Cpp17); + CHECK_PARSE("Standard: C++2a", Standard, FormatStyle::LS_Cpp2a); CHECK_PARSE("Standard: Auto", Standard, FormatStyle::LS_Auto); Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; @@ -13770,6 +13779,18 @@ verifyFormat("auto const &[ a, b ] = f();", Spaces); } +TEST_F(FormatTest, Coroutines) { + FormatStyle Cpp2a = getLLVMStyle(); + Cpp2a.Standard = FormatStyle::LS_Cpp2a; + + // 'co_yield' is treated as an identifier in standards below C++2a, and so + // the increment is interpreted as a postfix on that identifier. + // In C++2a, it is interpreted as a prefix increment on 'it'. + verifyFormat("f(co_yield ++it);", Cpp2a); + + verifyFormat("co_await []() -> g { co_return; }();", Cpp2a); +} + TEST_F(FormatTest, FileAndCode) { EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.cc", "")); EXPECT_EQ(FormatStyle::LK_ObjC, guessLanguage("foo.m", ""));