-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[clang-format] Fix a bug in RemoveParentheses: ReturnStatement #67911
Conversation
Don't remove the outermost parentheses surrounding a return statement expression when inside a function/lambda that has the decltype(auto) return type. Fixed llvm#67892.
@llvm/pr-subscribers-clang-format ChangesDon't remove the outermost parentheses surrounding a return statement expression when inside a function/lambda that has the decltype(auto) return type. Fixed #67892. Full diff: https://github.com/llvm/llvm-project/pull/67911.diff 3 Files Affected:
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index bf38ed73c4a0b4e..dda5fd077e590e5 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 4138baaabe2693d..a4f150d19571266 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<bool, 8> NestedTooDeep;
+ // Keeps a stack of the states of nested lambdas (true if the return type of
+ // the lambda is `decltype(auto)`).
+ SmallVector<bool, 4> 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 0403de8a9a65594..63ef294ce9d2949 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);",
|
oh sorry for merging this @owenca - it was tagged for the 17.x release and I thought it was a PR towards the backport branch so ti wasn't my intention to merge it into main for you. |
@tru np! That was my intention anyways. |
Don't remove the outermost parentheses surrounding a return statement expression when inside a function/lambda that has the decltype(auto) return type.
Fixed #67892.