Skip to content

[clang] Fix crash when declaring invalid lambda member #74110

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

Merged
merged 3 commits into from
Mar 9, 2024

Conversation

philnik777
Copy link
Contributor

@philnik777 philnik777 commented Dec 1, 2023

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.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Dec 1, 2023
@llvmbot
Copy link
Member

llvmbot commented Dec 1, 2023

@llvm/pr-subscribers-clang

Author: Nikolas Klauser (philnik777)

Changes

I've come across this while working on implementing lambdas in C++03.


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

2 Files Affected:

  • (modified) clang/lib/AST/DeclCXX.cpp (+3-4)
  • (modified) clang/test/SemaCXX/lambda-expressions.cpp (+9-7)
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index c944862fcefeeef..e9e62fea9fb376a 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1526,10 +1526,9 @@ bool CXXRecordDecl::isGenericLambda() const {
 
 #ifndef NDEBUG
 static bool allLookupResultsAreTheSame(const DeclContext::lookup_result &R) {
-  for (auto *D : R)
-    if (!declaresSameEntity(D, R.front()))
-      return false;
-  return true;
+  return llvm::all_of(R, [&](NamedDecl *D) {
+    return D->isInvalidDecl() || declaresSameEntity(D, R.front());
+  });
 }
 #endif
 
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp
index 1797eef320b8659..1921d02b1a9cf8b 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -std=c++11 -Wno-unused-value -fsyntax-only -verify=expected,expected-cxx14,cxx11 -fblocks %s
 // RUN: %clang_cc1 -std=c++14 -Wno-unused-value -fsyntax-only -verify -verify=expected-cxx14 -fblocks %s
 // RUN: %clang_cc1 -std=c++17 -Wno-unused-value -verify -ast-dump -fblocks %s | FileCheck %s
 
@@ -558,8 +559,8 @@ struct B {
   int x;
   A a = [&] { int y = x; };
   A b = [&] { [&] { [&] { int y = x; }; }; };
-  A d = [&](auto param) { int y = x; };
-  A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; };
+  A d = [&](auto param) { int y = x; }; // cxx11-error {{'auto' not allowed in lambda parameter}}
+  A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; }; // cxx11-error 2 {{'auto' not allowed in lambda parameter}}
 };
 
 B<int> b;
@@ -589,6 +590,7 @@ struct S1 {
 void foo1() {
   auto s0 = S1{[name=]() {}}; // expected-error 2 {{expected expression}}
   auto s1 = S1{[name=name]() {}}; // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}}
+                                  // cxx11-warning@-1 {{initialized lambda captures are a C++14 extension}}
 }
 }
 
@@ -604,7 +606,7 @@ namespace PR25627_dont_odr_use_local_consts {
 
 namespace ConversionOperatorDoesNotHaveDeducedReturnType {
   auto x = [](int){};
-  auto y = [](auto &v) -> void { v.n = 0; };
+  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}}
   using T = decltype(x);
   using U = decltype(y);
   using ExpectedTypeT = void (*)(int);
