llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: 刘雨培 (LYP951018)

<details>
<summary>Changes</summary>

The code that causes the bug:

```cpp
template&lt;class T&gt; concept Q = requires(T t) { [](int*){}(t); };
struct A { template&lt;class T&gt; explicit(Q&lt;T&gt;) A(T); };
A a = 1;
```

When instantiating a lambda, the calculation of the lambda's dependency occurs 
in roughly two places (part of which this PR addresses):

1. `TransformLambdaExpr`:

    ```cpp
      if ((getSema().isUnevaluatedContext() ||
       getSema().isConstantEvaluatedContext()) &amp;&amp;
      (getSema().CurContext-&gt;isFileContext() ||
       !getSema().CurContext-&gt;getParent()-&gt;isDependentContext()))
        DependencyKind = CXXRecordDecl::LDK_NeverDependent;
    ```

   When instantiating the explicit specifier, it decides whether this lambda is 
dependent based on the parent context of the current context. For the situation 
in the issue, the `CurContext` of the lambda in `Q` is `RequiresExprBodyDecl`, 
and the parent is `CXXConstructorDecl`. However, since the parent's 
`CXXConstructorDecl` is the uninstantiated `CXXConstructorDecl`, it does not 
correctly set `DependencyKind` to `LDK_NeverDependent`.

2. When constructing the type of the lambda expression, it uses 
`DeclContext::isDependentContext` to determine whether the current lambda type 
is dependent. The current `DeclContext::isDependentContext` implementation does 
not handle `RequiresExprBodyDecl` (it seems that it is unable to calculate the 
dependency of `RequiresExprBodyDecl`), and it delegates to the parent, at which 
point the problem returns to step 1.

This ultimately leads to clang considering the expression as value dependent, 
causing an assertion failure. This PR sets CurContext to the instantiated 
constructor when instantiating the explicit specifier, so that the lambda in 
the explicit specifier can correctly calculate dependencies.

NOTE: This PR modifies the function that was added in #<!-- -->70548.

Fixes #<!-- -->67058.

---
Full diff: https://github.com/llvm/llvm-project/pull/78053.diff


3 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+3) 
- (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+1) 
- (modified) clang/test/SemaCXX/cxx2a-explicit-bool.cpp (+18) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f5159cdc8a3bff..a7b954b9d4b09b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -848,6 +848,9 @@ Bug Fixes to C++ Support
   completes (except deduction guides). Fixes:
   (`#59827 <https://github.com/llvm/llvm-project/issues/59827>`_)
 
+- Fixed the handling of concepts with lambda expression constraints in 
explicit specifiers. 
+  Fixes: (`#67058 <https://github.com/llvm/llvm-project/issues/67058>`_)
+
 - Fix crash when parsing nested requirement. Fixes:
   (`#73112 <https://github.com/llvm/llvm-project/issues/73112>`_)
 
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 699e0985e595b6..1ad6cab93614af 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3585,6 +3585,7 @@ static Sema::TemplateDeductionResult 
instantiateExplicitSpecifierDeferred(
   if (Inst.isInvalid())
     return Sema::TDK_InstantiationDepth;
   Sema::SFINAETrap Trap(S);
+  Sema::ContextRAII InstantiatedContext(S, Specialization);
   const ExplicitSpecifier InstantiatedES =
       S.instantiateExplicitSpecifier(SubstArgs, ES);
   if (InstantiatedES.isInvalid() || Trap.hasErrorOccurred()) {
diff --git a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp 
b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
index 9fdc059493aacb..7ee58da0a175b8 100644
--- a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
+++ b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
@@ -743,3 +743,21 @@ struct S {
   explicit(1L) S(char, char, char);
 };
 } // namespace P1401
+
+#if __cplusplus > 201703L
+namespace GH67058 {
+template <class T>
+concept Q = requires(T t) { [](int *) {}(t); };
+struct A {
+  template <class T> explicit(Q<T>) A(T);
+};
+A a = 1;
+
+struct B { // expected-note+ {{candidate constructor}}
+  template <class T>
+  explicit(requires(T t) { [](int *) {}(t); })
+      B(T); // expected-note {{explicit constructor is not a candidate}}
+};
+B b = new int; // expected-error {{no viable conversion}}
+} // namespace GH67058
+#endif
\ No newline at end of file

``````````

</details>


https://github.com/llvm/llvm-project/pull/78053
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to