[clang] [Clang] Set the decl context to the instantiated constructor when instantiating the explicit specifier (PR #78053)

via cfe-commits cfe-commits at lists.llvm.org
Sat Jan 13 09:36:58 PST 2024


https://github.com/LYP951018 created https://github.com/llvm/llvm-project/pull/78053

The code that causes the bug:

```cpp
template<class T> concept Q = requires(T t) { [](int*){}(t); };
struct A { template<class T> explicit(Q<T>) 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()) &&
      (getSema().CurContext->isFileContext() ||
       !getSema().CurContext->getParent()->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.

>From ebd57b11fbce96a493c57d4c459baca6bcd6e9d2 Mon Sep 17 00:00:00 2001
From: letrec <liuyupei951018 at hotmail.com>
Date: Sun, 14 Jan 2024 00:59:23 +0800
Subject: [PATCH] add release notes

---
 clang/docs/ReleaseNotes.rst                |  3 +++
 clang/lib/Sema/SemaTemplateDeduction.cpp   |  1 +
 clang/test/SemaCXX/cxx2a-explicit-bool.cpp | 18 ++++++++++++++++++
 3 files changed, 22 insertions(+)

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



More information about the cfe-commits mailing list