[clang] [clang] Fixed predefined expressions after lambda parameters (PR #211811)

via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 24 07:36:50 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: StefanPaulet

<details>
<summary>Changes</summary>

After the parameter declaration of a lambda expression, `Sema` enters the declaration context of the lambda call operator (in `ActOnLambdaClosureParameters`), so the lambda specifiers and the trailing return type are analyzed within that context. Because of this, predefined expressions such as `__func__` resolve to the lambda call operator, and not to the possibly enclosing function. (issue #<!-- -->122657)

Added a member to `LambdaScopeInfo` to mark whether or not the compound statement of the lambda expression has been entered, to be used when resolving a `PredefinedExpr`

---
Full diff: https://github.com/llvm/llvm-project/pull/211811.diff


5 Files Affected:

- (modified) clang/include/clang/Sema/ScopeInfo.h (+2) 
- (modified) clang/lib/Sema/SemaExpr.cpp (+9-3) 
- (modified) clang/lib/Sema/SemaLambda.cpp (+2) 
- (modified) clang/lib/Sema/TreeTransform.h (+2) 
- (added) clang/test/SemaCXX/GH122657.cpp (+49) 


``````````diff
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index 9514dead33f69..8fccad70eb9dd 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -879,6 +879,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 67d9ac4ad5cff..e936fdf1f8fc0 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2116,7 +2116,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);
@@ -2202,7 +2208,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();
 
@@ -3629,7 +3635,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 aa587e25bba27..a580fbbd33cf1 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 0f6f168d06812..3e75753c4c098 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -16312,6 +16312,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
         TPL->containsUnexpandedParameterPack();
   }
 
+  LSI->BeforeCompoundStatement = true;
   TypeLocBuilder NewCallOpTLBuilder;
   TypeLoc OldCallOpTypeLoc =
       E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
@@ -16338,6 +16339,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
     TRC.ConstraintExpr = E.get();
   }
 
+  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");
+}
+

``````````

</details>


https://github.com/llvm/llvm-project/pull/211811


More information about the cfe-commits mailing list