[clang] [clang] reject to capture variable in `RequiresExprBodyDecl` (PR #78598)

Congcong Cai via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 19 21:56:24 PST 2024


https://github.com/HerrCai0907 updated https://github.com/llvm/llvm-project/pull/78598

>From 8fa3dc43e770025308da47f6aff309fa58c47fc3 Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Thu, 18 Jan 2024 23:12:23 +0800
Subject: [PATCH 1/3] [clang] reject to capture variable in
 `RequiresExprBodyDecl`

Expression in `RequiresExprBodyDecl` is resolved as constants and should not be captured.
Fixes: #69307, #76593.
---
 clang/lib/Sema/SemaExpr.cpp                   | 21 ++++++++++------
 ...uires-expression-with-capture-variable.cpp | 25 +++++++++++++++++++
 2 files changed, 38 insertions(+), 8 deletions(-)
 create mode 100644 clang/test/SemaCXX/requires-expression-with-capture-variable.cpp

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 6413a48f809ac9c..580e759f634956b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -19704,6 +19704,12 @@ static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI,
   }
 }
 
+static DeclContext *ignoreReuquiresBodyDecl(DeclContext *DC) {
+  if (isa_and_present<RequiresExprBodyDecl>(DC))
+    return DC->getParent();
+  return DC;
+}
+
 bool Sema::tryCaptureVariable(
     ValueDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
     SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType,
@@ -19711,15 +19717,15 @@ bool Sema::tryCaptureVariable(
   // An init-capture is notionally from the context surrounding its
   // declaration, but its parent DC is the lambda class.
   DeclContext *VarDC = Var->getDeclContext();
-  DeclContext *DC = CurContext;
-
   // tryCaptureVariable is called every time a DeclRef is formed,
   // it can therefore have non-negigible impact on performances.
   // For local variables and when there is no capturing scope,
   // we can bailout early.
-  if (CapturingFunctionScopes == 0 && (!BuildAndDiagnose || VarDC == DC))
+  if (CapturingFunctionScopes == 0 && (!BuildAndDiagnose || VarDC == CurContext))
     return true;
 
+  DeclContext *DC = ignoreReuquiresBodyDecl(CurContext);
+
   const auto *VD = dyn_cast<VarDecl>(Var);
   if (VD) {
     if (VD->isInitCapture())
@@ -19789,11 +19795,10 @@ bool Sema::tryCaptureVariable(
 
     // Only block literals, captured statements, and lambda expressions can
     // capture; other scopes don't work.
-    DeclContext *ParentDC =
-        !IsInScopeDeclarationContext
-            ? DC->getParent()
-            : getParentOfCapturingContextOrNull(DC, Var, ExprLoc,
-                                                BuildAndDiagnose, *this);
+    DeclContext *ParentDC = IsInScopeDeclarationContext
+                                ? getParentOfCapturingContextOrNull(
+                                      DC, Var, ExprLoc, BuildAndDiagnose, *this)
+                                : DC->getParent();
     // We need to check for the parent *first* because, if we *have*
     // private-captured a global variable, we need to recursively capture it in
     // intermediate blocks, lambdas, etc.
diff --git a/clang/test/SemaCXX/requires-expression-with-capture-variable.cpp b/clang/test/SemaCXX/requires-expression-with-capture-variable.cpp
new file mode 100644
index 000000000000000..d01a54133f6c39b
--- /dev/null
+++ b/clang/test/SemaCXX/requires-expression-with-capture-variable.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang -fsyntax-only -std=c++20 -Xclang -verify %s
+
+// expected-no-diagnostics
+
+auto GH69307_Func_1() {
+  constexpr auto b = 1;
+  return [&](auto c) -> int
+           requires requires { b + c; }
+  { return 1; };
+};
+auto GH69307_Func_Ret = GH69307_Func_1()(1);
+
+auto GH69307_Lambda_1 = []() {
+  return [&](auto c) -> int
+           requires requires { c; }
+  { return 1; };
+};
+auto GH69307_Lambda_1_Ret = GH69307_Lambda_1()(1);
+
+auto GH69307_Lambda_2 = [](auto c) {
+  return [&]() -> int
+           requires requires { c; }
+  { return 1; };
+};
+auto GH69307_Lambda_2_Ret = GH69307_Lambda_2(1)();

>From a99f16ff51702ff249cdf8a47de0cf24a08f694a Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Sat, 20 Jan 2024 13:40:12 +0800
Subject: [PATCH 2/3] another test

---
 clang/test/SemaCXX/warn-unused-lambda-capture-cxx20.cpp | 7 +++++++
 clang/test/SemaCXX/warn-unused-lambda-capture.cpp       | 4 ++++
 2 files changed, 11 insertions(+)
 create mode 100644 clang/test/SemaCXX/warn-unused-lambda-capture-cxx20.cpp

diff --git a/clang/test/SemaCXX/warn-unused-lambda-capture-cxx20.cpp b/clang/test/SemaCXX/warn-unused-lambda-capture-cxx20.cpp
new file mode 100644
index 000000000000000..b787edb188ed8b5
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unused-lambda-capture-cxx20.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-lambda-capture -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++20 %s
+
+void test() {
+  int i;
+  auto explicit_by_value_unused_requires = [i] (auto) requires requires { i; } {}; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
+  explicit_by_value_unused_requires(1);
+}
diff --git a/clang/test/SemaCXX/warn-unused-lambda-capture.cpp b/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
index 73459496e4cd9a7..98a3f4623098af6 100644
--- a/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
+++ b/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
@@ -44,6 +44,10 @@ void test() {
   auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
   auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
   auto explicit_by_value_unused_const = [k] { return k + 1; };         // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
+#if __cplusplus >= 202002L
+  auto explicit_by_value_unused_requires = [i] (auto) requires requires { i; } {}; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
+  explicit_by_value_unused_requires(1);
+#endif
 
   auto explicit_by_reference_used = [&i] { i++; };
   auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}}

>From b27d0ac058ca00257c42a3e2598b4701c8ae812d Mon Sep 17 00:00:00 2001
From: Congcong Cai <congcongcai0907 at 163.com>
Date: Sat, 20 Jan 2024 13:56:10 +0800
Subject: [PATCH 3/3] format

---
 clang/lib/Sema/SemaExpr.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 580e759f634956b..04cfe5435eb231d 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -19721,7 +19721,8 @@ bool Sema::tryCaptureVariable(
   // it can therefore have non-negigible impact on performances.
   // For local variables and when there is no capturing scope,
   // we can bailout early.
-  if (CapturingFunctionScopes == 0 && (!BuildAndDiagnose || VarDC == CurContext))
+  if (CapturingFunctionScopes == 0 &&
+      (!BuildAndDiagnose || VarDC == CurContext))
     return true;
 
   DeclContext *DC = ignoreReuquiresBodyDecl(CurContext);



More information about the cfe-commits mailing list