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", ""));