Fznamznon created this revision.
Herald added a project: All.
Fznamznon requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Attribute arguments are always compile-time expressions that need to be
evaluated. So, it is not necessary to treat attribute use as ODR use.

Treatment of use from attribute aruments as ODR use had a side
effect in incorrect processing of attributes applied to nested lambdas.
That happened because ODR use from attribute applied to a lambda forced
Sema to check if used variable is correctly captured.
For the following example:

  const int I = 10;
  auto OL = [=] () {
    auto IL = [&](int K) __attribute__((enable_if(I > K, "..."))) {};
  };

when capture-checking function was validating use of either variable `I` or
parameter `K` the error "variable cannot be implicitly captured in a lambda with
no capture-default specified" was emitted. That happened due to the
following order of actions during lambda parsing: first, an empty lambda scope
is pushed to `FunctionScopes` collection in `Sema`, then the attributes on
lambdas are handled, and only after that the info about inner lambda capturing
style is saved to a corresponding lambda scope. So, at the point when
attributes on inner lambda are handled, capture-checking function thinks
that it is already inside the inner lambda and it doesn't have capturing
style, so the error was emitted.

This patch makes this error go away.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122494

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/attr-on-lambda.cpp

Index: clang/test/SemaCXX/attr-on-lambda.cpp
===================================================================
--- /dev/null
+++ 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"))){};
+  };
+}
+
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ 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
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ 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;
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ 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,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to