https://github.com/StefanPaulet updated https://github.com/llvm/llvm-project/pull/211811
>From 9bb556e0041bad23057343ff227aac711871463e Mon Sep 17 00:00:00 2001 From: StefanPaulet <[email protected]> Date: Mon, 20 Jul 2026 17:38:02 +0300 Subject: [PATCH 1/5] 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 <[email protected]> Date: Fri, 24 Jul 2026 17:45:42 +0300 Subject: [PATCH 2/5] 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 >From 69f3bc776864f88c938f0fbce7da9d2837a7f36f Mon Sep 17 00:00:00 2001 From: StefanPaulet <[email protected]> Date: Sat, 25 Jul 2026 17:00:19 +0300 Subject: [PATCH 3/5] Addressed review comment --- clang/include/clang/Sema/ScopeInfo.h | 2 +- clang/lib/Sema/SemaLambda.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index 8fccad70eb9dd..8dc40a5bc58bd 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -879,7 +879,7 @@ class LambdaScopeInfo final : /// is known. bool AfterParameterList = true; - bool BeforeCompoundStatement = false; + bool BeforeCompoundStatement = true; ParmVarDecl *ExplicitObjectParameter = nullptr; diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index a580fbbd33cf1..bbe93f6ab8a40 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -1436,7 +1436,6 @@ void Sema::ActOnLambdaClosureParameters( TemplateParams->containsUnexpandedParameterPack(); } LSI->AfterParameterList = true; - LSI->BeforeCompoundStatement = true; } void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, >From c93c24dcbc721017e0e4d9c9068182de642fe80f Mon Sep 17 00:00:00 2001 From: StefanPaulet <[email protected]> Date: Sat, 25 Jul 2026 18:18:10 +0300 Subject: [PATCH 4/5] Addressed review comment --- clang/lib/Sema/SemaExpr.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e936fdf1f8fc0..1066a337f2012 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2117,14 +2117,28 @@ static PredefinedIdentKind getPredefinedExprKind(tok::TokenKind Kind) { /// to determine the value of a PredefinedExpr. This can be either a /// block, lambda, captured statement, function, otherwise a nullptr. static Decl *getPredefinedExprDecl(Sema &S, DeclContext *DC) { - if (isLambdaCallOperator(DC)) { - LambdaScopeInfo *LSI = S.getCurLambda(); - if (LSI->BeforeCompoundStatement) { - DC = DC->getParent(); + auto LSI = S.FunctionScopes.rbegin(); + + auto tryAdjustLambdaContext = [&S, &LSI](DeclContext *&DC) { + if (isLambdaCallOperator(DC)) { + auto E = S.FunctionScopes.rend(); + while (LSI != E && isa<CapturingScopeInfo>(*LSI) && + !isa<LambdaScopeInfo>(*LSI)) + ++LSI; + assert(LSI != E && "Should be in a lambda scope info"); + if (dyn_cast<LambdaScopeInfo>(*LSI)->BeforeCompoundStatement) + DC = DC->getParent(); + ++LSI; } - } - while (DC && !isa<BlockDecl, CapturedDecl, FunctionDecl, ObjCMethodDecl>(DC)) + }; + + tryAdjustLambdaContext(DC); + while (DC && + !isa<BlockDecl, CapturedDecl, FunctionDecl, ObjCMethodDecl>(DC)) { DC = DC->getParent(); + tryAdjustLambdaContext(DC); + } + return cast_or_null<Decl>(DC); } >From 19a38795768a94998d16045561d0c0389f714219 Mon Sep 17 00:00:00 2001 From: StefanPaulet <[email protected]> Date: Sun, 26 Jul 2026 16:06:18 +0300 Subject: [PATCH 5/5] Fixed error on template lambdas found from libcxx tests --- clang/lib/Sema/SemaDecl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7de5542e72559..0d0229940d783 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16260,6 +16260,7 @@ LambdaScopeInfo *Sema::RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator) { // substituting into it. In this case the flag needs to be true such that // tryCaptureVariable can correctly handle potential captures thereof. LSI->AfterParameterList = CurContext == CallOperator; + LSI->BeforeCompoundStatement = false; // GLTemplateParameterList is necessary for getCurGenericLambda() which is // used at the point of dealing with potential captures. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