@@ -624,14 +626,14 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType {
     template<typename T>
       friend constexpr U::operator ExpectedTypeU<T>() const noexcept;
 #else
-    friend auto T::operator()(int) const;
+    friend auto T::operator()(int) const; // cxx11-error {{'auto' return without trailing return type; deduced return types are a C++14 extension}}
     friend T::operator ExpectedTypeT() const;
 
     template<typename T>
-      friend void U::operator()(T&) const;
+      friend void U::operator()(T&) const; // cxx11-error {{friend declaration of 'operator()' does not match any declaration}}
     // FIXME: This should not match, as above.
     template<typename T>
-      friend U::operator ExpectedTypeU<T>() const;
+      friend U::operator ExpectedTypeU<T>() const; // cxx11-error {{friend declaration of 'operator void (*)(type-parameter-0-0 &)' does not match any declaration}}
 #endif
 
   private:
@@ -639,7 +641,7 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType {
   };
 
   // Should be OK: lambda's call operator is a friend.
-  void use(X &x) { y(x); }
+  void use(X &x) { y(x); } // cxx11-error {{no matching function for call to object}}
 
   // This used to crash in return type deduction for the conversion opreator.
   struct A { int n; void f() { +[](decltype(n)) {}; } };

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests changes look mostly unrelated to this PR

Comment on lines +1529 to +1531
return llvm::all_of(R, [&](NamedDecl *D) {
return D->isInvalidDecl() || declaresSameEntity(D, R.front());
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move the isInvalidDecl check to declaresSameEntity?
I doubt this is the only place this might happen

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I can tell nowhere is checking what they pass to declaresSameEntity(...) but I did not dig too deeply to see if we know they are valid earlier in some way.

@shafik
Copy link
Collaborator

shafik commented Dec 2, 2023

Can you add a little more details in the description on the root cause of the bug?

@philnik777
Copy link
Contributor Author

The tests changes look mostly unrelated to this PR

They mostly are. I found this while trying to check C++03 with the test and noticed that C++11 also crashes, so I updated the test to also run in C++11.

@philnik777
Copy link
Contributor Author

gentle ping

@philnik777
Copy link
Contributor Author

ping

@philnik777
Copy link
Contributor Author

Ping (@AaronBallman maybe?)

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes should come with a release note in clang/docs/ReleaseNotes.rst.

I'm confused -- the patch says that it's fixing a crash, but none of those test cases crash today. Can you add some new test coverage that demonstrates the crash? Also, the changes are to code that's only run in asserts builds... so why are we getting more diagnostics after these changes?

Comment on lines 643 to 644
// Should be OK: lambda's call operator is a friend.
void use(X &x) { y(x); }
void use(X &x) { y(x); } // cxx11-error {{no matching function for call to object}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above no longer matches the behavior, the comment should be updated slightly.

// FIXME: This should not match, as above.
template<typename T>
friend U::operator ExpectedTypeU<T>() const;
friend U::operator ExpectedTypeU<T>() const; // cxx11-error {{friend declaration of 'operator void (*)(type-parameter-0-0 &)' does not match any declaration}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oof, that's a bit of a gross diagnostic (not the fault of your patch).

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oooh, I see now, there's a new RUN line added to the test and that's where the new diagnostics are coming from.

The tests are unrelated to the patch and should be split out into a separate change, and you should add test coverage where we were crashing and we no longer do so. That may need to go into its own file which // REQUIRES: asserts.

@philnik777
Copy link
Contributor Author

@AaronBallman Thanks for the review. Sorry for responding so late - I've missed your review.

The tests aren't actually unrelated to the path. This is the file where I discovered the crash, so I just used it to demonstrate that it's fixed. I'm not sure how to split things, since I can't add the run line without fixing the bug.

@AaronBallman
Copy link
Collaborator

@AaronBallman Thanks for the review. Sorry for responding so late - I've missed your review.

The tests aren't actually unrelated to the path. This is the file where I discovered the crash, so I just used it to demonstrate that it's fixed. I'm not sure how to split things, since I can't add the run line without fixing the bug.

Ah, I see now what's going on, and yeah, the tests are not unrelated to the patch (the added RUN line is what causes the crash today), sorry for missing that.

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a minor nit with a comment in the test file where the comment should be updated, and the changes need a release note. Otherwise, LGTM

@philnik777 philnik777 merged commit dc567a2 into llvm:main Mar 9, 2024
@philnik777 philnik777 deleted the fix_cxx11_assert branch March 9, 2024 00:18
@nico
Copy link
Contributor

nico commented Mar 9, 2024

Looks like the included test still makes clang crash: http://45.33.8.238/linux/132722/step_7.txt

@nico
Copy link
Contributor

nico commented Mar 9, 2024

Also on the official waterfall, eg here: https://lab.llvm.org/buildbot/#/builders/188/builds/42935

Can you take a look, and revert for now if it takes a while to fix?

vitalybuka added a commit that referenced this pull request Mar 9, 2024
philnik777 added a commit to philnik777/llvm-project that referenced this pull request Mar 15, 2024
This re-applies llvm#74110 with the crashing code disabled in C++03. I'll
try to fix the new crash in it's own patch.
philnik777 added a commit that referenced this pull request Mar 16, 2024
)

This re-applies #74110 with the crashing code disabled in C++11. I'll
try to fix the new crash in it's own patch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants