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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
