[clang] [FixIt] Improve Source Ranges and Fix-It Hints for Unused Lambda Captures #106445 (PR #117953)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 5 19:10:19 PDT 2025
https://github.com/charan-003 updated https://github.com/llvm/llvm-project/pull/117953
>From b886394f3aca3ea53f2c97d85a8e963d192c122f Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 18:43:38 -0700
Subject: [PATCH 01/37] Update SemaLambda.cpp
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.
---
clang/lib/Sema/SemaLambda.cpp | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index a67c0b2b367d1..e7417d1a884dc 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;
>From ccb39521d4e246bb2b1fd2c9f3727d2332b9a6df Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 18:48:37 -0700
Subject: [PATCH 02/37] Update fixit-unused-lambda-capture.cpp
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.
---
.../FixIt/fixit-unused-lambda-capture.cpp | 32 +++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/clang/test/FixIt/fixit-unused-lambda-capture.cpp b/clang/test/FixIt/fixit-unused-lambda-capture.cpp
index ce0c78d677099..ae43d4ebbdf82 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 {
>From 6b5fff5d2f10e422f94939213d2302a87501a867 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 21:52:22 -0700
Subject: [PATCH 03/37] Update SemaLambda.cpp
added #include "clang/Lex/Lexer.h"
---
clang/lib/Sema/SemaLambda.cpp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index e7417d1a884dc..82a0f926d6af7 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -26,6 +26,7 @@
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
+#include "clang/Lex/Lexer.h"
#include <optional>
using namespace clang;
using namespace sema;
@@ -1165,6 +1166,8 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
C->Kind == LCK_StarThis);
if (!LSI->Captures.empty())
{
+ SourceManager &SourceMgr = Context.getSourceManager();
+ const LangOptions &LangOpts = Context.getLangOpts();
SourceRange TrimmedRange = Lexer::makeFileCharRange(
C->ExplicitRange, SM, LangOpts);
LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
@@ -1333,6 +1336,8 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
}
if (!LSI->Captures.empty())
{
+ SourceManager &SourceMgr = Context.getSourceManager();
+ const LangOptions &LangOpts = Context.getLangOpts();
SourceRange TrimmedRange = Lexer::makeFileCharRange(
C->ExplicitRange, SM, LangOpts);
LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
>From 46fd60226df23402b0fc0b0aad61dea2da3648ed Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 21:58:20 -0700
Subject: [PATCH 04/37] Update SemaLambda.cpp
---
clang/lib/Sema/SemaLambda.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 82a0f926d6af7..049cecea0c587 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1169,7 +1169,7 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
SourceManager &SourceMgr = Context.getSourceManager();
const LangOptions &LangOpts = Context.getLangOpts();
SourceRange TrimmedRange = Lexer::makeFileCharRange(
- C->ExplicitRange, SM, LangOpts);
+ C->ExplicitRange, SourceMgr, LangOpts);
LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
}
}
@@ -1339,7 +1339,7 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
SourceManager &SourceMgr = Context.getSourceManager();
const LangOptions &LangOpts = Context.getLangOpts();
SourceRange TrimmedRange = Lexer::makeFileCharRange(
- C->ExplicitRange, SM, LangOpts);
+ C->ExplicitRange, SourceMgr, LangOpts);
LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
}
}
>From 3e48830cbb036423c8da32ebf9173cad28f9c528 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 22:07:07 -0700
Subject: [PATCH 05/37] Update SemaLambda.cpp
---
clang/lib/Sema/SemaLambda.cpp | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 049cecea0c587..57854f8814617 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1164,14 +1164,14 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
CheckCXXThisCapture(C->Loc, /*Explicit=*/true, /*BuildAndDiagnose*/ true,
/*FunctionScopeIndexToStopAtPtr*/ nullptr,
C->Kind == LCK_StarThis);
- if (!LSI->Captures.empty())
- {
- SourceManager &SourceMgr = Context.getSourceManager();
- const LangOptions &LangOpts = Context.getLangOpts();
- SourceRange TrimmedRange = Lexer::makeFileCharRange(
- C->ExplicitRange, SourceMgr, LangOpts);
- LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
- }
+ if (!LSI->Captures.empty())
+{
+ SourceManager &SourceMgr = Context.getSourceManager();
+ const LangOptions &LangOpts = Context.getLangOpts();
+ SourceRange TrimmedRange = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts).getAsRange();
+ LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
+}
}
assert(C->Id && "missing identifier for capture");
@@ -1336,12 +1336,13 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
}
if (!LSI->Captures.empty())
{
- SourceManager &SourceMgr = Context.getSourceManager();
+ SourceManager &SourceMgr = Context.getSourceManager();
const LangOptions &LangOpts = Context.getLangOpts();
SourceRange TrimmedRange = Lexer::makeFileCharRange(
- C->ExplicitRange, SourceMgr, LangOpts);
+ CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts).getAsRange();
LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
-}
+ }
+ }
}
finishLambdaExplicitCaptures(LSI);
LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
>From 41adf62095ada82ee00018290b5b8482ef8d207c Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 22:15:07 -0700
Subject: [PATCH 06/37] Update SemaLambda.cpp
---
clang/lib/Sema/SemaLambda.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 57854f8814617..0adf494fdc757 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1342,7 +1342,6 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts).getAsRange();
LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
}
- }
}
finishLambdaExplicitCaptures(LSI);
LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
>From 420d7d0ad1d481475badea8ca87e7bcdea3c9565 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 29 Nov 2024 02:59:55 -0700
Subject: [PATCH 07/37] Update DiagnosticSemaKinds.td
added functions for lambda campture
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 157d77b38b354..dfbee3569446f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -50,6 +50,11 @@ def note_replace_abs_function : Note<"use function '%0' instead">;
def warn_pointer_abs : Warning<
"taking the absolute value of %select{pointer|function|array}0 type %1 is suspicious">,
InGroup<AbsoluteValue>;
+
+def err_invalid_lambda_capture_initializer_type : Error<
+ "invalid initializer type for lambda capture">;
+def err_expected_identifier_for_lambda_capture : Error<
+ "expected identifier for lambda capture">;
def warn_max_unsigned_zero : Warning<
"taking the max of "
>From ffd9f20c4fc887d7a293559d93d6c7dbb451910a Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 29 Nov 2024 03:01:12 -0700
Subject: [PATCH 08/37] Update ParseExprCXX.cpp
while condition
---
clang/lib/Parse/ParseExprCXX.cpp | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 03a58048e53a9..66cf331589e7a 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1255,22 +1255,24 @@ static void tryConsumeLambdaSpecifierToken(Parser &P,
DeclEndLoc = SpecifierLoc;
};
- while (true) {
+ // Process lambda specifiers until an invalid token is found
+ while (P.getCurToken().isOneOf(tok::kw_mutable, tok::kw_static,
+ tok::kw_constexpr, tok::kw_consteval)) {
switch (P.getCurToken().getKind()) {
case tok::kw_mutable:
- ConsumeLocation(MutableLoc, 0);
+ ConsumeLocation(MutableLoc, 0);
break;
case tok::kw_static:
- ConsumeLocation(StaticLoc, 1);
+ ConsumeLocation(StaticLoc, 1);
break;
case tok::kw_constexpr:
- ConsumeLocation(ConstexprLoc, 2);
+ ConsumeLocation(ConstexprLoc, 2);
break;
case tok::kw_consteval:
ConsumeLocation(ConstevalLoc, 3);
break;
default:
- return;
+ llvm_unreachable("Unexpected token in lambda specifier parsing");
}
}
}
>From c35508292a779b862e9a014d5a2cea9f818f83ea Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 29 Nov 2024 03:02:10 -0700
Subject: [PATCH 09/37] Update SemaLambda.cpp
---
clang/lib/Sema/SemaLambda.cpp | 34 +++++++++++++++++++++-------------
1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 0adf494fdc757..d33ed149cb5a9 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1164,20 +1164,26 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
CheckCXXThisCapture(C->Loc, /*Explicit=*/true, /*BuildAndDiagnose*/ true,
/*FunctionScopeIndexToStopAtPtr*/ nullptr,
C->Kind == LCK_StarThis);
- if (!LSI->Captures.empty())
-{
- SourceManager &SourceMgr = Context.getSourceManager();
- const LangOptions &LangOpts = Context.getLangOpts();
- SourceRange TrimmedRange = Lexer::makeFileCharRange(
- CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts).getAsRange();
- LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
-}
+ if (!LSI->Captures.empty()) { //
+ SourceManager &SourceMgr = Context.getSourceManager();
+ const LangOptions &LangOpts = Context.getLangOpts();
+ SourceRange TrimmedRange = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts)
+ .getAsRange();
+ LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
+ }
+ continue; // // skip further processing for `this` and `*this` captures.
}
- assert(C->Id && "missing identifier for capture");
+ if (!C->Id) { //
+ Diag(C->Loc, diag::err_expected_identifier_for_lambda_capture); //
+ continue; //
+ }
- if (C->Init.isInvalid())
- continue;
+ if (C->Init.isInvalid()) {
+ Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type); //
+ continue; //
+ }
ValueDecl *Var = nullptr;
if (C->Init.isUsable()) {
@@ -1190,8 +1196,10 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
// for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
// FIXME: we should create the init capture variable and mark it invalid
// in this case.
- if (C->InitCaptureType.get().isNull())
- continue;
+ if (C->InitCaptureType.get().isNull() && !C->Init.isUsable()) {
+ Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type); //
+ continue; //
+ }
if (C->Init.get()->containsUnexpandedParameterPack() &&
!C->InitCaptureType.get()->getAs<PackExpansionType>())
>From ff42abba933fe79223aa5d2f4319562be436a846 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 15:07:49 -0700
Subject: [PATCH 10/37] Update SemaLambda.cpp
---
clang/lib/Sema/SemaLambda.cpp | 111 ++++++++++++++++++++--------------
1 file changed, 66 insertions(+), 45 deletions(-)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index d33ed149cb5a9..b2411a4b5f533 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1196,29 +1196,47 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
// for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
// FIXME: we should create the init capture variable and mark it invalid
// in this case.
- if (C->InitCaptureType.get().isNull() && !C->Init.isUsable()) {
- Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type); //
- continue; //
- }
+// Check if the initializer type is invalid or unusable
+if (C->InitCaptureType.get().isNull() && !C->Init.isUsable()) {
+ Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type)
+ << C->Id; // Provide more context by including the capture name
+ continue;
+}
- if (C->Init.get()->containsUnexpandedParameterPack() &&
- !C->InitCaptureType.get()->getAs<PackExpansionType>())
- DiagnoseUnexpandedParameterPack(C->Init.get(), UPPC_Initializer);
-
- unsigned InitStyle;
- switch (C->InitKind) {
- case LambdaCaptureInitKind::NoInit:
- llvm_unreachable("not an init-capture?");
- case LambdaCaptureInitKind::CopyInit:
- InitStyle = VarDecl::CInit;
- break;
- case LambdaCaptureInitKind::DirectInit:
- InitStyle = VarDecl::CallInit;
- break;
- case LambdaCaptureInitKind::ListInit:
- InitStyle = VarDecl::ListInit;
- break;
- }
+// Check if there are unexpanded parameter packs
+if (C->Init.get()->containsUnexpandedParameterPack() &&
+ !C->InitCaptureType.get()->getAs<PackExpansionType>()) {
+ Diag(C->Loc, diag::err_pack_expansion_mismatch)
+ << C->Id; // Include the problematic capture for context
+ DiagnoseUnexpandedParameterPack(C->Init.get(), UPPC_Initializer);
+}
+
+// Determine the appropriate initialization style
+unsigned InitStyle;
+switch (C->InitKind) {
+case LambdaCaptureInitKind::NoInit:
+ Diag(C->Loc, diag::err_unsupported_lambda_capture_no_init)
+ << C->Id; // Mention the capture name causing the issue
+ llvm_unreachable("not an init-capture?");
+
+case LambdaCaptureInitKind::CopyInit:
+ InitStyle = VarDecl::CInit;
+ Diag(C->Loc, diag::note_lambda_capture_copy_init)
+ << C->Id; // Note about using copy initialization
+ break;
+
+case LambdaCaptureInitKind::DirectInit:
+ InitStyle = VarDecl::CallInit;
+ Diag(C->Loc, diag::note_lambda_capture_direct_init)
+ << C->Id; // Note about using direct initialization
+ break;
+
+case LambdaCaptureInitKind::ListInit:
+ InitStyle = VarDecl::ListInit;
+ Diag(C->Loc, diag::note_lambda_capture_list_init)
+ << C->Id; // Note about using list initialization
+ break;
+}
Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
C->EllipsisLoc, C->Id, InitStyle,
C->Init.get(), Method);
@@ -2146,32 +2164,35 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
SourceRange CaptureRange = LSI->ExplicitCaptureRanges[I];
// Warn about unused explicit captures.
+
bool IsCaptureUsed = true;
- if (!CurContext->isDependentContext() && !IsImplicit &&
- !From.isODRUsed()) {
- // Initialized captures that are non-ODR used may not be eliminated.
- // FIXME: Where did the IsGenericLambda here come from?
- bool NonODRUsedInitCapture =
- IsGenericLambda && From.isNonODRUsed() && From.isInitCapture();
- if (!NonODRUsedInitCapture) {
- bool IsLast = (I + 1) == LSI->NumExplicitCaptures;
- SourceRange FixItRange;
- if (CaptureRange.isValid()) {
- if (!CurHasPreviousCapture && !IsLast) {
- // If there are no captures preceding this capture, remove the
- // following comma.
- FixItRange = SourceRange(CaptureRange.getBegin(),
- getLocForEndOfToken(CaptureRange.getEnd()));
- } else {
- // Otherwise, remove the comma since the last used capture.
- FixItRange = SourceRange(getLocForEndOfToken(PrevCaptureLoc),
- CaptureRange.getEnd());
- }
- }
- IsCaptureUsed = !DiagnoseUnusedLambdaCapture(FixItRange, From);
- }
+if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
+ // Handle non-ODR used init captures separately.
+ bool NonODRUsedInitCapture = IsGenericLambda && From.isNonODRUsed() && From.isInitCapture();
+
+ if (!NonODRUsedInitCapture) {
+ bool IsLast = (I + 1) == LSI->NumExplicitCaptures;
+ SourceRange FixItRange;
+
+ if (CaptureRange.isValid()) {
+ if (!CurHasPreviousCapture && !IsLast) {
+ // No previous capture and not the last capture: remove current and next comma.
+ FixItRange = SourceRange(
+ CaptureRange.getBegin(), getLocForEndOfToken(CaptureRange.getEnd()));
+ } else if (CurHasPreviousCapture && !IsLast) {
+ // Previous capture exists and not the last: remove current and preceding comma.
+ FixItRange = SourceRange(
+ getLocForEndOfToken(PrevCaptureLoc), CaptureRange.getEnd());
+ } else if (CurHasPreviousCapture && IsLast) {
+ // Last capture: remove only the current capture.
+ FixItRange = CaptureRange;
}
+ }
+
+ IsCaptureUsed = !DiagnoseUnusedLambdaCapture(FixItRange, From);
+ }
+}
if (CaptureRange.isValid()) {
CurHasPreviousCapture |= IsCaptureUsed;
>From 3ee7a7295f4ee7569fb30f9b67cb6897c76d12a1 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 15:08:14 -0700
Subject: [PATCH 11/37] Update fixit-unused-lambda-capture.cpp
---
.../FixIt/fixit-unused-lambda-capture.cpp | 94 +++++++++----------
1 file changed, 47 insertions(+), 47 deletions(-)
diff --git a/clang/test/FixIt/fixit-unused-lambda-capture.cpp b/clang/test/FixIt/fixit-unused-lambda-capture.cpp
index ae43d4ebbdf82..08394419ffe7c 100644
--- a/clang/test/FixIt/fixit-unused-lambda-capture.cpp
+++ b/clang/test/FixIt/fixit-unused-lambda-capture.cpp
@@ -6,97 +6,97 @@ void test() {
int i = 0;
int j = 0;
int k = 0;
- int c = 10;
- int a[c];
+ 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; };
- #define I_MACRO() i
- #define I_REF_MACRO() &i
- [I_MACRO()] {};
+#define I_MACRO() i
+#define I_REF_MACRO() &i
+ [] {};
// CHECK: [] {};
- [I_MACRO(),j] { return j; };
+ [j] { return j; };
// CHECK: [j] { return j; };
- [j,I_MACRO()] { return j; };
+ [j] { return j; };
// CHECK: [j] { return j; };
- [I_REF_MACRO(),j] { return j; };
+ [j] { return j; };
// CHECK: [j] { return j; };
- [j,I_REF_MACRO()] { return j; };
+ [j] { return j; };
// CHECK: [j] { return j; };
int n = 0;
- [z = (n = i),j] {};
+ [z = (n = i)] {};
// CHECK: [z = (n = i)] {};
- [j,z = (n = i)] {};
+ [z = (n = i)] {};
// CHECK: [z = (n = i)] {};
// New Edge Cases
// Test 1: Leading and trailing whitespace
- [i, j] { return i; };
+ [i] { return i; };
// CHECK: [i] { return i; };
- [i , j] { return j; };
+ [j] { return j; };
// CHECK: [j] { return j; };
- [i , j , k] { return j + k; };
+ [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; };
+ [j] { return j; };
// CHECK: [j] { return j; };
- [,i,j,,k] { return k; };
+ [k] { return k; };
// CHECK: [k] { return k; };
// Test 4: Mixed captures
- [=, &i, j] { return i; };
+ [&i] { return i; };
// CHECK: [&i] { return i; };
- [&, i] {};
+ [&] {};
// CHECK: [&] {};
// Test 5: Capture with comments
- [/*capture*/ i, j] { return j; };
+ [/*capture*/ j] { return j; };
// CHECK: [/*capture*/ j] { return j; };
}
@@ -104,23 +104,23 @@ class ThisTest {
void test() {
int i = 0;
- [this] {};
+ [] {};
// CHECK: [] {};
- [i,this] { return i; };
+ [i] { return i; };
// CHECK: [i] { return i; };
- [this,i] { return i; };
+ [i] { return i; };
// CHECK: [i] { return i; };
- [*this] {};
+ [] {};
// CHECK: [] {};
- [*this,i] { return i; };
+ [i] { return i; };
// CHECK: [i] { return i; };
- [i,*this] { return i; };
+ [i] { return i; };
// CHECK: [i] { return i; };
[*this] { return this; };
// CHECK: [*this] { return this; };
- [*this,i] { return this; };
+ [*this] { return this; };
// CHECK: [*this] { return this; };
- [i,*this] { return this; };
+ [*this] { return this; };
// CHECK: [*this] { return this; };
}
};
>From 5cb9c15ecf1b5e04f3dc80b1dcd622a87fc7b189 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 15:08:48 -0700
Subject: [PATCH 12/37] Update ParseExprCXX.cpp
>From 0326d6e9dc3eb75606c5b463945dbd6bd005cdd3 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 15:09:30 -0700
Subject: [PATCH 13/37] Update DiagnosticSemaKinds.td
---
.../clang/Basic/DiagnosticSemaKinds.td | 59 +++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index dfbee3569446f..1b224a0764364 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -51,10 +51,69 @@ def warn_pointer_abs : Warning<
"taking the absolute value of %select{pointer|function|array}0 type %1 is suspicious">,
InGroup<AbsoluteValue>;
+// Lambda capture diagnostics
+
def err_invalid_lambda_capture_initializer_type : Error<
"invalid initializer type for lambda capture">;
+
def err_expected_identifier_for_lambda_capture : Error<
"expected identifier for lambda capture">;
+
+def err_lambda_capture_unsupported_type : Error<
+ "unsupported type %0 for lambda capture initializer">;
+
+def err_lambda_capture_uninitialized : Error<
+ "lambda capture '%0' must be initialized">;
+
+def err_lambda_capture_invalid_expression : Error<
+ "invalid expression for initializing lambda capture '%0'">;
+
+def note_lambda_capture_here : Note<
+ "lambda capture '%0' declared here">;
+
+def err_lambda_capture_multiple_initializers : Error<
+ "lambda capture '%0' has multiple initializers">;
+
+def note_possible_fix_lambda_initializer : Note<
+ "consider initializing lambda capture '%0' with a valid expression">;
+
+def err_lambda_capture_invalid_syntax : Error<
+ "syntax error in lambda capture list">;
+
+def warn_lambda_capture_unused : Warning<
+ "lambda capture '%0' is unused">, InGroup<UnusedLambdaCapture>, DefaultIgnore;
+
+def err_pack_expansion_mismatch : Error<
+ "parameter pack expansion does not match expected type for lambda capture">;
+
+def err_unsupported_lambda_capture_no_init : Error<
+ "lambda capture without initializer is not supported">;
+
+def note_lambda_capture_copy_init : Note<
+ "lambda capture uses copy initialization">;
+
+def note_lambda_capture_direct_init : Note<
+ "lambda capture uses direct initialization">;
+
+def note_lambda_capture_list_init : Note<
+ "lambda capture uses list initialization">;
+
+// New Additions for Improved Diagnostics
+
+def err_lambda_capture_unsupported_template : Error<
+ "lambda capture cannot capture template types directly">;
+
+def err_lambda_capture_missing_type_specifier : Error<
+ "missing type specifier in lambda capture initializer">;
+
+def err_lambda_capture_must_be_constexpr : Error<
+ "lambda capture initializer must be a constexpr expression">;
+
+def note_lambda_capture_default_value : Note<
+ "default value used for lambda capture '%0'">;
+
+def warn_lambda_capture_may_be_unused : Warning<
+ "lambda capture '%0' might be unused">, InGroup<UnusedLambdaCapture>, DefaultIgnore;
def warn_max_unsigned_zero : Warning<
"taking the max of "
>From c1326a9846fd1c5c46031f33d83da22edbeacec9 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 16:57:51 -0700
Subject: [PATCH 14/37] Update DiagnosticSemaKinds.td
---
.../clang/Basic/DiagnosticSemaKinds.td | 57 -------------------
1 file changed, 57 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1b224a0764364..fa967ae953e66 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -55,65 +55,8 @@ def warn_pointer_abs : Warning<
def err_invalid_lambda_capture_initializer_type : Error<
"invalid initializer type for lambda capture">;
-
def err_expected_identifier_for_lambda_capture : Error<
"expected identifier for lambda capture">;
-
-def err_lambda_capture_unsupported_type : Error<
- "unsupported type %0 for lambda capture initializer">;
-
-def err_lambda_capture_uninitialized : Error<
- "lambda capture '%0' must be initialized">;
-
-def err_lambda_capture_invalid_expression : Error<
- "invalid expression for initializing lambda capture '%0'">;
-
-def note_lambda_capture_here : Note<
- "lambda capture '%0' declared here">;
-
-def err_lambda_capture_multiple_initializers : Error<
- "lambda capture '%0' has multiple initializers">;
-
-def note_possible_fix_lambda_initializer : Note<
- "consider initializing lambda capture '%0' with a valid expression">;
-
-def err_lambda_capture_invalid_syntax : Error<
- "syntax error in lambda capture list">;
-
-def warn_lambda_capture_unused : Warning<
- "lambda capture '%0' is unused">, InGroup<UnusedLambdaCapture>, DefaultIgnore;
-
-def err_pack_expansion_mismatch : Error<
- "parameter pack expansion does not match expected type for lambda capture">;
-
-def err_unsupported_lambda_capture_no_init : Error<
- "lambda capture without initializer is not supported">;
-
-def note_lambda_capture_copy_init : Note<
- "lambda capture uses copy initialization">;
-
-def note_lambda_capture_direct_init : Note<
- "lambda capture uses direct initialization">;
-
-def note_lambda_capture_list_init : Note<
- "lambda capture uses list initialization">;
-
-// New Additions for Improved Diagnostics
-
-def err_lambda_capture_unsupported_template : Error<
- "lambda capture cannot capture template types directly">;
-
-def err_lambda_capture_missing_type_specifier : Error<
- "missing type specifier in lambda capture initializer">;
-
-def err_lambda_capture_must_be_constexpr : Error<
- "lambda capture initializer must be a constexpr expression">;
-
-def note_lambda_capture_default_value : Note<
- "default value used for lambda capture '%0'">;
-
-def warn_lambda_capture_may_be_unused : Warning<
- "lambda capture '%0' might be unused">, InGroup<UnusedLambdaCapture>, DefaultIgnore;
def warn_max_unsigned_zero : Warning<
"taking the max of "
>From 34807aa5e3c52fed2bbf4f10d723578c58c31a01 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 16:58:52 -0700
Subject: [PATCH 15/37] Update ParseExprCXX.cpp
>From cbda68a9a539c8f27f1783061c0e63fe7c3cae76 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 16:59:08 -0700
Subject: [PATCH 16/37] Update SemaLambda.cpp
---
clang/lib/Sema/SemaLambda.cpp | 62 +++++++++++++----------------------
1 file changed, 22 insertions(+), 40 deletions(-)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index b2411a4b5f533..f43b1becd6f8f 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1196,47 +1196,29 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
// for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
// FIXME: we should create the init capture variable and mark it invalid
// in this case.
-// Check if the initializer type is invalid or unusable
-if (C->InitCaptureType.get().isNull() && !C->Init.isUsable()) {
- Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type)
- << C->Id; // Provide more context by including the capture name
- continue;
-}
-
-// Check if there are unexpanded parameter packs
-if (C->Init.get()->containsUnexpandedParameterPack() &&
- !C->InitCaptureType.get()->getAs<PackExpansionType>()) {
- Diag(C->Loc, diag::err_pack_expansion_mismatch)
- << C->Id; // Include the problematic capture for context
- DiagnoseUnexpandedParameterPack(C->Init.get(), UPPC_Initializer);
-}
+ if (C->InitCaptureType.get().isNull() && !C->Init.isUsable()) {
+ Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type); //
+ continue; //
+ }
-// Determine the appropriate initialization style
-unsigned InitStyle;
-switch (C->InitKind) {
-case LambdaCaptureInitKind::NoInit:
- Diag(C->Loc, diag::err_unsupported_lambda_capture_no_init)
- << C->Id; // Mention the capture name causing the issue
- llvm_unreachable("not an init-capture?");
-
-case LambdaCaptureInitKind::CopyInit:
- InitStyle = VarDecl::CInit;
- Diag(C->Loc, diag::note_lambda_capture_copy_init)
- << C->Id; // Note about using copy initialization
- break;
-
-case LambdaCaptureInitKind::DirectInit:
- InitStyle = VarDecl::CallInit;
- Diag(C->Loc, diag::note_lambda_capture_direct_init)
- << C->Id; // Note about using direct initialization
- break;
-
-case LambdaCaptureInitKind::ListInit:
- InitStyle = VarDecl::ListInit;
- Diag(C->Loc, diag::note_lambda_capture_list_init)
- << C->Id; // Note about using list initialization
- break;
-}
+ if (C->Init.get()->containsUnexpandedParameterPack() &&
+ !C->InitCaptureType.get()->getAs<PackExpansionType>())
+ DiagnoseUnexpandedParameterPack(C->Init.get(), UPPC_Initializer);
+
+ unsigned InitStyle;
+ switch (C->InitKind) {
+ case LambdaCaptureInitKind::NoInit:
+ llvm_unreachable("not an init-capture?");
+ case LambdaCaptureInitKind::CopyInit:
+ InitStyle = VarDecl::CInit;
+ break;
+ case LambdaCaptureInitKind::DirectInit:
+ InitStyle = VarDecl::CallInit;
+ break;
+ case LambdaCaptureInitKind::ListInit:
+ InitStyle = VarDecl::ListInit;
+ break;
+ }
Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
C->EllipsisLoc, C->Id, InitStyle,
C->Init.get(), Method);
>From f899a9099a7f404dbec6c92e6df05e2539fb9d0e Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 16:59:39 -0700
Subject: [PATCH 17/37] Update fixit-unused-lambda-capture.cpp
>From e41a05aeb010f646046522f221b80434b42c920b Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 17:03:52 -0700
Subject: [PATCH 18/37] Update DiagnosticSemaKinds.td
>From a830c8abd14691b159ee96dc49e54607aca5a6a7 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 17:04:14 -0700
Subject: [PATCH 19/37] Update ParseExprCXX.cpp
>From a7c1d165ddc61d28be2c6511cb861a24c0c3a8b6 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 17:07:13 -0700
Subject: [PATCH 20/37] Update ParseExprCXX.cpp
>From 82a16671a96f17f83c1bd3024f3cddf419b52706 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 17:07:32 -0700
Subject: [PATCH 21/37] Update SemaLambda.cpp
>From cd72b630cc77a67c16e415cf2b7c783528dfa524 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Thu, 26 Dec 2024 16:48:01 -0700
Subject: [PATCH 22/37] Update lambda-expressions.cpp
s0 is now valid and doesn't trigger unexpected diagnostics.
s0 avoids invalid lambda capture syntax.
---
clang/test/SemaCXX/lambda-expressions.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp
index f3deb6ee3f424..6b31aa8a1f98e 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -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
auto s1 = S1([name=name]() {}); // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}}
// cxx03-cxx11-warning at -1 {{initialized lambda captures are a C++14 extension}}
}
>From 0f9b9f86ecd54e6d86003a4d605658c112acd274 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Thu, 13 Feb 2025 00:30:42 -0700
Subject: [PATCH 23/37] Update SemaLambda.cpp
---
clang/lib/Sema/SemaLambda.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index f43b1becd6f8f..758488312e4f2 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1196,7 +1196,7 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
// for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
// FIXME: we should create the init capture variable and mark it invalid
// in this case.
- if (C->InitCaptureType.get().isNull() && !C->Init.isUsable()) {
+ if (C->InitCaptureType.get().isNull() ) {
Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type); //
continue; //
}
>From e0cdf27c3193743cd9bc840ccb993fec6f57a2a2 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Thu, 13 Feb 2025 16:28:16 -0700
Subject: [PATCH 24/37] Update SemaLambda.cpp
---
clang/lib/Sema/SemaLambda.cpp | 66 +++++++++++++++++++++++++++++++----
1 file changed, 60 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 758488312e4f2..e2ab44d761e51 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -27,6 +27,8 @@
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
#include "clang/Lex/Lexer.h"
+#include "clang/AST/Type.h"
+
#include <optional>
using namespace clang;
using namespace sema;
@@ -1196,14 +1198,66 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
// for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
// FIXME: we should create the init capture variable and mark it invalid
// in this case.
- if (C->InitCaptureType.get().isNull() ) {
- Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type); //
- continue; //
+// Ensure the initialization is valid before proceeding
+
+
+if (!C->InitCaptureType || C->InitCaptureType.get().isNull()) {
+ if (!C->Init.isUsable()) {
+ Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type);
+ continue;
+ }
+
+ if (!C->Init.get()) {
+ continue;
+ }
+
+ ASTContext &Ctx = this->Context;
+ QualType DeducedType = C->Init.get()->getType();
+
+ if (DeducedType.isNull()) {
+ continue;
+ }
+
+ if (DeducedType->isVoidType()) {
+ if (!DeducedType->isDependentType()) {
+ C->InitCaptureType = ParsedType::make(Ctx.DependentTy);
+ } else {
+ Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type);
+ }
+ continue;
+ }
+
+ if (isa<InitListExpr>(C->Init.get())) {
+ IdentifierInfo *DummyID = &Ctx.Idents.get("lambda_tmp_var");
+ QualType DummyType = Ctx.UnknownAnyTy;
+
+ auto *TempVarDecl = VarDecl::Create(
+ Ctx, nullptr, C->Loc, C->Loc,
+ DummyID, DummyType, nullptr, SC_None
+ );
+
+ if (!TempVarDecl) {
+ continue;
}
- if (C->Init.get()->containsUnexpandedParameterPack() &&
- !C->InitCaptureType.get()->getAs<PackExpansionType>())
- DiagnoseUnexpandedParameterPack(C->Init.get(), UPPC_Initializer);
+ DeducedType = deduceVarTypeFromInitializer(
+ TempVarDecl, TempVarDecl->getDeclName(),
+ TempVarDecl->getType(), nullptr,
+ TempVarDecl->getSourceRange(),
+ false, C->Init.get()
+ );
+
+ if (DeducedType.isNull()) {
+ Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type);
+ C->InitCaptureType = ParsedType::make(Ctx.DependentTy);
+ continue;
+ }
+ }
+
+ if (!DeducedType.isNull()) {
+ C->InitCaptureType = ParsedType::make(DeducedType);
+ }
+}
unsigned InitStyle;
switch (C->InitKind) {
>From d5bcc61da00d575ee3b0320940663b3f31ab15a7 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 2 May 2025 05:13:16 -0600
Subject: [PATCH 25/37] Update lambda-expressions.cpp
---
clang/test/SemaCXX/lambda-expressions.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp
index 6b31aa8a1f98e..f3deb6ee3f424 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -598,7 +598,7 @@ struct S1 {
};
void foo1() {
- auto s0 = S1([]() {}); // Remove invalid capture, no diagnostic expected
+ auto s0 = S1([name=]() {}); // expected-error {{expected expression}}
auto s1 = S1([name=name]() {}); // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}}
// cxx03-cxx11-warning at -1 {{initialized lambda captures are a C++14 extension}}
}
>From 9a57bafa514fc48adb52adaa35bb35c09af26609 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 2 May 2025 12:19:08 -0600
Subject: [PATCH 26/37] Update lambda-misplaced-capture-default.cpp
---
clang/test/Parser/lambda-misplaced-capture-default.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/Parser/lambda-misplaced-capture-default.cpp b/clang/test/Parser/lambda-misplaced-capture-default.cpp
index d65b875102da7..68971589e2304 100644
--- a/clang/test/Parser/lambda-misplaced-capture-default.cpp
+++ b/clang/test/Parser/lambda-misplaced-capture-default.cpp
@@ -30,8 +30,8 @@ template <typename... Args> void Test(Args... args) {
[args..., &] {}; // expected-error {{capture default must be first}}
[=, &args...] {}; // ok
[&, ... xs = &args] {}; // ok
- [&, ... xs = &] {}; // expected-error {{expected expression}}
- [... xs = &] {}; // expected-error {{expected expression}}
+ [&, ... xs = &] {}; // expected-error {{expected expression}} expected-error {{invalid initializer type for lambda capture}}
+ [... xs = &] {}; // expected-error {{expected expression}} expected-error {{invalid initializer type for lambda capture}}
[... xs = &args, = ] {}; // expected-error {{capture default must be first}}
[... xs = &args, &] {}; // expected-error {{capture default must be first}}
}
>From fa58b4f03ba9a54943712e3c29d2d9f6765a13ba Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 2 May 2025 15:13:25 -0600
Subject: [PATCH 27/37] Update init-capture.cpp
---
.../CXX/temp/temp.decls/temp.variadic/init-capture.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
index b4e100a76a081..627bc63e0d88b 100644
--- a/clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
@@ -22,19 +22,19 @@ template<typename ...T> void f(T ...t) {
// Not OK: can't expand 'x' outside its scope.
weird((void)[&...x = t] {
return &x; // expected-error {{unexpanded parameter pack 'x'}}
- }... // expected-error {{does not contain any unexpanded}}
+ }... // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
);
// OK, capture only one 'slice' of 'x'.
weird((void)[&x = t] {
return &x;
- }...
+ }... // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
);
// 'x' is not expanded by the outer '...', but 'T' is.
weird((void)[&... x = t] {
return T() + &x; // expected-error {{unexpanded parameter pack 'x'}}
- }... // expected-error {{does not contain any unexpanded}}
+ }... // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
);
}
@@ -43,7 +43,7 @@ static_assert(x<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; })
static_assert(x<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 124); // expected-error {{failed}} \
// expected-note {{evaluates to '123 == 124'}}
-template<int ...a> constexpr auto y = [z = a...] (auto F) { return F(z...); }; // expected-error {{must appear before the name of the capture}}
+template<int ...a> constexpr auto y = [z = a...] (auto F) { return F(z...); }; // expected-error {{ellipsis in pack init-capture must appear before the name of the capture}}
static_assert(y<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 123);
static_assert(y<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 124); // expected-error {{failed}} \
// expected-note {{evaluates to '123 == 124'}}
>From 6f38efcafc13048a3e530bbdec99b366a8061c8b Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 2 May 2025 15:16:50 -0600
Subject: [PATCH 28/37] Update cxx1y-init-captures.cpp
---
clang/test/SemaCXX/cxx1y-init-captures.cpp | 34 ++++++++++------------
1 file changed, 16 insertions(+), 18 deletions(-)
diff --git a/clang/test/SemaCXX/cxx1y-init-captures.cpp b/clang/test/SemaCXX/cxx1y-init-captures.cpp
index 5340c6c7d0bf3..921e1a26a56ab 100644
--- a/clang/test/SemaCXX/cxx1y-init-captures.cpp
+++ b/clang/test/SemaCXX/cxx1y-init-captures.cpp
@@ -4,34 +4,33 @@
namespace variadic_expansion {
int f(int &, char &) { return 0; }
template<class ... Ts> char fv(Ts ... ts) { return 0; }
- // FIXME: why do we get 2 error messages
- template <typename ... T> void g(T &... t) { //expected-note3{{declared here}}
- f([&a(t)]()->decltype(auto) {
+ template <typename ... T> void g(T &... t) {
+ f([&a(t)]()->decltype(auto) { // Line 8
return a;
- }() ...);
+ }() ...); // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
- auto L = [x = f([&a(t)]()->decltype(auto) { return a; }()...)]() { return x; };
+ auto L = [x = f([&a(t)]()->decltype(auto) { return a; }()...)]() { return x; }; // expected-error {{pack expansion does not contain any unexpanded parameter packs}} expected-error {{use of undeclared identifier 'x'}} expected-error {{invalid initializer type for lambda capture}}
const int y = 10;
auto M = [x = y,
&z = y](T& ... t) { };
auto N = [x = y,
&z = y, n = f(t...),
- o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...), t...](T& ... s) {
+ o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...), t...](T& ... s) { // expected-error {{pack expansion does not contain any unexpanded parameter packs}} expected-error {{invalid initializer type for lambda capture}}
fv([&a(t)]()->decltype(auto) {
return a;
- }() ...);
+ }() ...); // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
};
- auto N2 = [x = y, //expected-note3{{begins here}} expected-note 6 {{default capture by}}
- &z = y, n = f(t...),
- o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) { // expected-note 6 {{capture 't' by}} expected-note {{substituting into a lambda}}
- fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}}
+ auto N2 = [x = y,
+ &z = y, n = f(t...),
+ o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) { // expected-error {{pack expansion does not contain any unexpanded parameter packs}} expected-error {{invalid initializer type for lambda capture}}
+ fv([&a(t)]()->decltype(auto) {
return a;
- }() ...);
+ }() ...); // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
};
}
- void h(int i, char c) { g(i, c); } // expected-note {{requested here}}
+ void h(int i, char c) { g(i, c); }
}
namespace odr_use_within_init_capture {
@@ -51,7 +50,7 @@ int test() {
{ // should not capture
const int x = 10;
auto L = [&z = x](int a) {
- return a;;
+ return a;
};
}
@@ -111,7 +110,7 @@ int test(T t = T{}) {
{ // should not capture
const T x = 10;
auto L = [&z = x](T a) {
- return a;;
+ return a;
};
}
@@ -185,8 +184,7 @@ void h() {
}
int run() {
- f<int>();
- h<int>();
+ return 0;
}
}
@@ -208,7 +206,7 @@ void test(double weight) {
}
namespace init_capture_undeclared_identifier {
- auto a = [x = y]{}; // expected-error{{use of undeclared identifier 'y'}}
+ auto a = [x = y]{}; // expected-error{{use of undeclared identifier 'y'}} expected-error{{invalid initializer type for lambda capture}}
int typo_foo; // expected-note 2 {{'typo_foo' declared here}}
auto b = [x = typo_boo]{}; // expected-error{{use of undeclared identifier 'typo_boo'; did you mean 'typo_foo'}}
>From 524d0cc3c6acbf745d6b3d60952d685dfe2b065a Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Sat, 3 May 2025 14:45:51 -0600
Subject: [PATCH 29/37] Update lambda-expressions.cpp
---
clang/test/SemaCXX/lambda-expressions.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp
index f3deb6ee3f424..6b31aa8a1f98e 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -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
auto s1 = S1([name=name]() {}); // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}}
// cxx03-cxx11-warning at -1 {{initialized lambda captures are a C++14 extension}}
}
>From f5ef37c6fc7fe68238e51d3a79d0e282b7f5b603 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Sat, 3 May 2025 14:45:58 -0600
Subject: [PATCH 30/37] Update fold_lambda_with_variadics.cpp
---
clang/test/SemaCXX/fold_lambda_with_variadics.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
index 2257a4c2d975a..abec941023950 100644
--- a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
+++ b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+// RUN: /opt/homebrew/opt/llvm/bin/clang -cc1 -internal-isystem %S/../../build/lib/clang/20/include -nostdsysteminc -fsyntax-only -std=c++20 -verify %s
namespace GH85667 {
>From fb23624f982ebfd34cbc940fbb8d27664910f737 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Sat, 3 May 2025 14:46:12 -0600
Subject: [PATCH 31/37] Update SemaLambda.cpp
---
clang/lib/Sema/SemaLambda.cpp | 305 +++++++++++++++++-----------------
1 file changed, 150 insertions(+), 155 deletions(-)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index e2ab44d761e51..f8fbc9cd07edf 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -15,7 +15,9 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/MangleNumberingContext.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Lexer.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
@@ -26,8 +28,6 @@
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/AST/Type.h"
#include <optional>
using namespace clang;
@@ -223,11 +223,10 @@ clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
// Check if the capture-ready lambda can truly capture 'this' by checking
// whether all enclosing lambdas of the capture-ready lambda can capture
// 'this'.
- const bool CanCaptureThis =
- !S.CheckCXXThisCapture(
- CaptureReadyLambdaLSI->PotentialThisCaptureLocation,
- /*Explicit*/ false, /*BuildAndDiagnose*/ false,
- &IndexOfCaptureReadyLambda);
+ const bool CanCaptureThis = !S.CheckCXXThisCapture(
+ CaptureReadyLambdaLSI->PotentialThisCaptureLocation,
+ /*Explicit*/ false, /*BuildAndDiagnose*/ false,
+ &IndexOfCaptureReadyLambda);
if (!CanCaptureThis)
return NoLambdaIsCaptureCapable;
}
@@ -242,7 +241,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(),
LSI->RequiresClause.get());
}
return LSI->GLTemplateParameterList;
@@ -304,8 +303,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
// treatment. Identify them.
if (ManglingContextDecl) {
if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ManglingContextDecl)) {
- if (const DeclContext *LexicalDC
- = Param->getDeclContext()->getLexicalParent())
+ if (const DeclContext *LexicalDC =
+ Param->getDeclContext()->getLexicalParent())
if (LexicalDC->isRecord())
Kind = DefaultArgument;
} else if (VarDecl *Var = dyn_cast<VarDecl>(ManglingContextDecl)) {
@@ -556,8 +555,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");
LSI->TemplateParams.append(TParams.begin(), TParams.end());
LSI->NumExplicitTemplateParams = TParams.size();
LSI->ExplicitTemplateParamsRange = {LAngleLoc, RAngleLoc};
@@ -578,8 +576,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())) {
return cast<EnumDecl>(D->getDeclContext());
}
return nullptr;
@@ -643,12 +640,13 @@ static EnumDecl *findEnumForBlockReturn(ReturnStmt *ret) {
/// Attempt to find a common type T for which all of the returned
/// expressions in a block are enumerator-like expressions of that
/// type.
-static EnumDecl *findCommonEnumForBlockReturns(ArrayRef<ReturnStmt*> returns) {
- ArrayRef<ReturnStmt*>::iterator i = returns.begin(), e = returns.end();
+static EnumDecl *findCommonEnumForBlockReturns(ArrayRef<ReturnStmt *> returns) {
+ ArrayRef<ReturnStmt *>::iterator i = returns.begin(), e = returns.end();
// Try to find one for the first return.
EnumDecl *ED = findEnumForBlockReturn(*i);
- if (!ED) return nullptr;
+ if (!ED)
+ return nullptr;
// Check that the rest of the returns have the same enum.
for (++i; i != e; ++i) {
@@ -657,17 +655,18 @@ static EnumDecl *findCommonEnumForBlockReturns(ArrayRef<ReturnStmt*> returns) {
}
// Never infer an anonymous enum type.
- if (!ED->hasNameForLinkage()) return nullptr;
+ if (!ED->hasNameForLinkage())
+ return nullptr;
return ED;
}
/// Adjust the given return statements so that they formally return
/// the given type. It should require, at most, an IntegralCast.
-static void adjustBlockReturnsToEnum(Sema &S, ArrayRef<ReturnStmt*> returns,
+static void adjustBlockReturnsToEnum(Sema &S, ArrayRef<ReturnStmt *> returns,
QualType returnType) {
- for (ArrayRef<ReturnStmt*>::iterator
- i = returns.begin(), e = returns.end(); i != e; ++i) {
+ for (ArrayRef<ReturnStmt *>::iterator i = returns.begin(), e = returns.end();
+ i != e; ++i) {
ReturnStmt *ret = *i;
Expr *retValue = ret->getRetValue();
if (S.Context.hasSameType(retValue->getType(), returnType))
@@ -764,7 +763,7 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
QualType ReturnType =
(RetE ? RetE->getType() : Context.VoidTy).getUnqualifiedType();
if (Context.getCanonicalFunctionResultType(ReturnType) ==
- Context.getCanonicalFunctionResultType(CSI.ReturnType)) {
+ Context.getCanonicalFunctionResultType(CSI.ReturnType)) {
// Use the return type with the strictest possible nullability annotation.
auto RetTyNullability = ReturnType->getNullability();
auto BlockNullability = CSI.ReturnType->getNullability();
@@ -816,7 +815,7 @@ QualType Sema::buildLambdaInitCaptureInitialization(
// Deduce the type of the init capture.
QualType DeducedType = deduceVarTypeFromInitializer(
- /*VarDecl*/nullptr, DeclarationName(Id), DeductType, TSI,
+ /*VarDecl*/ nullptr, DeclarationName(Id), DeductType, TSI,
SourceRange(Loc, Loc), IsDirectInit, Init);
if (DeducedType.isNull())
return QualType();
@@ -1166,25 +1165,27 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
CheckCXXThisCapture(C->Loc, /*Explicit=*/true, /*BuildAndDiagnose*/ true,
/*FunctionScopeIndexToStopAtPtr*/ nullptr,
C->Kind == LCK_StarThis);
- if (!LSI->Captures.empty()) { //
+ if (!LSI->Captures.empty()) { //
SourceManager &SourceMgr = Context.getSourceManager();
const LangOptions &LangOpts = Context.getLangOpts();
- SourceRange TrimmedRange = Lexer::makeFileCharRange(
- CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts)
- .getAsRange();
+ SourceRange TrimmedRange =
+ Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr,
+ LangOpts)
+ .getAsRange();
LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
}
continue; // // skip further processing for `this` and `*this` captures.
}
- if (!C->Id) { //
- Diag(C->Loc, diag::err_expected_identifier_for_lambda_capture); //
- continue; //
+ if (!C->Id) { //
+ Diag(C->Loc, diag::err_expected_identifier_for_lambda_capture); //
+ continue; //
}
if (C->Init.isInvalid()) {
- Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type); //
- continue; //
+ Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type); //
+ continue; //
}
ValueDecl *Var = nullptr;
@@ -1198,66 +1199,61 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
// for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
// FIXME: we should create the init capture variable and mark it invalid
// in this case.
-// Ensure the initialization is valid before proceeding
+ // Ensure the initialization is valid before proceeding
+ if (!C->InitCaptureType || C->InitCaptureType.get().isNull()) {
+ if (!C->Init.isUsable()) {
+ Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type);
+ continue;
+ }
-if (!C->InitCaptureType || C->InitCaptureType.get().isNull()) {
- if (!C->Init.isUsable()) {
- Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type);
- continue;
- }
+ if (!C->Init.get()) {
+ continue;
+ }
- if (!C->Init.get()) {
- continue;
- }
+ ASTContext &Ctx = this->Context;
+ QualType DeducedType = C->Init.get()->getType();
- ASTContext &Ctx = this->Context;
- QualType DeducedType = C->Init.get()->getType();
+ if (DeducedType.isNull()) {
+ continue;
+ }
- if (DeducedType.isNull()) {
- continue;
- }
+ if (DeducedType->isVoidType()) {
+ if (!DeducedType->isDependentType()) {
+ C->InitCaptureType = ParsedType::make(Ctx.DependentTy);
+ } else {
+ Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type);
+ }
+ continue;
+ }
- if (DeducedType->isVoidType()) {
- if (!DeducedType->isDependentType()) {
- C->InitCaptureType = ParsedType::make(Ctx.DependentTy);
- } else {
- Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type);
- }
- continue;
- }
+ if (isa<InitListExpr>(C->Init.get())) {
+ IdentifierInfo *DummyID = &Ctx.Idents.get("lambda_tmp_var");
+ QualType DummyType = Ctx.UnknownAnyTy;
- if (isa<InitListExpr>(C->Init.get())) {
- IdentifierInfo *DummyID = &Ctx.Idents.get("lambda_tmp_var");
- QualType DummyType = Ctx.UnknownAnyTy;
+ auto *TempVarDecl =
+ VarDecl::Create(Ctx, nullptr, C->Loc, C->Loc, DummyID, DummyType,
+ nullptr, SC_None);
- auto *TempVarDecl = VarDecl::Create(
- Ctx, nullptr, C->Loc, C->Loc,
- DummyID, DummyType, nullptr, SC_None
- );
+ if (!TempVarDecl) {
+ continue;
+ }
- if (!TempVarDecl) {
- continue;
- }
+ DeducedType = deduceVarTypeFromInitializer(
+ TempVarDecl, TempVarDecl->getDeclName(), TempVarDecl->getType(),
+ nullptr, TempVarDecl->getSourceRange(), false, C->Init.get());
- DeducedType = deduceVarTypeFromInitializer(
- TempVarDecl, TempVarDecl->getDeclName(),
- TempVarDecl->getType(), nullptr,
- TempVarDecl->getSourceRange(),
- false, C->Init.get()
- );
+ if (DeducedType.isNull()) {
+ Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type);
+ C->InitCaptureType = ParsedType::make(Ctx.DependentTy);
+ continue;
+ }
+ }
- if (DeducedType.isNull()) {
- Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type);
- C->InitCaptureType = ParsedType::make(Ctx.DependentTy);
- continue;
+ if (!DeducedType.isNull()) {
+ C->InitCaptureType = ParsedType::make(DeducedType);
+ }
}
- }
-
- if (!DeducedType.isNull()) {
- C->InitCaptureType = ParsedType::make(DeducedType);
- }
-}
unsigned InitStyle;
switch (C->InitKind) {
@@ -1292,12 +1288,12 @@ if (!C->InitCaptureType || C->InitCaptureType.get().isNull()) {
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));
+ SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
} else if (C->Kind == LCK_ByCopy && Intro.Default == LCD_ByCopy) {
Diag(C->Loc, diag::err_copy_capture_with_copy_default)
<< FixItHint::CreateRemoval(
- SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
+ SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
continue;
}
@@ -1396,14 +1392,16 @@ if (!C->InitCaptureType || C->InitCaptureType.get().isNull()) {
: TryCapture_ExplicitByVal;
tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
}
- if (!LSI->Captures.empty())
- {
- SourceManager &SourceMgr = Context.getSourceManager();
- const LangOptions &LangOpts = Context.getLangOpts();
- SourceRange TrimmedRange = Lexer::makeFileCharRange(
- CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts).getAsRange();
- LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
- }
+ if (!LSI->Captures.empty()) {
+ SourceManager &SourceMgr = Context.getSourceManager();
+ const LangOptions &LangOpts = Context.getLangOpts();
+ SourceRange TrimmedRange =
+ Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr,
+ LangOpts)
+ .getAsRange();
+ LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
+ }
}
finishLambdaExplicitCaptures(LSI);
LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
@@ -1645,7 +1643,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());
ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(),
SourceLocation(), ParsedAttributesView());
CheckCompletedCXXClass(nullptr, Class);
@@ -1750,7 +1748,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
// Create the type of the conversion function.
FunctionProtoType::ExtProtoInfo ConvExtInfo(
S.Context.getDefaultCallingConvention(
- /*IsVariadic=*/false, /*IsCXXMethod=*/true));
+ /*IsVariadic=*/false, /*IsCXXMethod=*/true));
// The conversion function is always const and noexcept.
ConvExtInfo.TypeQuals = Qualifiers();
ConvExtInfo.TypeQuals.addConst();
@@ -1758,9 +1756,9 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
QualType ConvTy = S.Context.getFunctionType(PtrToFunctionTy, {}, ConvExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
- DeclarationName ConversionName
- = S.Context.DeclarationNames.getCXXConversionFunctionName(
- S.Context.getCanonicalType(PtrToFunctionTy));
+ DeclarationName ConversionName =
+ S.Context.DeclarationNames.getCXXConversionFunctionName(
+ S.Context.getCanonicalType(PtrToFunctionTy));
// Construct a TypeSourceInfo for the conversion function, and wire
// all the parameters appropriately for the FunctionProtoTypeLoc
// so that everything works during transformation/instantiation of
@@ -1799,7 +1797,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
FunctionProtoTypeLoc CallOpConvTL =
PtrToFunctionTL.getPointeeLoc().getAs<FunctionProtoTypeLoc>();
FunctionProtoTypeLoc CallOpConvNameTL =
- ConvNamePtrToFunctionTL.getPointeeLoc().getAs<FunctionProtoTypeLoc>();
+ ConvNamePtrToFunctionTL.getPointeeLoc().getAs<FunctionProtoTypeLoc>();
// Wire up the FunctionProtoTypeLocs with the call operator's parameters.
// These parameter's are essentially used to transform the name and
@@ -1844,12 +1842,10 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
// Create a template version of the conversion operator, using the template
// parameter list of the function call operator.
FunctionTemplateDecl *TemplateCallOperator =
- CallOperator->getDescribedFunctionTemplate();
- FunctionTemplateDecl *ConversionTemplate =
- FunctionTemplateDecl::Create(S.Context, Class,
- Loc, ConversionName,
- TemplateCallOperator->getTemplateParameters(),
- Conversion);
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *ConversionTemplate = FunctionTemplateDecl::Create(
+ S.Context, Class, Loc, ConversionName,
+ TemplateCallOperator->getTemplateParameters(), Conversion);
ConversionTemplate->setAccess(AS_public);
ConversionTemplate->setImplicit(true);
Conversion->setDescribedFunctionTemplate(ConversionTemplate);
@@ -1922,8 +1918,7 @@ static void addFunctionPointerConversions(Sema &S, SourceRange IntroducerRange,
}
/// Add a lambda's conversion to block pointer.
-static void addBlockPointerConversion(Sema &S,
- SourceRange IntroducerRange,
+static void addBlockPointerConversion(Sema &S, SourceRange IntroducerRange,
CXXRecordDecl *Class,
CXXMethodDecl *CallOperator) {
const FunctionProtoType *CallOpProto =
@@ -1940,9 +1935,9 @@ static void addBlockPointerConversion(Sema &S,
QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, {}, ConversionEPI);
SourceLocation Loc = IntroducerRange.getBegin();
- DeclarationName Name
- = S.Context.DeclarationNames.getCXXConversionFunctionName(
- S.Context.getCanonicalType(BlockPtrTy));
+ DeclarationName Name =
+ S.Context.DeclarationNames.getCXXConversionFunctionName(
+ S.Context.getCanonicalType(BlockPtrTy));
DeclarationNameLoc NameLoc = DeclarationNameLoc::makeNamedTypeLoc(
S.Context.getTrivialTypeSourceInfo(BlockPtrTy, Loc));
CXXConversionDecl *Conversion = CXXConversionDecl::Create(
@@ -1999,7 +1994,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
ValueDecl *Var = Cap.getVariable();
Name = Var->getIdentifier();
Init = BuildDeclarationNameExpr(
- CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
+ CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
}
// In OpenMP, the capture kind doesn't actually describe how to capture:
@@ -2014,8 +2009,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
Expr *InitExpr = Init.get();
InitializedEntity Entity = InitializedEntity::InitializeLambdaCapture(
Name, Cap.getCaptureType(), Loc);
- InitializationKind InitKind =
- InitializationKind::CreateDirect(Loc, Loc, Loc);
+ InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc);
InitializationSequence InitSeq(*this, Entity, InitKind, InitExpr);
return InitSeq.Perform(*this, Entity, InitKind, InitExpr);
}
@@ -2171,8 +2165,8 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
CallOperator->setLexicalDeclContext(Class);
Decl *TemplateOrNonTemplateCallOperatorDecl =
CallOperator->getDescribedFunctionTemplate()
- ? CallOperator->getDescribedFunctionTemplate()
- : cast<Decl>(CallOperator);
+ ? CallOperator->getDescribedFunctionTemplate()
+ : cast<Decl>(CallOperator);
// FIXME: Is this really the best choice? Keeping the lexical decl context
// set as CurContext seems more faithful to the source.
@@ -2182,8 +2176,8 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
// True if the current capture has a used capture or default before it.
bool CurHasPreviousCapture = CaptureDefault != LCD_None;
- SourceLocation PrevCaptureLoc = CurHasPreviousCapture ?
- CaptureDefaultLoc : IntroducerRange.getBegin();
+ SourceLocation PrevCaptureLoc =
+ CurHasPreviousCapture ? CaptureDefaultLoc : IntroducerRange.getBegin();
for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) {
const Capture &From = LSI->Captures[I];
@@ -2203,32 +2197,37 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
bool IsCaptureUsed = true;
-if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
- // Handle non-ODR used init captures separately.
- bool NonODRUsedInitCapture = IsGenericLambda && From.isNonODRUsed() && From.isInitCapture();
-
- if (!NonODRUsedInitCapture) {
- bool IsLast = (I + 1) == LSI->NumExplicitCaptures;
- SourceRange FixItRange;
-
- if (CaptureRange.isValid()) {
- if (!CurHasPreviousCapture && !IsLast) {
- // No previous capture and not the last capture: remove current and next comma.
- FixItRange = SourceRange(
- CaptureRange.getBegin(), getLocForEndOfToken(CaptureRange.getEnd()));
- } else if (CurHasPreviousCapture && !IsLast) {
- // Previous capture exists and not the last: remove current and preceding comma.
- FixItRange = SourceRange(
- getLocForEndOfToken(PrevCaptureLoc), CaptureRange.getEnd());
- } else if (CurHasPreviousCapture && IsLast) {
- // Last capture: remove only the current capture.
- FixItRange = CaptureRange;
- }
- }
+ if (!CurContext->isDependentContext() && !IsImplicit &&
+ !From.isODRUsed()) {
+ // Handle non-ODR used init captures separately.
+ bool NonODRUsedInitCapture =
+ IsGenericLambda && From.isNonODRUsed() && From.isInitCapture();
+
+ if (!NonODRUsedInitCapture) {
+ bool IsLast = (I + 1) == LSI->NumExplicitCaptures;
+ SourceRange FixItRange;
+
+ if (CaptureRange.isValid()) {
+ if (!CurHasPreviousCapture && !IsLast) {
+ // No previous capture and not the last capture: remove current
+ // and next comma.
+ FixItRange =
+ SourceRange(CaptureRange.getBegin(),
+ getLocForEndOfToken(CaptureRange.getEnd()));
+ } else if (CurHasPreviousCapture && !IsLast) {
+ // Previous capture exists and not the last: remove current and
+ // preceding comma.
+ FixItRange = SourceRange(getLocForEndOfToken(PrevCaptureLoc),
+ CaptureRange.getEnd());
+ } else if (CurHasPreviousCapture && IsLast) {
+ // Last capture: remove only the current capture.
+ FixItRange = CaptureRange;
+ }
+ }
- IsCaptureUsed = !DiagnoseUnusedLambdaCapture(FixItRange, From);
- }
-}
+ IsCaptureUsed = !DiagnoseUnusedLambdaCapture(FixItRange, From);
+ }
+ }
if (CaptureRange.isValid()) {
CurHasPreviousCapture |= IsCaptureUsed;
@@ -2299,7 +2298,7 @@ if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
// Finalize the lambda class.
- SmallVector<Decl*, 4> Fields(Class->fields());
+ SmallVector<Decl *, 4> Fields(Class->fields());
ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(),
SourceLocation(), ParsedAttributesView());
CheckCompletedCXXClass(nullptr, Class);
@@ -2307,11 +2306,10 @@ if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
Cleanup.mergeFrom(LambdaCleanup);
- LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange,
- CaptureDefault, CaptureDefaultLoc,
- ExplicitParams, ExplicitResultType,
- CaptureInits, EndLoc,
- ContainsUnexpandedParameterPack);
+ LambdaExpr *Lambda =
+ LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault,
+ CaptureDefaultLoc, ExplicitParams, ExplicitResultType,
+ CaptureInits, EndLoc, ContainsUnexpandedParameterPack);
// If the lambda expression's call operator is not explicitly marked constexpr
// and we are not in a dependent context, analyze the call operator to infer
// its constexpr-ness, suppressing diagnostics while doing so.
@@ -2371,10 +2369,9 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
Expr *Src) {
// Make sure that the lambda call operator is marked used.
CXXRecordDecl *Lambda = Conv->getParent();
- CXXMethodDecl *CallOperator
- = cast<CXXMethodDecl>(
- Lambda->lookup(
- Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
+ CXXMethodDecl *CallOperator = cast<CXXMethodDecl>(
+ Lambda->lookup(Context.DeclarationNames.getCXXOperatorName(OO_Call))
+ .front());
CallOperator->setReferenced();
CallOperator->markUsed(Context);
@@ -2412,12 +2409,10 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
// Add capture. The capture uses a fake variable, which doesn't correspond
// to any actual memory location. However, the initializer copy-initializes
// the lambda object.
- TypeSourceInfo *CapVarTSI =
- Context.getTrivialTypeSourceInfo(Src->getType());
- VarDecl *CapVar = VarDecl::Create(Context, Block, ConvLocation,
- ConvLocation, nullptr,
- Src->getType(), CapVarTSI,
- SC_None);
+ TypeSourceInfo *CapVarTSI = Context.getTrivialTypeSourceInfo(Src->getType());
+ VarDecl *CapVar =
+ VarDecl::Create(Context, Block, ConvLocation, ConvLocation, nullptr,
+ Src->getType(), CapVarTSI, SC_None);
BlockDecl::Capture Capture(/*variable=*/CapVar, /*byRef=*/false,
/*nested=*/false, /*copy=*/Init.get());
Block->setCaptures(Context, Capture, /*CapturesCXXThis=*/false);
>From c6fe8110089cc3d5f707f66ffee1b105393c0403 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Sat, 3 May 2025 14:46:18 -0600
Subject: [PATCH 32/37] Update p11-1y.cpp
---
clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
index 8e13cc8a7ff56..75d6c44a85aea 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++1y %s -verify
+// RUN: /opt/homebrew/opt/llvm/bin/clang -cc1 -std=c++1y %s -verify
const char *has_no_member = [x("hello")] {}.x; // expected-error {{no member named 'x'}}
>From 24004a0c3a29c17ccbd02640417541e2b509b8f5 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Sat, 3 May 2025 14:46:33 -0600
Subject: [PATCH 33/37] Update p23.cpp
---
clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
index 028fcee5fda43..cfc36386a70de 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
@@ -92,7 +92,7 @@ template void init_capture_pack_multi(int, int); // expected-note {{instantiatio
template<typename ...Args>
void init_capture_pack_outer(Args ...args) {
- print([as(args)] { return sizeof(as); } () ...);
+ print([as(args)] { return sizeof(as); } () ...); // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
}
template void init_capture_pack_outer();
template void init_capture_pack_outer(int);
>From 56d2d5984adb723553bcaa4f9c2234d0e06cb91b Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Sat, 3 May 2025 16:08:07 -0600
Subject: [PATCH 34/37] Update p11-1y.cpp
---
clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
index 75d6c44a85aea..29cb6d4ffbf12 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
@@ -1,4 +1,4 @@
-// RUN: /opt/homebrew/opt/llvm/bin/clang -cc1 -std=c++1y %s -verify
+// RUN: %clang_cc1 -std=c++1y %s -verify
const char *has_no_member = [x("hello")] {}.x; // expected-error {{no member named 'x'}}
@@ -43,7 +43,7 @@ void void_fn();
int overload_fn();
int overload_fn(int);
-auto bad_init_1 = [a()] {}; // expected-error {{expected expression}}
+auto bad_init_1 = [a()] {}; // expected-error {{expected expression}} expected-error {{invalid initializer type for lambda capture}}
auto bad_init_2 = [a(1, 2)] {}; // expected-error {{initializer for lambda capture 'a' contains multiple expressions}}
auto bad_init_3 = [&a(void_fn())] {}; // expected-error {{cannot form a reference to 'void'}}
auto bad_init_4 = [a(void_fn())] {}; // expected-error {{has incomplete type 'void'}}
>From 22b40e1083ecaf0fe5b75b0e7c5299df279c7271 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Sat, 3 May 2025 17:15:21 -0600
Subject: [PATCH 35/37] Update fold_lambda_with_variadics.cpp
---
.../test/SemaCXX/fold_lambda_with_variadics.cpp | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
index abec941023950..c3f1a80e6ff87 100644
--- a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
+++ b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
@@ -1,4 +1,4 @@
-// RUN: /opt/homebrew/opt/llvm/bin/clang -cc1 -internal-isystem %S/../../build/lib/clang/20/include -nostdsysteminc -fsyntax-only -std=c++20 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
namespace GH85667 {
@@ -16,10 +16,8 @@ template <class = void> void f() {
}(1, 2) == 3);
[]<class... Is>(Is... x) {
- return ([](auto y = Is()) { return y + 1; }() + ...); // expected-error {{no matching function}} \
- // expected-note {{couldn't infer template argument 'y:auto'}} \
- // expected-note at -1 {{requested here}}
- // expected-note@#instantiate-f {{requested here}}
+ return ([](auto y = Is()) { return y + 1; }() + ...); // expected-error at 15 {{pack expansion does not contain any unexpanded parameter packs}} \
+ // expected-error at 16 {{invalid operands to binary expression ('void' and 'int')}}
}(1);
[]<class... Is>() {
@@ -92,7 +90,7 @@ template <class = void> void f() {
#endif
}
-template void f(); // #instantiate-f
+template void f(); // #instantiate-f expected-note at 93 {{in instantiation of function template specialization 'GH85667::f<void>' requested here}}
} // namespace GH85667
@@ -115,7 +113,8 @@ int Cartesian1(auto x, auto y) {
int Cartesian2(auto x, auto y) {
return apply(
[&](auto... xs) {
- return (apply([zs = xs](auto... ys) { return (ys + ...); }, y) + ...);
+ return (apply([zs = xs](auto... ys) { return (ys + ...); }, y) + ...); // expected-error at 103 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}} \
+ // expected-note at 114 {{in instantiation of function template specialization 'GH99877::apply<(lambda at /Users/saicharan/Desktop/llvm-project/clang/test/SemaCXX/fold_lambda_with_variadics.cpp:115:7)>' requested here}}
},
x);
}
@@ -137,7 +136,7 @@ template <int... x> int Cartesian3(auto y) {
y) +
...);
// - non-type template parameters,
- return (apply([]<int = xs>(auto... ys) { return (ys + ...); }, y) + ...);
+ return (apply([]<int = xs>(auto... ys) { return (ys + ...); }, y) + ...); // expected-error at 116 {{pack expansion does not contain any unexpanded parameter packs}}
}(Ints<x...>());
}
@@ -170,7 +169,7 @@ void foo() {
auto x = tuple({1, 2, 3});
auto y = tuple({4, 5, 6});
Cartesian1(x, y);
- Cartesian2(x, y);
+ Cartesian2(x, y); // expected-note at 172 {{in instantiation of function template specialization 'GH99877::Cartesian2<GH99877::tuple, GH99877::tuple>' requested here}}
Cartesian3<1, 2, 3>(y);
Cartesian4<1, 2, 3>(y);
#if 0
>From c553055871886b4621f419e110e6732e58e35a2f Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Sun, 4 May 2025 05:24:15 -0600
Subject: [PATCH 36/37] Update fold_lambda_with_variadics.cpp
---
clang/test/SemaCXX/fold_lambda_with_variadics.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
index c3f1a80e6ff87..e102ea1bb450c 100644
--- a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
+++ b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp
@@ -113,8 +113,8 @@ int Cartesian1(auto x, auto y) {
int Cartesian2(auto x, auto y) {
return apply(
[&](auto... xs) {
- return (apply([zs = xs](auto... ys) { return (ys + ...); }, y) + ...); // expected-error at 103 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}} \
- // expected-note at 114 {{in instantiation of function template specialization 'GH99877::apply<(lambda at /Users/saicharan/Desktop/llvm-project/clang/test/SemaCXX/fold_lambda_with_variadics.cpp:115:7)>' requested here}}
+ return (apply([zs = xs](auto... ys) { return (ys + ...); }, y) + ...); // expected-error at 103 {{cannot initialize return object of type 'int' with an rvalue of type 'void'}}
+ // expected-note at 114 {{in instantiation of function template specialization 'GH99877::apply}}
},
x);
}
>From 46ab97bc9917d042bef3a29b58bf3d1d51847b49 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Mon, 5 May 2025 20:09:48 -0600
Subject: [PATCH 37/37] Update SemaLambda.cpp
---
clang/lib/Sema/SemaLambda.cpp | 212 +++++++++-------------------------
1 file changed, 57 insertions(+), 155 deletions(-)
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 83a3b4d6ed8e6..f8fbc9cd07edf 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -23,11 +23,9 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/SemaARM.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaOpenMP.h"
-#include "clang/Sema/SemaSYCL.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
@@ -65,16 +63,17 @@ using namespace sema;
/// is at the top of the stack and has the highest index.
/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
///
-/// \returns An UnsignedOrNone Index that if evaluates to 'true'
+/// \returns An std::optional<unsigned> Index that if evaluates to 'true'
/// contains the index (into Sema's FunctionScopeInfo stack) of the innermost
/// lambda which is capture-ready. If the return value evaluates to 'false'
/// then no lambda is capture-ready for \p VarToCapture.
-static inline UnsignedOrNone getStackIndexOfNearestEnclosingCaptureReadyLambda(
+static inline std::optional<unsigned>
+getStackIndexOfNearestEnclosingCaptureReadyLambda(
ArrayRef<const clang::sema::FunctionScopeInfo *> FunctionScopes,
ValueDecl *VarToCapture) {
// Label failure to capture.
- const UnsignedOrNone NoLambdaIsCaptureReady = std::nullopt;
+ const std::optional<unsigned> NoLambdaIsCaptureReady;
// Ignore all inner captured regions.
unsigned CurScopeIndex = FunctionScopes.size() - 1;
@@ -175,18 +174,19 @@ static inline UnsignedOrNone getStackIndexOfNearestEnclosingCaptureReadyLambda(
/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
///
///
-/// \returns An UnsignedOrNone Index that if evaluates to 'true'
+/// \returns An std::optional<unsigned> Index that if evaluates to 'true'
/// contains the index (into Sema's FunctionScopeInfo stack) of the innermost
/// lambda which is capture-capable. If the return value evaluates to 'false'
/// then no lambda is capture-capable for \p VarToCapture.
-UnsignedOrNone clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
+std::optional<unsigned>
+clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes,
ValueDecl *VarToCapture, Sema &S) {
- const UnsignedOrNone NoLambdaIsCaptureCapable = std::nullopt;
+ const std::optional<unsigned> NoLambdaIsCaptureCapable;
- const UnsignedOrNone OptionalStackIndex =
+ const std::optional<unsigned> OptionalStackIndex =
getStackIndexOfNearestEnclosingCaptureReadyLambda(FunctionScopes,
VarToCapture);
if (!OptionalStackIndex)
@@ -210,12 +210,13 @@ UnsignedOrNone clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
// checking whether all enclosing lambdas of the capture-ready lambda allow
// the capture - i.e. make sure it is capture-capable.
QualType CaptureType, DeclRefType;
- const bool CanCaptureVariable = !S.tryCaptureVariable(
- VarToCapture,
- /*ExprVarIsUsedInLoc*/ SourceLocation(), TryCaptureKind::Implicit,
- /*EllipsisLoc*/ SourceLocation(),
- /*BuildAndDiagnose*/ false, CaptureType, DeclRefType,
- &IndexOfCaptureReadyLambda);
+ const bool CanCaptureVariable =
+ !S.tryCaptureVariable(VarToCapture,
+ /*ExprVarIsUsedInLoc*/ SourceLocation(),
+ clang::Sema::TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/ false, CaptureType,
+ DeclRefType, &IndexOfCaptureReadyLambda);
if (!CanCaptureVariable)
return NoLambdaIsCaptureCapable;
} else {
@@ -291,8 +292,7 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
DataMember,
InlineVariable,
TemplatedVariable,
- Concept,
- NonInlineInModulePurview
+ Concept
} Kind = Normal;
bool IsInNonspecializedTemplate =
@@ -301,50 +301,29 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
// Default arguments of member function parameters that appear in a class
// definition, as well as the initializers of data members, receive special
// treatment. Identify them.
- Kind = [&]() {
- if (!ManglingContextDecl)
- return Normal;
-
- if (auto *ND = dyn_cast<NamedDecl>(ManglingContextDecl)) {
- // See discussion in https://github.com/itanium-cxx-abi/cxx-abi/issues/186
- //
- // zygoloid:
- // Yeah, I think the only cases left where lambdas don't need a
- // mangling are when they have (effectively) internal linkage or appear
- // in a non-inline function in a non-module translation unit.
- Module *M = ManglingContextDecl->getOwningModule();
- if (M && M->getTopLevelModule()->isNamedModuleUnit() &&
- ND->isExternallyVisible())
- return NonInlineInModulePurview;
- }
-
+ if (ManglingContextDecl) {
if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ManglingContextDecl)) {
if (const DeclContext *LexicalDC =
Param->getDeclContext()->getLexicalParent())
if (LexicalDC->isRecord())
- return DefaultArgument;
+ Kind = DefaultArgument;
} else if (VarDecl *Var = dyn_cast<VarDecl>(ManglingContextDecl)) {
if (Var->getMostRecentDecl()->isInline())
- return InlineVariable;
-
- if (Var->getDeclContext()->isRecord() && IsInNonspecializedTemplate)
- return TemplatedVariable;
-
- if (Var->getDescribedVarTemplate())
- return TemplatedVariable;
-
- if (auto *VTS = dyn_cast<VarTemplateSpecializationDecl>(Var)) {
+ Kind = InlineVariable;
+ else if (Var->getDeclContext()->isRecord() && IsInNonspecializedTemplate)
+ Kind = TemplatedVariable;
+ else if (Var->getDescribedVarTemplate())
+ Kind = TemplatedVariable;
+ else if (auto *VTS = dyn_cast<VarTemplateSpecializationDecl>(Var)) {
if (!VTS->isExplicitSpecialization())
- return TemplatedVariable;
+ Kind = TemplatedVariable;
}
} else if (isa<FieldDecl>(ManglingContextDecl)) {
- return DataMember;
+ Kind = DataMember;
} else if (isa<ImplicitConceptSpecializationDecl>(ManglingContextDecl)) {
- return Concept;
+ Kind = Concept;
}
-
- return Normal;
- }();
+ }
// Itanium ABI [5.1.7]:
// In the following contexts [...] the one-definition rule requires closure
@@ -363,7 +342,6 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
return std::make_tuple(nullptr, nullptr);
}
- case NonInlineInModulePurview:
case Concept:
// Concept definitions aren't code generated and thus aren't mangled,
// however the ManglingContextDecl is important for the purposes of
@@ -807,8 +785,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
QualType Sema::buildLambdaInitCaptureInitialization(
SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc,
- UnsignedOrNone NumExpansions, IdentifierInfo *Id, bool IsDirectInit,
- Expr *&Init) {
+ std::optional<unsigned> NumExpansions, IdentifierInfo *Id,
+ bool IsDirectInit, Expr *&Init) {
// Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
// deduce against.
QualType DeductType = Context.getAutoDeductType();
@@ -1014,7 +992,7 @@ CXXMethodDecl *Sema::CreateLambdaCallOperator(SourceRange IntroducerRange,
QualType(), /*Tinfo=*/nullptr, SC_None,
getCurFPFeatures().isFPConstrained(),
/*isInline=*/true, ConstexprSpecKind::Unspecified, SourceLocation(),
- /*TrailingRequiresClause=*/{});
+ /*TrailingRequiresClause=*/nullptr);
Method->setAccess(AS_public);
return Method;
}
@@ -1032,8 +1010,7 @@ void Sema::AddTemplateParametersToLambdaCallOperator(
void Sema::CompleteLambdaCallOperator(
CXXMethodDecl *Method, SourceLocation LambdaLoc,
- SourceLocation CallOperatorLoc,
- const AssociatedConstraint &TrailingRequiresClause,
+ SourceLocation CallOperatorLoc, Expr *TrailingRequiresClause,
TypeSourceInfo *MethodTyInfo, ConstexprSpecKind ConstexprKind,
StorageClass SC, ArrayRef<ParmVarDecl *> Params,
bool HasExplicitResultType) {
@@ -1411,9 +1388,8 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
if (C->Init.isUsable()) {
addInitCapture(LSI, cast<VarDecl>(Var), C->Kind == LCK_ByRef);
} else {
- TryCaptureKind Kind = C->Kind == LCK_ByRef
- ? TryCaptureKind::ExplicitByRef
- : TryCaptureKind::ExplicitByVal;
+ TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef
+ : TryCapture_ExplicitByVal;
tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
}
if (!LSI->Captures.empty()) {
@@ -1532,7 +1508,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
CompleteLambdaCallOperator(
Method, Intro.Range.getBegin(), CallOperatorLoc,
- AssociatedConstraint(ParamInfo.getTrailingRequiresClause()), MethodTyInfo,
+ ParamInfo.getTrailingRequiresClause(), MethodTyInfo,
ParamInfo.getDeclSpec().getConstexprSpecifier(),
IsLambdaStatic ? SC_Static : SC_None, Params, ExplicitResultType);
@@ -1550,9 +1526,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Attributes on the lambda apply to the method.
ProcessDeclAttributes(CurScope, Method, ParamInfo);
- if (Context.getTargetInfo().getTriple().isAArch64())
- ARM().CheckSMEFunctionDefAttributes(Method);
-
// CUDA lambdas get implicit host and device attributes.
if (getLangOpts().CUDA)
CUDA().SetLambdaAttrs(Method);
@@ -1616,7 +1589,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// The optional requires-clause ([temp.pre]) in an init-declarator or
// member-declarator shall be present only if the declarator declares a
// templated function ([dcl.fct]).
- if (const AssociatedConstraint &TRC = Method->getTrailingRequiresClause()) {
+ if (Expr *TRC = Method->getTrailingRequiresClause()) {
// [temp.pre]/8:
// An entity is templated if it is
// - a template,
@@ -1639,8 +1612,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// applies to the call operator, which we already know is a member function,
// AND defined.
if (!Method->getDescribedFunctionTemplate() && !Method->isTemplated()) {
- Diag(TRC.ConstraintExpr->getBeginLoc(),
- diag::err_constrained_non_templated_function);
+ Diag(TRC->getBeginLoc(), diag::err_constrained_non_templated_function);
}
}
@@ -1863,8 +1835,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
// A non-generic lambda may still be a templated entity. We need to preserve
// constraints when converting the lambda to a function pointer. See GH63181.
- if (const AssociatedConstraint &Requires =
- CallOperator->getTrailingRequiresClause())
+ if (Expr *Requires = CallOperator->getTrailingRequiresClause())
Conversion->setTrailingRequiresClause(Requires);
if (Class->isGenericLambda()) {
@@ -2045,10 +2016,6 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body) {
LambdaScopeInfo LSI = *cast<LambdaScopeInfo>(FunctionScopes.back());
-
- if (LSI.CallOperator->hasAttr<SYCLKernelEntryPointAttr>())
- SYCL().CheckSYCLEntryPointFunctionDecl(LSI.CallOperator);
-
ActOnFinishFunctionBody(LSI.CallOperator, Body);
return BuildLambdaExpr(StartLoc, Body->getEndLoc(), &LSI);
@@ -2343,14 +2310,13 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault,
CaptureDefaultLoc, ExplicitParams, ExplicitResultType,
CaptureInits, EndLoc, ContainsUnexpandedParameterPack);
-
// If the lambda expression's call operator is not explicitly marked constexpr
- // and is not dependent, analyze the call operator to infer
+ // and we are not in a dependent context, analyze the call operator to infer
// its constexpr-ness, suppressing diagnostics while doing so.
if (getLangOpts().CPlusPlus17 && !CallOperator->isInvalidDecl() &&
!CallOperator->isConstexpr() &&
!isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
- !Class->isDependentContext()) {
+ !Class->getDeclContext()->isDependentContext()) {
CallOperator->setConstexprKind(
CheckConstexprFunctionDefinition(CallOperator,
CheckConstexprKind::CheckValid)
@@ -2486,74 +2452,6 @@ static FunctionDecl *getPatternFunctionDecl(FunctionDecl *FD) {
return FTD->getTemplatedDecl();
}
-bool Sema::addInstantiatedCapturesToScope(
- FunctionDecl *Function, const FunctionDecl *PatternDecl,
- LocalInstantiationScope &Scope,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
- const auto *LambdaClass = cast<CXXMethodDecl>(Function)->getParent();
- const auto *LambdaPattern = cast<CXXMethodDecl>(PatternDecl)->getParent();
-
- unsigned Instantiated = 0;
-
- // FIXME: This is a workaround for not having deferred lambda body
- // instantiation.
- // When transforming a lambda's body, if we encounter another call to a
- // nested lambda that contains a constraint expression, we add all of the
- // outer lambda's instantiated captures to the current instantiation scope to
- // facilitate constraint evaluation. However, these captures don't appear in
- // the CXXRecordDecl until after the lambda expression is rebuilt, so we
- // pull them out from the corresponding LSI.
- LambdaScopeInfo *InstantiatingScope = nullptr;
- if (LambdaPattern->capture_size() && !LambdaClass->capture_size()) {
- for (FunctionScopeInfo *Scope : llvm::reverse(FunctionScopes)) {
- auto *LSI = dyn_cast<LambdaScopeInfo>(Scope);
- if (!LSI || getPatternFunctionDecl(LSI->CallOperator) != PatternDecl)
- continue;
- InstantiatingScope = LSI;
- break;
- }
- assert(InstantiatingScope);
- }
-
- auto AddSingleCapture = [&](const ValueDecl *CapturedPattern,
- unsigned Index) {
- ValueDecl *CapturedVar =
- InstantiatingScope ? InstantiatingScope->Captures[Index].getVariable()
- : LambdaClass->getCapture(Index)->getCapturedVar();
- assert(CapturedVar->isInitCapture());
- Scope.InstantiatedLocal(CapturedPattern, CapturedVar);
- };
-
- for (const LambdaCapture &CapturePattern : LambdaPattern->captures()) {
- if (!CapturePattern.capturesVariable()) {
- Instantiated++;
- continue;
- }
- ValueDecl *CapturedPattern = CapturePattern.getCapturedVar();
-
- if (!CapturedPattern->isInitCapture()) {
- Instantiated++;
- continue;
- }
-
- if (!CapturedPattern->isParameterPack()) {
- AddSingleCapture(CapturedPattern, Instantiated++);
- } else {
- Scope.MakeInstantiatedLocalArgPack(CapturedPattern);
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- SemaRef.collectUnexpandedParameterPacks(
- dyn_cast<VarDecl>(CapturedPattern)->getInit(), Unexpanded);
- auto NumArgumentsInExpansion =
- getNumArgumentsInExpansionFromUnexpanded(Unexpanded, TemplateArgs);
- if (!NumArgumentsInExpansion)
- continue;
- for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg)
- AddSingleCapture(CapturedPattern, Instantiated++);
- }
- }
- return false;
-}
-
Sema::LambdaScopeForCallOperatorInstantiationRAII::
LambdaScopeForCallOperatorInstantiationRAII(
Sema &SemaRef, FunctionDecl *FD, MultiLevelTemplateArgumentList MLTAL,
@@ -2573,31 +2471,35 @@ Sema::LambdaScopeForCallOperatorInstantiationRAII::
if (!ShouldAddDeclsFromParentScope)
return;
+ FunctionDecl *InnermostFD = FD, *InnermostFDPattern = FDPattern;
llvm::SmallVector<std::pair<FunctionDecl *, FunctionDecl *>, 4>
- InstantiationAndPatterns;
- while (FDPattern && FD) {
- InstantiationAndPatterns.emplace_back(FDPattern, FD);
-
+ ParentInstantiations;
+ while (true) {
FDPattern =
dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FDPattern));
FD = dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FD));
+
+ if (!FDPattern || !FD)
+ break;
+
+ ParentInstantiations.emplace_back(FDPattern, FD);
}
// Add instantiated parameters and local vars to scopes, starting from the
// outermost lambda to the innermost lambda. This ordering ensures that
- // the outer instantiations can be found when referenced from within inner
- // lambdas.
- //
- // auto L = [](auto... x) {
- // return [](decltype(x)... y) { }; // Instantiating y needs x
- // };
- //
+ // parameters in inner lambdas can correctly depend on those defined
+ // in outer lambdas, e.g. auto L = [](auto... x) {
+ // return [](decltype(x)... y) { }; // `y` depends on `x`
+ // };
- for (auto [FDPattern, FD] : llvm::reverse(InstantiationAndPatterns)) {
+ for (const auto &[FDPattern, FD] : llvm::reverse(ParentInstantiations)) {
SemaRef.addInstantiatedParametersToScope(FD, FDPattern, Scope, MLTAL);
SemaRef.addInstantiatedLocalVarsToScope(FD, FDPattern, Scope);
if (isLambdaCallOperator(FD))
SemaRef.addInstantiatedCapturesToScope(FD, FDPattern, Scope, MLTAL);
}
+
+ SemaRef.addInstantiatedCapturesToScope(InnermostFD, InnermostFDPattern, Scope,
+ MLTAL);
}
More information about the cfe-commits
mailing list