-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Clang] Fix crash with source_location
in lambda declarators.
#107411
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
Conversation
Parsing lambdas require pushing a declaration context for the lambda, so that parameters can be attached to it, before its trailing type is parsed. DAt that point, partially-parsed lambda don't have a name that can be computed for then. This would cause source_location::current() to crash when use in the decltype of a lambda(). We work around this by producing a source_location for an enclosing scope in that scenario. Fixes llvm#67134
@llvm/pr-subscribers-clang Author: cor3ntin (cor3ntin) ChangesParsing lambdas require pushing a declaration context for the lambda, so that parameters can be attached to it, before its trailing type is parsed. DAt that point, partially-parsed lambda don't have a name that can be computed for then. Fixes #67134 Full diff: https://github.com/llvm/llvm-project/pull/107411.diff 3 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ab3c3e6049f602..968283a73a7f81 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -366,6 +366,7 @@ Bug Fixes to C++ Support
- Clang no longer tries to capture non-odr used default arguments of template parameters of generic lambdas (#GH107048)
- Fixed a bug where defaulted comparison operators would remove ``const`` from base classes. (#GH102588)
+- Fix a crash when using ``source_location`` in the trailing return type of a lambda expression. (#GH67134)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 96c6276f3f34c1..27930db019a172 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/Attr.h"
#include "clang/AST/ComputeDependence.h"
#include "clang/AST/DeclCXX.h"
@@ -2287,6 +2288,15 @@ APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx,
Context = getParentContext();
}
+ // If we are currently parsing a lambda declarator, we might not have a fully
+ // formed call operator declaration yet, and we could not form a function name
+ // for it. Because we do not have access to Sema/function scopes here, we
+ // detect this case by relying on the fact such method doesn't yet have a
+ // type.
+ if (const auto *D = dyn_cast<CXXMethodDecl>(Context);
+ D && D->getFunctionTypeLoc().isNull() && isLambdaCallOperator(D))
+ Context = D->getParent()->getParent();
+
PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc(
Ctx.getSourceManager().getExpansionRange(Loc).getEnd());
diff --git a/clang/test/SemaCXX/source_location.cpp b/clang/test/SemaCXX/source_location.cpp
index 34177bfe287fc3..60aa19ae995674 100644
--- a/clang/test/SemaCXX/source_location.cpp
+++ b/clang/test/SemaCXX/source_location.cpp
@@ -989,3 +989,16 @@ void Test() {
}
#endif
+
+
+namespace GH67134 {
+template <int loc = std::source_location::current().line()>
+constexpr auto f(std::source_location loc2 = std::source_location::current()) { return loc; }
+int g = []() -> decltype(f()) { return 0; }();
+int call() {
+#if __cplusplus >= 202002L
+ return []<decltype(f()) = 0>() -> decltype(f()) { return 0; }();
+#endif
+ return []() -> decltype(f()) { return 0; }();
+}
+}
|
// type. | ||
if (const auto *D = dyn_cast<CXXMethodDecl>(Context); | ||
D && D->getFunctionTypeLoc().isNull() && isLambdaCallOperator(D)) | ||
Context = D->getParent()->getParent(); |
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.
So the first getParent
should get the lambda object, correct?
Could this cause issues where the parent of the lambda is a TU? Can we have a test for that? Also, there are some goofinesses around variable templates and requires in a lambda, can we have a test for that?
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.
Do we need to make sure we're in an unevaluated context here?
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.
ideally yes, I'd assert on it... but we do not have access to that information in constant evaluation
Woops! Had the wrong tab open and typed in the wrong 'fixes', did not mean to close this. The patch was supposed to fix #107052 |
While looking at it, I found another bug where we seem to have problems mangling |
See #59948 (comment) :) |
Parsing lambdas require pushing a declaration context for the lambda, so that parameters can be attached to it, before its trailing type is parsed. DAt that point, partially-parsed lambda don't have a name that can be computed for then.
This would cause source_location::current() to crash when use in the decltype of a lambda().
We work around this by producing a source_location for an enclosing scope in that scenario.
Fixes #67134