Skip to content

Commit 9fe5aa3

Browse files
authored
[clang][Sema] Skip the RequiresExprBodyDecls for lambda dependencies (#83997)
The dependency of a lambda inside of a `RequiresExprBodyDecl` was previously affected by its parent, e.g., `ClassTemplateSpecializationDecl`. This made the lambda always dependent regardless of the template arguments we had, which caused some crashes on the constraint evaluation later. This fixes #56556, fixes #82849 and a case demonstrated by #49570 (comment).
1 parent 84842f4 commit 9fe5aa3

File tree

3 files changed

+81
-2
lines changed

3 files changed

+81
-2
lines changed

clang/docs/ReleaseNotes.rst

+2
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,8 @@ Bug Fixes to C++ Support
319319
Fixes (#GH80630)
320320
- Fix a crash when an explicit template argument list is used with a name for which lookup
321321
finds a non-template function and a dependent using declarator.
322+
- Fixed an issue where the ``RequiresExprBody`` was involved in the lambda dependency
323+
calculation. (#GH56556), (#GH82849).
322324
- Fix a bug where overload resolution falsely reported an ambiguity when it was comparing
323325
a member-function against a non member function or a member-function with an
324326
explicit object parameter against a member function with no explicit object parameter

clang/lib/Sema/TreeTransform.h

+21-2
Original file line numberDiff line numberDiff line change
@@ -13649,10 +13649,29 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
1364913649
// use evaluation contexts to distinguish the function parameter case.
1365013650
CXXRecordDecl::LambdaDependencyKind DependencyKind =
1365113651
CXXRecordDecl::LDK_Unknown;
13652+
DeclContext *DC = getSema().CurContext;
13653+
// A RequiresExprBodyDecl is not interesting for dependencies.
13654+
// For the following case,
13655+
//
13656+
// template <typename>
13657+
// concept C = requires { [] {}; };
13658+
//
13659+
// template <class F>
13660+
// struct Widget;
13661+
//
13662+
// template <C F>
13663+
// struct Widget<F> {};
13664+
//
13665+
// While we are substituting Widget<F>, the parent of DC would be
13666+
// the template specialization itself. Thus, the lambda expression
13667+
// will be deemed as dependent even if there are no dependent template
13668+
// arguments.
13669+
// (A ClassTemplateSpecializationDecl is always a dependent context.)
13670+
while (DC->getDeclKind() == Decl::Kind::RequiresExprBody)
13671+
DC = DC->getParent();
1365213672
if ((getSema().isUnevaluatedContext() ||
1365313673
getSema().isConstantEvaluatedContext()) &&
13654-
(getSema().CurContext->isFileContext() ||
13655-
!getSema().CurContext->getParent()->isDependentContext()))
13674+
(DC->isFileContext() || !DC->getParent()->isDependentContext()))
1365613675
DependencyKind = CXXRecordDecl::LDK_NeverDependent;
1365713676

1365813677
CXXRecordDecl *OldClass = E->getLambdaClass();

clang/test/SemaTemplate/concepts-lambda.cpp

+58
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,64 @@ struct Foo {
9090

9191
static_assert(ConstructibleWithN<Foo>);
9292

93+
namespace GH56556 {
94+
95+
template <typename It>
96+
inline constexpr It declare ();
97+
98+
template <typename It, template <typename> typename Template>
99+
concept D = requires {
100+
{ [] <typename T1> (Template<T1> &) {}(declare<It &>()) };
101+
};
102+
103+
template <typename T>
104+
struct B {};
105+
106+
template <typename T>
107+
struct Adapter;
108+
109+
template <D<B> T>
110+
struct Adapter<T> {};
111+
112+
template struct Adapter<B<int>>;
113+
114+
} // namespace GH56556
115+
116+
namespace GH82849 {
117+
118+
template <class T>
119+
concept C = requires(T t) {
120+
requires requires (T u) {
121+
[]<class V>(V) {
122+
return requires(V v) {
123+
[](V w) {}(v);
124+
};
125+
}(t);
126+
};
127+
};
128+
129+
template <class From>
130+
struct Widget;
131+
132+
template <C F>
133+
struct Widget<F> {
134+
static F create(F from) {
135+
return from;
136+
}
137+
};
138+
139+
template <class>
140+
bool foo() {
141+
return C<int>;
142+
}
143+
144+
void bar() {
145+
// https://github.com/llvm/llvm-project/issues/49570#issuecomment-1664966972
146+
Widget<char>::create(0);
147+
}
148+
149+
} // namespace GH82849
150+
93151
}
94152

95153
// GH60642 reported an assert being hit, make sure we don't assert.

0 commit comments

Comments
 (0)