Skip to content

Commit dc567a2

Browse files
authored
[clang] Fix crash when declaring invalid lambda member (#74110)
In valid code, there should only be a very specific set of members in a lambda definition. If the user tries to define something inside the lambda class, this assumption is violated and causes an assertion error. This can be fixed by checking whether the members are valid, and if not, ignore that the class members are potentially unexpected. I've come across this while working on implementing lambdas in C++03.
1 parent 4d323e4 commit dc567a2

File tree

3 files changed

+17
-13
lines changed

3 files changed

+17
-13
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ Bug Fixes in This Version
258258
operator.
259259
Fixes (#GH83267).
260260

261+
- Fixes an assertion failure on invalid code when trying to define member
262+
functions in lambdas.
263+
261264
Bug Fixes to Compiler Builtins
262265
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
263266

@@ -408,7 +411,7 @@ RISC-V Support
408411
CUDA/HIP Language Changes
409412
^^^^^^^^^^^^^^^^^^^^^^^^^
410413

411-
- PTX is no longer included by default when compiling for CUDA. Using
414+
- PTX is no longer included by default when compiling for CUDA. Using
412415
``--cuda-include-ptx=all`` will return the old behavior.
413416

414417
CUDA Support

clang/lib/AST/DeclCXX.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,10 +1567,9 @@ bool CXXRecordDecl::isGenericLambda() const {
15671567

15681568
#ifndef NDEBUG
15691569
static bool allLookupResultsAreTheSame(const DeclContext::lookup_result &R) {
1570-
for (auto *D : R)
1571-
if (!declaresSameEntity(D, R.front()))
1572-
return false;
1573-
return true;
1570+
return llvm::all_of(R, [&](NamedDecl *D) {
1571+
return D->isInvalidDecl() || declaresSameEntity(D, R.front());
1572+
});
15741573
}
15751574
#endif
15761575

clang/test/SemaCXX/lambda-expressions.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// RUN: %clang_cc1 -std=c++11 -Wno-unused-value -fsyntax-only -verify=expected,expected-cxx14,cxx11 -fblocks %s
12
// RUN: %clang_cc1 -std=c++14 -Wno-unused-value -fsyntax-only -verify -verify=expected-cxx14 -fblocks %s
23
// RUN: %clang_cc1 -std=c++17 -Wno-unused-value -verify -ast-dump -fblocks %s | FileCheck %s
34

@@ -558,8 +559,8 @@ struct B {
558559
int x;
559560
A a = [&] { int y = x; };
560561
A b = [&] { [&] { [&] { int y = x; }; }; };
561-
A d = [&](auto param) { int y = x; };
562-
A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; };
562+
A d = [&](auto param) { int y = x; }; // cxx11-error {{'auto' not allowed in lambda parameter}}
563+
A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; }; // cxx11-error 2 {{'auto' not allowed in lambda parameter}}
563564
};
564565

565566
B<int> b;
@@ -589,6 +590,7 @@ struct S1 {
589590
void foo1() {
590591
auto s0 = S1{[name=]() {}}; // expected-error 2 {{expected expression}}
591592
auto s1 = S1{[name=name]() {}}; // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}}
593+
// cxx11-warning@-1 {{initialized lambda captures are a C++14 extension}}
592594
}
593595
}
594596

@@ -604,7 +606,7 @@ namespace PR25627_dont_odr_use_local_consts {
604606

605607
namespace ConversionOperatorDoesNotHaveDeducedReturnType {
606608
auto x = [](int){};
607-
auto y = [](auto &v) -> void { v.n = 0; };
609+
auto y = [](auto &v) -> void { v.n = 0; }; // cxx11-error {{'auto' not allowed in lambda parameter}} cxx11-note {{candidate function not viable}} cxx11-note {{conversion candidate}}
608610
using T = decltype(x);
609611
using U = decltype(y);
610612
using ExpectedTypeT = void (*)(int);
@@ -624,22 +626,22 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType {
624626
template<typename T>
625627
friend constexpr U::operator ExpectedTypeU<T>() const noexcept;
626628
#else
627-
friend auto T::operator()(int) const;
629+
friend auto T::operator()(int) const; // cxx11-error {{'auto' return without trailing return type; deduced return types are a C++14 extension}}
628630
friend T::operator ExpectedTypeT() const;
629631

630632
template<typename T>
631-
friend void U::operator()(T&) const;
633+
friend void U::operator()(T&) const; // cxx11-error {{friend declaration of 'operator()' does not match any declaration}}
632634
// FIXME: This should not match, as above.
633635
template<typename T>
634-
friend U::operator ExpectedTypeU<T>() const;
636+
friend U::operator ExpectedTypeU<T>() const; // cxx11-error {{friend declaration of 'operator void (*)(type-parameter-0-0 &)' does not match any declaration}}
635637
#endif
636638

637639
private:
638640
int n;
639641
};
640642

641-
// Should be OK: lambda's call operator is a friend.
642-
void use(X &x) { y(x); }
643+
// Should be OK in C++14 and later: lambda's call operator is a friend.
644+
void use(X &x) { y(x); } // cxx11-error {{no matching function for call to object}}
643645

644646
// This used to crash in return type deduction for the conversion opreator.
645647
struct A { int n; void f() { +[](decltype(n)) {}; } };

0 commit comments

Comments
 (0)