diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index bf38ed73c4a0b..dda5fd077e590 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -173,10 +173,12 @@ void UnwrappedLineParser::reset() { CommentsBeforeNextToken.clear(); FormatTok = nullptr; MustBreakBeforeNextToken = false; + IsDecltypeAutoFunction = false; PreprocessorDirectives.clear(); CurrentLines = &Lines; DeclarationScopeStack.clear(); NestedTooDeep.clear(); + NestedLambdas.clear(); PPStack.clear(); Line->FirstStartColumn = FirstStartColumn; @@ -1766,6 +1768,17 @@ void UnwrappedLineParser::parseStructuralElement( if (parseStructLike()) return; break; + case tok::kw_decltype: + nextToken(); + if (FormatTok->is(tok::l_paren)) { + parseParens(); + assert(FormatTok->Previous); + if (FormatTok->Previous->endsSequence(tok::r_paren, tok::kw_auto, + tok::l_paren)) { + Line->SeenDecltypeAuto = true; + } + } + break; case tok::period: nextToken(); // In Java, classes have an implicit static member "class". @@ -1827,6 +1840,7 @@ void UnwrappedLineParser::parseStructuralElement( if (InRequiresExpression) FormatTok->setFinalizedType(TT_BracedListLBrace); if (!tryToParsePropertyAccessor() && !tryToParseBracedList()) { + IsDecltypeAutoFunction = Line->SeenDecltypeAuto; // A block outside of parentheses must be the last part of a // structural element. // FIXME: Figure out cases where this is not true, and add projections @@ -1844,6 +1858,7 @@ void UnwrappedLineParser::parseStructuralElement( } FormatTok->setFinalizedType(TT_FunctionLBrace); parseBlock(); + IsDecltypeAutoFunction = false; addUnwrappedLine(); return; } @@ -2249,9 +2264,15 @@ bool UnwrappedLineParser::tryToParseLambda() { return true; } } + FormatTok->setFinalizedType(TT_LambdaLBrace); LSquare.setFinalizedType(TT_LambdaLSquare); + + NestedLambdas.push_back(Line->SeenDecltypeAuto); parseChildBlock(); + assert(!NestedLambdas.empty()); + NestedLambdas.pop_back(); + return true; } @@ -2469,6 +2490,8 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) { PrevPrev->endsSequence(tok::kw_constexpr, tok::kw_if)))); const bool ReturnParens = Style.RemoveParentheses == FormatStyle::RPS_ReturnStatement && + ((NestedLambdas.empty() && !IsDecltypeAutoFunction) || + (!NestedLambdas.empty() && !NestedLambdas.back())) && Prev && Prev->isOneOf(tok::kw_return, tok::kw_co_return) && Next && Next->is(tok::semi); if ((DoubleParens && !Blacklisted) || ReturnParens) { @@ -4379,6 +4402,7 @@ void UnwrappedLineParser::addUnwrappedLine(LineLevel AdjustLevel) { Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex; Line->FirstStartColumn = 0; Line->IsContinuation = false; + Line->SeenDecltypeAuto = false; if (ClosesWhitesmithsBlock && AdjustLevel == LineLevel::Remove) --Line->Level; diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 4138baaabe269..a4f150d195712 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -61,6 +61,9 @@ struct UnwrappedLine { bool MustBeDeclaration = false; + /// Whether the parser has seen \c decltype(auto) in this line. + bool SeenDecltypeAuto = false; + /// \c True if this line should be indented by ContinuationIndent in /// addition to the normal indention level. bool IsContinuation = false; @@ -335,6 +338,14 @@ class UnwrappedLineParser { // statement contains more than some predefined number of nested statements). SmallVector NestedTooDeep; + // Keeps a stack of the states of nested lambdas (true if the return type of + // the lambda is `decltype(auto)`). + SmallVector NestedLambdas; + + // Whether the parser is parsing the body of a function whose return type is + // `decltype(auto)`. + bool IsDecltypeAutoFunction = false; + // Represents preprocessor branch type, so we can find matching // #if/#else/#endif directives. enum PPBranchKind { diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 0403de8a9a655..63ef294ce9d29 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -26305,6 +26305,56 @@ TEST_F(FormatTest, RemoveParentheses) { verifyFormat("co_return 0;", "co_return ((0));", Style); verifyFormat("return 0;", "return (((0)));", Style); verifyFormat("return ({ 0; });", "return ((({ 0; })));", Style); + verifyFormat("inline decltype(auto) f() {\n" + " if (a) {\n" + " return (a);\n" + " }\n" + " return (b);\n" + "}", + "inline decltype(auto) f() {\n" + " if (a) {\n" + " return ((a));\n" + " }\n" + " return ((b));\n" + "}", + Style); + verifyFormat("auto g() {\n" + " decltype(auto) x = [] {\n" + " auto y = [] {\n" + " if (a) {\n" + " return a;\n" + " }\n" + " return b;\n" + " };\n" + " if (c) {\n" + " return (c);\n" + " }\n" + " return (d);\n" + " };\n" + " if (e) {\n" + " return e;\n" + " }\n" + " return f;\n" + "}", + "auto g() {\n" + " decltype(auto) x = [] {\n" + " auto y = [] {\n" + " if (a) {\n" + " return ((a));\n" + " }\n" + " return ((b));\n" + " };\n" + " if (c) {\n" + " return ((c));\n" + " }\n" + " return ((d));\n" + " };\n" + " if (e) {\n" + " return ((e));\n" + " }\n" + " return ((f));\n" + "}", + Style); Style.ColumnLimit = 25; verifyFormat("return (a + b) - (c + d);",