-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[Clang] Set the decl context to the instantiated constructor when instantiating the explicit specifier #78053
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang Author: 刘雨培 (LYP951018) ChangesThe code that causes the bug: 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):
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:
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
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it looks good but I'd like @erichkeane's input.
I also wonder whether we should look at the instantiated parent to determine whether the lambda is dependent, instead of just looking at the non-instantiated parent.
Might fix a few bugs and it's an approach i never considered before
Yeah, unfortunately this falls very quickly into the 'we need to implement deferred instantiation of lambda bodies' here. I'd definitely like to see an exploration of that idea, but if that doesn't work out for good reason/with a bit of effort, I think this is probably a 'good enough for now'. |
The code that causes the bug:
When instantiating a lambda, the calculation of the lambda's dependency occurs in roughly two places (part of which this PR addresses):
TransformLambdaExpr
: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 inQ
isRequiresExprBodyDecl
, and the parent isCXXConstructorDecl
. However, since the parent'sCXXConstructorDecl
is the uninstantiatedCXXConstructorDecl
, it does not correctly setDependencyKind
toLDK_NeverDependent
.When constructing the type of the lambda expression, it uses
DeclContext::isDependentContext
to determine whether the current lambda type is dependent. The currentDeclContext::isDependentContext
implementation does not handleRequiresExprBodyDecl
(it seems that it is unable to calculate the dependency ofRequiresExprBodyDecl
), 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.