[clang] [Clang] Fix incorrect mutability of decltype((x)) in lambda return types (PR #180690)
Samrudh Nelli via cfe-commits
cfe-commits at lists.llvm.org
Sun Feb 15 00:33:54 PST 2026
https://github.com/SamrudhNelli updated https://github.com/llvm/llvm-project/pull/180690
>From e6344701149989a2f40973c6b76c7b2fb398215c Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <samrudhnelli at gmail.com>
Date: Tue, 10 Feb 2026 12:32:45 +0530
Subject: [PATCH 1/2] [Clang] Fix incorrect mutability of decltype((x)) in
lambda return types
Previously, the parser did not update the lambda's mutability state
before parsing the trailing return type. This caused decltype((x))
to incorrectly deduce a non-const reference even in a non-mutable lambda.
---
clang/docs/ReleaseNotes.rst | 2 ++
clang/lib/Parse/ParseExprCXX.cpp | 3 +++
clang/test/SemaCXX/lambda-expressions.cpp | 13 +++++++++++++
3 files changed, 18 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a1bb1bd2467b7..f7a1a97cc1caf 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -262,6 +262,8 @@ Bug Fixes to C++ Support
- Fixed a crash when instantiating ``requires`` expressions involving substitution failures in C++ concepts. (#GH176402)
- Fixed a crash when a default argument is passed to an explicit object parameter. (#GH176639)
- Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741)
+- Fixed a bug where captured variables in non-mutable lambdas were incorrectly treated as mutable
+ when used inside decltype in the return type. (#GH180460)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 842b52375eb14..0fb050cce329c 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1383,6 +1383,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS);
addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
+ if (clang::sema::LambdaScopeInfo *LSI = Actions.getCurLambda()) {
+ LSI->Mutable = MutableLoc.isValid();
+ }
}
Actions.ActOnLambdaClosureParameters(getCurScope(), ParamInfo);
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp
index f9d7cfcbbd18d..ee6ae81107082 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -799,3 +799,16 @@ template auto t::operator()<int>(int a) const; // expected-note {{in instantiati
}
#endif
+
+namespace GH180460 {
+// Trailing return type incorrectly treated 'x' as mutable.
+void test_lambda_return_type() {
+ float x = 0.0f;
+
+ [=]() -> decltype((x)) {
+ decltype(x) y1 = x;
+ decltype((x)) y2 = y1; // expected-note{{binding reference variable 'y2' here}}
+ return y2; // expected-warning{{reference to stack memory associated with local variable 'y1' returned}}
+ };
+}
+}
\ No newline at end of file
>From bc3fb547bf24996aa86a93914632f8e8f5679092 Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <samrudhnelli at gmail.com>
Date: Wed, 11 Feb 2026 00:17:00 +0530
Subject: [PATCH 2/2] fix: run ActonLambdaClosureQualifiers before parsing
return type
---
clang/lib/Parse/ParseExprCXX.cpp | 13 +++++--------
clang/test/SemaCXX/lambda-expressions.cpp | 2 +-
2 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 0fb050cce329c..b3d50daf66b10 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1383,9 +1383,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS);
addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
- if (clang::sema::LambdaScopeInfo *LSI = Actions.getCurLambda()) {
- LSI->Mutable = MutableLoc.isValid();
- }
}
Actions.ActOnLambdaClosureParameters(getCurScope(), ParamInfo);
@@ -1420,6 +1417,11 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
ConsumeToken();
}
+ // We have called ActOnLambdaClosureQualifiers for parentheses-less cases
+ // above.
+ if (HasParentheses)
+ Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc);
+
SourceLocation FunLocalRangeEnd = DeclEndLoc;
// Parse trailing-return-type[opt].
@@ -1448,11 +1450,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
TrailingReturnType, TrailingReturnTypeLoc, &DS),
std::move(Attributes), DeclEndLoc);
- // We have called ActOnLambdaClosureQualifiers for parentheses-less cases
- // above.
- if (HasParentheses)
- Actions.ActOnLambdaClosureQualifiers(Intro, MutableLoc);
-
if (HasParentheses && Tok.is(tok::kw_requires))
ParseTrailingRequiresClause(D);
}
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp
index ee6ae81107082..00c52efb78a7d 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -811,4 +811,4 @@ void test_lambda_return_type() {
return y2; // expected-warning{{reference to stack memory associated with local variable 'y1' returned}}
};
}
-}
\ No newline at end of file
+}
More information about the cfe-commits
mailing list