-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[FixIt] Improve Source Ranges and Fix-It Hints for Unused Lambda Captures #106445 #117953
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
This patch refines how Clang handles source ranges for unused lambda captures. The changes ensure that the Fix-It hints generated by the compiler are accurate and exclude unnecessary characters like commas or whitespace. Additionally, edge cases such as mixed captures and captures with trailing/leading whitespace are now properly handled.
This patch extends the existing test coverage in fixit-unused-lambda-capture.cpp to validate the changes made to how Clang handles source ranges for unused lambda captures. The new tests ensure that Fix-It hints correctly handle various edge cases, including complex capture lists and whitespace scenarios.
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-clang Author: None (charan-003) ChangesKey Changes Updated the ExplicitCaptureRanges logic to compute more precise source ranges for unused lambda captures.
Test Improvements in fixit-unused-lambda-capture.cpp:
Full diff: https://github.com/llvm/llvm-project/pull/117953.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index a67c0b2b367d1a..e7417d1a884dcd 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1164,8 +1164,11 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
/*FunctionScopeIndexToStopAtPtr*/ nullptr,
C->Kind == LCK_StarThis);
if (!LSI->Captures.empty())
- LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange;
- continue;
+ {
+ SourceRange TrimmedRange = Lexer::makeFileCharRange(
+ C->ExplicitRange, SM, LangOpts);
+ LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
+ }
}
assert(C->Id && "missing identifier for capture");
@@ -1329,7 +1332,11 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
}
if (!LSI->Captures.empty())
- LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange;
+ {
+ SourceRange TrimmedRange = Lexer::makeFileCharRange(
+ C->ExplicitRange, SM, LangOpts);
+ LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
+}
}
finishLambdaExplicitCaptures(LSI);
LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
diff --git a/clang/test/FixIt/fixit-unused-lambda-capture.cpp b/clang/test/FixIt/fixit-unused-lambda-capture.cpp
index ce0c78d677099a..ae43d4ebbdf821 100644
--- a/clang/test/FixIt/fixit-unused-lambda-capture.cpp
+++ b/clang/test/FixIt/fixit-unused-lambda-capture.cpp
@@ -66,6 +66,38 @@ void test() {
// CHECK: [z = (n = i)] {};
[j,z = (n = i)] {};
// CHECK: [z = (n = i)] {};
+
+ // New Edge Cases
+
+ // Test 1: Leading and trailing whitespace
+ [i, j] { return i; };
+ // CHECK: [i] { return i; };
+ [i , j] { return j; };
+ // CHECK: [j] { return j; };
+ [i , j , k] { return j + k; };
+ // CHECK: [j,k] { return j + k; };
+
+ // Test 2: Single unused capture
+ [i] {};
+ // CHECK: [] {};
+ [&i] {};
+ // CHECK: [] {};
+
+ // Test 3: Multiple commas
+ [i,,j] { return j; };
+ // CHECK: [j] { return j; };
+ [,i,j,,k] { return k; };
+ // CHECK: [k] { return k; };
+
+ // Test 4: Mixed captures
+ [=, &i, j] { return i; };
+ // CHECK: [&i] { return i; };
+ [&, i] {};
+ // CHECK: [&] {};
+
+ // Test 5: Capture with comments
+ [/*capture*/ i, j] { return j; };
+ // CHECK: [/*capture*/ j] { return j; };
}
class ThisTest {
|
added #include "clang/Lex/Lexer.h"
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.
[FixIt] Improve Source Ranges and Fix-It Hints for Unused Lambda Captures #106445
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.
[FixIt] Improve Source Ranges and Fix-It Hints for Unused Lambda Captures #106445
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.
mprove Source Ranges and Fix-It Hints for Unused Lambda Captures #106445
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.
[FixIt] Improve Source Ranges and Fix-It Hints for Unused Lambda Captures #106445
By the time we are in Sema, the ranges should be correct. In particular, can you check whether |
added functions for lambda campture
while condition
hi @cor3ntin made necessary updates to ParseExprCXX.cpp, but now ten tests are failing. Could you kindly provide on how to debug them? What are the main areas in ParseExprCXX.cpp that I should concentrate on while debugging these kinds of problems? |
Hi @cor3ntin After making changes in ParseExprCXX.cpp, I’m down to 10 failing test cases related to lambda parsing and Fix-It hints for unused captures. I reviewed Parser::ParseLambdaIntroducer and checked how SourceLocation LocEnd = PrevTokLocation; is used, but I’m still uncertain about where the incorrect source ranges might be originating. Could you suggest: Specific Parsing Logic: Which part of ParseLambdaIntroducer should I focus on when debugging incorrect source ranges? Are there common issues with PrevTokLocation assignments? Source Location Validations: Would it be helpful to insert assertions or debug prints at specific points in the parser to check computed source ranges during parsing? Next Steps: Given the test cases I shared earlier, would focusing on a particular test provide better insight into the issue? |
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.
added few test cases
constexpr int c = 10; | ||
int a[c]; // Make 'c' constexpr to avoid variable-length array warnings. | ||
|
||
[i,j] { return i; }; | ||
[i] { return i; }; | ||
// CHECK: [i] { return i; }; | ||
[i,j] { return j; }; | ||
[j] { return j; }; | ||
// CHECK: [j] { return j; }; | ||
[&i,j] { return j; }; | ||
[j] { return j; }; | ||
// CHECK: [j] { return j; }; | ||
[j,&i] { return j; }; | ||
[j] { return j; }; | ||
// CHECK: [j] { return j; }; | ||
[i,j,k] {}; | ||
[] {}; | ||
// CHECK: [] {}; | ||
[i,j,k] { return i + j; }; | ||
[i,j] { return i + j; }; | ||
// CHECK: [i,j] { return i + j; }; | ||
[i,j,k] { return j + k; }; | ||
[j,k] { return j + k; }; | ||
// CHECK: [j,k] { return j + k; }; | ||
[i,j,k] { return i + k; }; | ||
[i,k] { return i + k; }; | ||
// CHECK: [i,k] { return i + k; }; | ||
[i,j,k] { return i + j + k; }; | ||
// CHECK: [i,j,k] { return i + j + k; }; | ||
[&,i] { return k; }; | ||
[&] { return k; }; | ||
// CHECK: [&] { return k; }; | ||
[=,&i] { return k; }; | ||
[=] { return k; }; | ||
// CHECK: [=] { return k; }; | ||
[=,&i,&j] { return j; }; | ||
[=,&j] { return j; }; | ||
// CHECK: [=,&j] { return j; }; | ||
[=,&i,&j] { return i; }; | ||
[=,&i] { return i; }; | ||
// CHECK: [=,&i] { return i; }; | ||
[z = i] {}; | ||
[] {}; | ||
// CHECK: [] {}; | ||
[i,z = i] { return z; }; | ||
[z = i] { return z; }; | ||
// CHECK: [z = i] { return z; }; | ||
[z = i,i] { return z; }; | ||
[z = i] { return z; }; | ||
// CHECK: [z = i] { return z; }; | ||
[&a] {}; | ||
[] {}; | ||
// CHECK: [] {}; | ||
[i,&a] { return i; }; | ||
[i] { return i; }; | ||
// CHECK: [i] { return i; }; | ||
[&a,i] { return i; }; | ||
[i] { return i; }; | ||
// CHECK: [i] { return i; }; |
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.
Can you keep the existing tests as they were?
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.
@cor3ntin I get errors if I do so, any hint on how to resolve them ?
@@ -598,7 +598,7 @@ struct S1 { | |||
}; | |||
|
|||
void foo1() { | |||
auto s0 = S1([name=]() {}); // expected-error {{expected expression}} | |||
auto s0 = S1([]() {}); // Remove invalid capture, no diagnostic expected |
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.
@cor3ntin Also, I'm nearly done with this task. Can it be assigned to me? |
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.
There are a lot of changes that are non-functional (NFC) formatting changes, it would help to remove those changes from this PR as it makes the PR larger than necessary.
Another common issue is excess braces - the llvm formatting rule is no braces for if
, etc if there is a single statement even if the statement crosses multiple lines.
clang/lib/Sema/SemaLambda.cpp
Outdated
CaptureReadyLambdaLSI->PotentialThisCaptureLocation, | ||
/*Explicit*/ false, /*BuildAndDiagnose*/ false, | ||
&IndexOfCaptureReadyLambda); | ||
const bool CanCaptureThis = !S.CheckCXXThisCapture( |
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.
This looks like an irrelevant formatting change? possibly the result of accumulated changes
clang/lib/Sema/SemaLambda.cpp
Outdated
@@ -238,7 +240,7 @@ getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) { | |||
/*Template kw loc*/ SourceLocation(), | |||
/*L angle loc*/ LSI->ExplicitTemplateParamsRange.getBegin(), | |||
LSI->TemplateParams, | |||
/*R angle loc*/LSI->ExplicitTemplateParamsRange.getEnd(), | |||
/*R angle loc*/ LSI->ExplicitTemplateParamsRange.getEnd(), |
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.
irrelevant formatting change
clang/lib/Sema/SemaLambda.cpp
Outdated
@@ -317,8 +319,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { | |||
} | |||
|
|||
if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ManglingContextDecl)) { | |||
if (const DeclContext *LexicalDC | |||
= Param->getDeclContext()->getLexicalParent()) | |||
if (const DeclContext *LexicalDC = |
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.
irrelevant formatting change again
clang/lib/Sema/SemaLambda.cpp
Outdated
@@ -575,8 +577,7 @@ void Sema::ActOnLambdaExplicitTemplateParameterList( | |||
assert(LSI->TemplateParams.empty() && | |||
"Explicit template parameters should come " | |||
"before invented (auto) ones"); | |||
assert(!TParams.empty() && | |||
"No template parameters to act on"); | |||
assert(!TParams.empty() && "No template parameters to act on"); |
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.
NFC formatting change
clang/lib/Sema/SemaLambda.cpp
Outdated
@@ -597,8 +598,7 @@ static EnumDecl *findEnumForBlockReturn(Expr *E) { | |||
|
|||
// - it is an enumerator whose enum type is T or | |||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { | |||
if (EnumConstantDecl *D | |||
= dyn_cast<EnumConstantDecl>(DRE->getDecl())) { | |||
if (EnumConstantDecl *D = dyn_cast<EnumConstantDecl>(DRE->getDecl())) { |
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.
NFC formatting change
clang/lib/Sema/SemaLambda.cpp
Outdated
} | ||
|
||
if (DeducedType->isVoidType()) { | ||
if (!DeducedType->isDependentType()) { |
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.
excess braces again
clang/lib/Sema/SemaLambda.cpp
Outdated
VarDecl::Create(Ctx, nullptr, C->Loc, C->Loc, DummyID, DummyType, | ||
nullptr, SC_None); | ||
|
||
if (!TempVarDecl) { |
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.
excess brace
clang/lib/Sema/SemaLambda.cpp
Outdated
} | ||
} | ||
|
||
if (!DeducedType.isNull()) { |
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.
excess braces
clang/lib/Sema/SemaLambda.cpp
Outdated
@@ -1247,12 +1311,12 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro, | |||
if (C->Kind == LCK_ByRef && Intro.Default == LCD_ByRef) { | |||
Diag(C->Loc, diag::err_reference_capture_with_reference_default) | |||
<< FixItHint::CreateRemoval( | |||
SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc)); |
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.
NFC formatting change that should be removed
clang/lib/Sema/SemaLambda.cpp
Outdated
@@ -1599,7 +1671,7 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, | |||
// Finalize the lambda. | |||
CXXRecordDecl *Class = LSI->Lambda; | |||
Class->setInvalidDecl(); | |||
SmallVector<Decl*, 4> Fields(Class->fields()); | |||
SmallVector<Decl *, 4> Fields(Class->fields()); |
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.
NFC formatting change
clang/lib/Sema/SemaLambda.cpp
Outdated
@@ -1633,8 +1633,8 @@ static void repeatForLambdaConversionFunctionCallingConvs( | |||
CC_C, CC_X86StdCall, CC_X86FastCall, CC_X86VectorCall, | |||
DefaultFree, DefaultMember, CallOpCC}; | |||
llvm::sort(Convs); | |||
llvm::iterator_range<CallingConv *> Range( | |||
std::begin(Convs), std::unique(std::begin(Convs), std::end(Convs))); | |||
llvm::iterator_range<CallingConv *> Range(std::begin(Convs), |
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.
what is the reason for this change?
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.
llvm::unique
likely sorts and removes duplicates in one step
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 mean the std::unique
to llvm::unique
change -- llvm::unique is just a wrapper for std::unique so this change is not needed
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.
ohh okay sure, let me try changing it
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 there's no actual behavioral change so just reverting this specific change seems reasonable - ideally we want to avoid unrelated changes from PRs
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.
.
|
||
// Lambda capture diagnostics | ||
|
||
def err_invalid_lambda_capture_initializer_type : Error< |
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 you've last the code to emit these :-O
The fix for the core issue was more complex than the easy fix/new contributor tag implied: #141148 |
@charan-003 Oliver told me you were happy with him taking over in #141148. Can you confirm? |
@cor3ntin yes, I confirm Oliver taking it over. |
Key Changes
Enhancements in SemaLambda.cpp:
Updated the ExplicitCaptureRanges logic to compute more precise source ranges for unused lambda captures.
Test Improvements in fixit-unused-lambda-capture.cpp: