diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1311,15 +1311,19 @@ bool InDiscardedStatement; bool InImmediateFunctionContext; + bool InAttributeArgsContext; + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumCleanupObjects, CleanupInfo ParentCleanup, Decl *ManglingContextDecl, - ExpressionKind ExprContext) + ExpressionKind ExprContext, + bool InAttributeArgsContext = false) : Context(Context), ParentCleanup(ParentCleanup), NumCleanupObjects(NumCleanupObjects), NumTypos(0), ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext), - InDiscardedStatement(false), InImmediateFunctionContext(false) {} + InDiscardedStatement(false), InImmediateFunctionContext(false), + InAttributeArgsContext(InAttributeArgsContext) {} bool isUnevaluated() const { return Context == ExpressionEvaluationContext::Unevaluated || @@ -5094,7 +5098,8 @@ void PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, ExpressionEvaluationContextRecord::ExpressionKind Type = - ExpressionEvaluationContextRecord::EK_Other); + ExpressionEvaluationContextRecord::EK_Other, + bool InAttributeArgs = false); enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; void PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, @@ -13263,11 +13268,11 @@ Decl *LambdaContextDecl = nullptr, Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = Sema::ExpressionEvaluationContextRecord::EK_Other, - bool ShouldEnter = true) + bool ShouldEnter = true, bool InAttributeArgs = false) : Actions(Actions), Entered(ShouldEnter) { if (Entered) Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, - ExprContext); + ExprContext, InAttributeArgs); } EnterExpressionEvaluationContext( Sema &Actions, Sema::ExpressionEvaluationContext NewContext, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -444,9 +444,11 @@ // General case. Parse all available expressions. bool Uneval = attributeParsedArgsUnevaluated(*AttrName); EnterExpressionEvaluationContext Unevaluated( - Actions, Uneval - ? Sema::ExpressionEvaluationContext::Unevaluated - : Sema::ExpressionEvaluationContext::ConstantEvaluated); + Actions, + Uneval ? Sema::ExpressionEvaluationContext::Unevaluated + : Sema::ExpressionEvaluationContext::ConstantEvaluated, + nullptr, Sema::ExpressionEvaluationContextRecord::EK_Other, true, + /* InAttributeArgs = */ true); CommaLocsTy CommaLocs; ExprVector ParsedExprs; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2031,6 +2031,8 @@ !isCapturingReferenceToHostVarInCUDADeviceLambda(*this, VD) && VD->isUsableInConstantExpressions(Context)) return NOUR_Constant; + if (ExprEvalContexts.back().InAttributeArgsContext) + return NOUR_Constant; } // All remaining non-variable cases constitute an odr-use. For variables, we @@ -16932,12 +16934,13 @@ return TransformToPE(*this).TransformType(TInfo); } -void -Sema::PushExpressionEvaluationContext( +void Sema::PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl, - ExpressionEvaluationContextRecord::ExpressionKind ExprContext) { + ExpressionEvaluationContextRecord::ExpressionKind ExprContext, + bool InAttributeArgs) { ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup, - LambdaContextDecl, ExprContext); + LambdaContextDecl, ExprContext, + InAttributeArgs); // Discarded statements and immediate contexts nested in other // discarded statements or immediate context are themselves diff --git a/clang/test/SemaCXX/attr-on-lambda.cpp b/clang/test/SemaCXX/attr-on-lambda.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/attr-on-lambda.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// expected-no-diagnostics + +constexpr int get(const int A) { return A; } + +struct MyStruct { + const int Member = get(1); +}; + +void foo() { + + const int I = 10; + constexpr MyStruct S = {1}; + auto Outer = [=]() { + auto Inner1 = [&](int k) __attribute__((enable_if(I > k, "nope"))){}; + + auto Inner2 = [=]() __attribute__((enable_if(S.Member, "nope"))){}; + + auto Inner3 = [&](int k) __attribute__((enable_if(k > get(I), "nope"))){}; + }; +} +