[clang] [clang] Fixed predefined expressions after lambda parameters (PR #211811)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 24 07:45:57 PDT 2026
https://github.com/StefanPaulet updated https://github.com/llvm/llvm-project/pull/211811
>From 9bb556e0041bad23057343ff227aac711871463e Mon Sep 17 00:00:00 2001
From: StefanPaulet <tudor.stefan.paulet at gmail.com>
Date: Mon, 20 Jul 2026 17:38:02 +0300
Subject: [PATCH 1/2] Fixed predefined expressions after lambda parameters
---
clang/include/clang/Sema/ScopeInfo.h | 2 ++
clang/lib/Sema/SemaExpr.cpp | 12 +++++--
clang/lib/Sema/SemaLambda.cpp | 2 ++
clang/lib/Sema/TreeTransform.h | 2 ++
clang/test/SemaCXX/GH122657.cpp | 49 ++++++++++++++++++++++++++++
5 files changed, 64 insertions(+), 3 deletions(-)
create mode 100644 clang/test/SemaCXX/GH122657.cpp
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index 7e4d3f2e0d1cb..a7a98e56b25ec 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -874,6 +874,8 @@ class LambdaScopeInfo final :
/// is known.
bool AfterParameterList = true;
+ bool BeforeCompoundStatement = false;
+
ParmVarDecl *ExplicitObjectParameter = nullptr;
/// Source range covering the lambda introducer [...].
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 592cb1d588370..0a9b02af8a8dd 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2114,7 +2114,13 @@ static PredefinedIdentKind getPredefinedExprKind(tok::TokenKind Kind) {
/// getPredefinedExprDecl - Returns Decl of a given DeclContext that can be used
/// to determine the value of a PredefinedExpr. This can be either a
/// block, lambda, captured statement, function, otherwise a nullptr.
-static Decl *getPredefinedExprDecl(DeclContext *DC) {
+static Decl *getPredefinedExprDecl(Sema &S, DeclContext *DC) {
+ if (isLambdaCallOperator(DC)) {
+ LambdaScopeInfo *LSI = S.getCurLambda();
+ if (LSI->BeforeCompoundStatement) {
+ DC = DC->getParent();
+ }
+ }
while (DC && !isa<BlockDecl, CapturedDecl, FunctionDecl, ObjCMethodDecl>(DC))
DC = DC->getParent();
return cast_or_null<Decl>(DC);
@@ -2200,7 +2206,7 @@ Sema::ExpandFunctionLocalPredefinedMacros(ArrayRef<Token> Toks) {
// Note: Although function local macros are defined only inside functions,
// we ensure a valid `CurrentDecl` even outside of a function. This allows
// expansion of macros into empty string literals without additional checks.
- Decl *CurrentDecl = getPredefinedExprDecl(CurContext);
+ Decl *CurrentDecl = getPredefinedExprDecl(*this, CurContext);
if (!CurrentDecl)
CurrentDecl = Context.getTranslationUnitDecl();
@@ -3627,7 +3633,7 @@ static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
PredefinedIdentKind IK) {
- Decl *currentDecl = getPredefinedExprDecl(CurContext);
+ Decl *currentDecl = getPredefinedExprDecl(*this, CurContext);
if (!currentDecl) {
Diag(Loc, diag::ext_predef_outside_function);
currentDecl = Context.getTranslationUnitDecl();
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 8572e3a742a6c..0fb4e1fa92d99 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1436,6 +1436,7 @@ void Sema::ActOnLambdaClosureParameters(
TemplateParams->containsUnexpandedParameterPack();
}
LSI->AfterParameterList = true;
+ LSI->BeforeCompoundStatement = true;
}
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
@@ -1444,6 +1445,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
LambdaScopeInfo *LSI = getCurrentLambdaScopeUnsafe(*this);
LSI->CallOperator->setConstexprKind(DS.getConstexprSpecifier());
+ LSI->BeforeCompoundStatement = false;
SmallVector<ParmVarDecl *, 8> Params;
bool ExplicitResultType;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 3c8fcbe582b43..df2c0429ef7e0 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -16077,6 +16077,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
TPL->containsUnexpandedParameterPack();
}
+ LSI->BeforeCompoundStatement = true;
TypeLocBuilder NewCallOpTLBuilder;
TypeLoc OldCallOpTypeLoc =
E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
@@ -16101,6 +16102,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
!TRC.ArgPackSubstIndex)
TRC.ArgPackSubstIndex = SemaRef.ArgPackSubstIndex;
+ LSI->BeforeCompoundStatement = false;
getSema().CompleteLambdaCallOperator(
NewCallOperator, E->getCallOperator()->getLocation(),
E->getCallOperator()->getInnerLocStart(), TRC, NewCallOpTSI,
diff --git a/clang/test/SemaCXX/GH122657.cpp b/clang/test/SemaCXX/GH122657.cpp
new file mode 100644
index 0000000000000..1faca88bf3a77
--- /dev/null
+++ b/clang/test/SemaCXX/GH122657.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -x c++ -std=c++11 -fblocks -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+template <unsigned long long n>
+struct Sized {
+ char data[n];
+};
+
+template <typename T>
+int baz() {
+ static constexpr auto funcSize = sizeof(__func__);
+ static constexpr auto functionSize = sizeof(__FUNCTION__);
+ static constexpr auto prettySize = sizeof(__PRETTY_FUNCTION__);
+
+ auto lfunc = []() noexcept(sizeof(__func__) == funcSize) -> Sized<sizeof(__func__)> { return {}; };
+ auto lfunction = []() noexcept(sizeof(__FUNCTION__) == functionSize) -> Sized<sizeof(__FUNCTION__)> { return {}; };
+ auto lpretty = []() noexcept(sizeof(__PRETTY_FUNCTION__) == prettySize) -> Sized<sizeof(__PRETTY_FUNCTION__)> { return {}; };
+
+ static_assert(sizeof(lfunc()) == 5, "baz");
+ static_assert(noexcept(lfunc()) == true, "noexcept");
+
+ static_assert(sizeof(lfunction()) == 5, "baz");
+ static_assert(noexcept(lfunction()) == true, "noexcept");
+
+ static_assert(sizeof(lpretty()) == 33, "int baz() [T = int]_block_invoke");
+ static_assert(noexcept(lpretty()) == true, "noexcept");
+
+ return 0;
+}
+
+int main() {
+ static constexpr auto funcSize = sizeof(__func__);
+ static constexpr auto functionSize = sizeof(__FUNCTION__);
+ static constexpr auto prettySize = sizeof(__PRETTY_FUNCTION__);
+
+ auto lfunc = []() noexcept(sizeof(__func__) == funcSize) -> Sized<sizeof(__func__)> { return {}; };
+ auto lfunction = []() noexcept(sizeof(__FUNCTION__) == functionSize) -> Sized<sizeof(__FUNCTION__)> { return {}; };
+ auto lpretty = []() noexcept(sizeof(__PRETTY_FUNCTION__) == prettySize) -> Sized<sizeof(__PRETTY_FUNCTION__)> { return {}; };
+
+ static_assert(sizeof(lfunc()) == 5, "main");
+ static_assert(noexcept(lfunc()) == true, "noexcept");
+
+ static_assert(sizeof(lfunction()) == 5, "main");
+ static_assert(noexcept(lfunction()) == true, "noexcept");
+
+ static_assert(sizeof(lpretty()) == 11, "int main()");
+ static_assert(noexcept(lpretty()) == true, "noexcept");
+}
+
>From aa5f7c86cecfef9e4ea967426e978b26fbcc7eb2 Mon Sep 17 00:00:00 2001
From: StefanPaulet <tudor.stefan.paulet at gmail.com>
Date: Fri, 24 Jul 2026 17:45:42 +0300
Subject: [PATCH 2/2] Added release note
---
clang/docs/ReleaseNotes.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 83a2b10d96046..8840286927a68 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -338,6 +338,7 @@ features cannot lower the translation-unit ABI level;
- Fixed a constraint comparison bug in partial ordering. (#GH182671)
- Fixed a rejected-valid case that used an explicit object parameter in an out-of-line definition of a nested class member. (#GH136472)
+- Fixed a bug where `__func__`, `__PRETTY_FUNCTION__` and `__FUNCTION__` were not resolving to the proper function when inside a lambda return type (#GH211811)
#### Bug Fixes to Compiler Builtins
More information about the cfe-commits
mailing list