[clang] [clang][Sema] Skip the RequiresExprBodyDecls for lambda dependencies (PR #83997)

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 6 17:48:53 PST 2024


https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/83997

>From 69414d7352b170f6fcff22c6f5dfa91cc76b0b58 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Tue, 5 Mar 2024 19:56:59 +0800
Subject: [PATCH 1/3] gh56556

---
 clang/lib/Sema/TreeTransform.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 7389a48fe56fcc..c96ffcb97a7591 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13649,10 +13649,12 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
   // use evaluation contexts to distinguish the function parameter case.
   CXXRecordDecl::LambdaDependencyKind DependencyKind =
       CXXRecordDecl::LDK_Unknown;
+  DeclContext *DC = getSema().CurContext;
+  if (DC->getDeclKind() == Decl::Kind::RequiresExprBody)
+    DC = DC->getParent();
   if ((getSema().isUnevaluatedContext() ||
        getSema().isConstantEvaluatedContext()) &&
-      (getSema().CurContext->isFileContext() ||
-       !getSema().CurContext->getParent()->isDependentContext()))
+      (DC->isFileContext() || !DC->getParent()->isDependentContext()))
     DependencyKind = CXXRecordDecl::LDK_NeverDependent;
 
   CXXRecordDecl *OldClass = E->getLambdaClass();

>From b905083e5d5186ad08ac3d553be3e8f47dabc1b6 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Wed, 6 Mar 2024 13:46:43 +0800
Subject: [PATCH 2/3] Tests & release notes

---
 clang/docs/ReleaseNotes.rst                 |  2 +
 clang/lib/Sema/TreeTransform.h              | 17 +++++++
 clang/test/SemaTemplate/concepts-lambda.cpp | 52 +++++++++++++++++++++
 3 files changed, 71 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d4e6bcf661da1a..141099fb68a200 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -302,6 +302,8 @@ Bug Fixes to C++ Support
   our attention by an attempt to fix in (#GH77703). Fixes (#GH83385).
 - Fix evaluation of some immediate calls in default arguments.
   Fixes (#GH80630)
+- Fixed an issue where the ``RequiresExprBody`` was involved in the lambda dependency
+  calculation. (#GH56556), (#GH82849).
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index c96ffcb97a7591..84348e13567e71 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13650,6 +13650,23 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
   CXXRecordDecl::LambdaDependencyKind DependencyKind =
       CXXRecordDecl::LDK_Unknown;
   DeclContext *DC = getSema().CurContext;
+  // A RequiresExprBodyDecl is not interesting for dependencies.
+  // For the following case,
+  //
+  // template <typename>
+  // concept C = requires { [] {}; };
+  //
+  // template <class F>
+  // struct Widget;
+  //
+  // template <C F>
+  // struct Widget<F> {};
+  //
+  // While we are here in substitution for Widget<F>, the parent of DC would be
+  // the template specialization itself. Thus, the lambda expression
+  // will be deemed as dependent even if we have non-dependent template
+  // arguments.
+  // (A ClassTemplateSpecializationDecl is always a dependent context.)
   if (DC->getDeclKind() == Decl::Kind::RequiresExprBody)
     DC = DC->getParent();
   if ((getSema().isUnevaluatedContext() ||
diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp b/clang/test/SemaTemplate/concepts-lambda.cpp
index 0b7580f91043c7..ef04cad4eef98b 100644
--- a/clang/test/SemaTemplate/concepts-lambda.cpp
+++ b/clang/test/SemaTemplate/concepts-lambda.cpp
@@ -90,6 +90,58 @@ struct Foo {
 
 static_assert(ConstructibleWithN<Foo>);
 
+namespace GH56556 {
+
+template <typename It>
+inline constexpr It declare ();
+
+template <typename It, template <typename> typename Template>
+concept D = requires {
+	{ [] <typename T1> (Template<T1> &) {}(declare<It &>()) };
+};
+
+template <typename T>
+struct B {};
+
+template <typename T>
+struct Adapter;
+
+template <D<B> T>
+struct Adapter<T> {};
+
+template struct Adapter<B<int>>;
+
+} // namespace GH56556
+
+namespace GH82849 {
+
+template <class T>
+concept C = requires(T t) {
+  [](T) {}(t);
+};
+
+template <class From>
+struct Widget;
+
+template <C F>
+struct Widget<F> {
+  static F create(F from) {
+    return from;
+  }
+};
+
+template <class>
+bool foo() {
+  return C<int>;
+}
+
+void bar() {
+  // https://github.com/llvm/llvm-project/issues/49570#issuecomment-1664966972
+  Widget<char>::create(0);
+}
+
+} // namespace GH82849
+
 }
 
 // GH60642 reported an assert being hit, make sure we don't assert.

>From 6b36f74b6aede38766674c99a803c86becacd01d Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Wed, 6 Mar 2024 18:56:53 +0800
Subject: [PATCH 3/3] Address Corentin's comments

---
 clang/lib/Sema/TreeTransform.h              | 6 +++---
 clang/test/SemaTemplate/concepts-lambda.cpp | 8 +++++++-
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 84348e13567e71..409aee73d960eb 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13662,12 +13662,12 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
   // template <C F>
   // struct Widget<F> {};
   //
-  // While we are here in substitution for Widget<F>, the parent of DC would be
+  // While we are substituting Widget<F>, the parent of DC would be
   // the template specialization itself. Thus, the lambda expression
-  // will be deemed as dependent even if we have non-dependent template
+  // will be deemed as dependent even if there are no dependent template
   // arguments.
   // (A ClassTemplateSpecializationDecl is always a dependent context.)
-  if (DC->getDeclKind() == Decl::Kind::RequiresExprBody)
+  while (DC->getDeclKind() == Decl::Kind::RequiresExprBody)
     DC = DC->getParent();
   if ((getSema().isUnevaluatedContext() ||
        getSema().isConstantEvaluatedContext()) &&
diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp b/clang/test/SemaTemplate/concepts-lambda.cpp
index ef04cad4eef98b..fac790d09f9cf2 100644
--- a/clang/test/SemaTemplate/concepts-lambda.cpp
+++ b/clang/test/SemaTemplate/concepts-lambda.cpp
@@ -117,7 +117,13 @@ namespace GH82849 {
 
 template <class T>
 concept C = requires(T t) {
-  [](T) {}(t);
+  requires requires (T u) {
+    []<class V>(V) {
+      return requires(V v) {
+        [](V w) {}(v);
+      };
+    }(t);
+  };
 };
 
 template <class From>



More information about the cfe-commits mailing list