git: 6d4bc09d9ce4 - main - devel/llvm17: merge upstream llvm fixes
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 11 Dec 2023 17:42:36 UTC
The branch main has been updated by brooks:
URL: https://cgit.FreeBSD.org/ports/commit/?id=6d4bc09d9ce42807965de65e0b0739b6308d96b3
commit 6d4bc09d9ce42807965de65e0b0739b6308d96b3
Author: Brooks Davis <brooks@FreeBSD.org>
AuthorDate: 2023-12-08 23:58:56 +0000
Commit: Brooks Davis <brooks@FreeBSD.org>
CommitDate: 2023-12-11 17:42:26 +0000
devel/llvm17: merge upstream llvm fixes
These fixes were merged to the base LLVM compiler:
158f4f30adb4 [Clang] Do not change the type of captured vars when checking lambda constraints
3ed9e9e3ace6 [Clang] Add captures to the instantiation scope of lambda call operators
---
devel/llvm17/Makefile | 2 +-
devel/llvm17/files/patch-backport-158f4f30adb4 | 211 +++++++++++++++
devel/llvm17/files/patch-backport-3ed9e9e3ace6 | 342 +++++++++++++++++++++++++
3 files changed, 554 insertions(+), 1 deletion(-)
diff --git a/devel/llvm17/Makefile b/devel/llvm17/Makefile
index b3b68f775d0f..914dc58793b4 100644
--- a/devel/llvm17/Makefile
+++ b/devel/llvm17/Makefile
@@ -1,6 +1,6 @@
PORTNAME= llvm
DISTVERSION= 17.0.6
-PORTREVISION= 1
+PORTREVISION= 2
CATEGORIES= devel lang
MASTER_SITES= https://github.com/llvm/llvm-project/releases/download/llvmorg-${DISTVERSION:S/rc/-rc/}/ \
https://${PRE_}releases.llvm.org/${LLVM_RELEASE}${RCDIR}/
diff --git a/devel/llvm17/files/patch-backport-158f4f30adb4 b/devel/llvm17/files/patch-backport-158f4f30adb4
new file mode 100644
index 000000000000..c7b31bdab7e6
--- /dev/null
+++ b/devel/llvm17/files/patch-backport-158f4f30adb4
@@ -0,0 +1,211 @@
+commit 158f4f30adb4bfd390057742a32934e4344e8fd3
+Author: Corentin Jabot <corentinjabot@gmail.com>
+Date: Mon Aug 21 18:07:43 2023 +0200
+
+ [Clang] Do not change the type of captured vars when checking lambda constraints
+
+ When checking the constraint of a lambda, we need to respect the constness
+ of the call operator when establishing the type of capture variables.
+
+ In D124351, this was done by adding const to the captured variable...
+ However, that would change the type of the variable outside of the scope
+ of the lambda, which is clearly not the desired outcome.
+
+ Instead, to ensure const-correctness, we need to populate
+ a LambdaScopeInfo with the capture variables before checking the
+ constraints of a generic lambda.
+
+ There is no changelog as I'd like to tentatively propose we backport
+ this change to RC3 as it is a regression introduced in the Clang 17
+ cycle.
+
+ Fixes #61267
+
+ Reviewed By: aaron.ballman, #clang-language-wg
+
+ Differential Revision: https://reviews.llvm.org/D158433
+
+diff --git clang/include/clang/Sema/Sema.h clang/include/clang/Sema/Sema.h
+index c992e8763057..807a52886ccb 100644
+--- clang/include/clang/Sema/Sema.h
++++ clang/include/clang/Sema/Sema.h
+@@ -7343,6 +7343,8 @@ public:
+ CXXConversionDecl *Conv,
+ Expr *Src);
+
++ sema::LambdaScopeInfo *RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator);
++
+ /// Check whether the given expression is a valid constraint expression.
+ /// A diagnostic is emitted if it is not, false is returned, and
+ /// PossibleNonPrimary will be set to true if the failure might be due to a
+diff --git clang/lib/Sema/SemaConcept.cpp clang/lib/Sema/SemaConcept.cpp
+index f24b549dd2ef..fa3dadf68229 100644
+--- clang/lib/Sema/SemaConcept.cpp
++++ clang/lib/Sema/SemaConcept.cpp
+@@ -13,12 +13,14 @@
+ #include "clang/Sema/SemaConcept.h"
+ #include "TreeTransform.h"
+ #include "clang/AST/ASTLambda.h"
++#include "clang/AST/DeclCXX.h"
+ #include "clang/AST/ExprConcepts.h"
+ #include "clang/AST/RecursiveASTVisitor.h"
+ #include "clang/Basic/OperatorPrecedence.h"
+ #include "clang/Sema/EnterExpressionEvaluationContext.h"
+ #include "clang/Sema/Initialization.h"
+ #include "clang/Sema/Overload.h"
++#include "clang/Sema/ScopeInfo.h"
+ #include "clang/Sema/Sema.h"
+ #include "clang/Sema/SemaDiagnostic.h"
+ #include "clang/Sema/SemaInternal.h"
+@@ -540,11 +542,6 @@ bool Sema::addInstantiatedCapturesToScope(
+ auto AddSingleCapture = [&](const ValueDecl *CapturedPattern,
+ unsigned Index) {
+ ValueDecl *CapturedVar = LambdaClass->getCapture(Index)->getCapturedVar();
+- if (cast<CXXMethodDecl>(Function)->isConst()) {
+- QualType T = CapturedVar->getType();
+- T.addConst();
+- CapturedVar->setType(T);
+- }
+ if (CapturedVar->isInitCapture())
+ Scope.InstantiatedLocal(CapturedPattern, CapturedVar);
+ };
+@@ -714,6 +711,22 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
+ Record = const_cast<CXXRecordDecl *>(Method->getParent());
+ }
+ CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
++
++ // When checking the constraints of a lambda, we need to restore a
++ // LambdaScopeInfo populated with correct capture information so that the type
++ // of a variable referring to a capture is correctly const-adjusted.
++ FunctionScopeRAII FuncScope(*this);
++ if (isLambdaCallOperator(FD)) {
++ LambdaScopeInfo *LSI = RebuildLambdaScopeInfo(
++ const_cast<CXXMethodDecl *>(cast<CXXMethodDecl>(FD)));
++ // Constraints are checked from the parent context of the lambda, so we set
++ // AfterParameterList to false, so that `tryCaptureVariable` finds
++ // explicit captures in the appropriate context.
++ LSI->AfterParameterList = false;
++ } else {
++ FuncScope.disable();
++ }
++
+ return CheckConstraintSatisfaction(
+ FD, {FD->getTrailingRequiresClause()}, *MLTAL,
+ SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
+@@ -902,10 +915,13 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
+ }
+ CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
+ FunctionScopeRAII FuncScope(*this);
+- if (isLambdaCallOperator(Decl))
+- PushLambdaScope();
+- else
++
++ if (isLambdaCallOperator(Decl)) {
++ LambdaScopeInfo *LSI = RebuildLambdaScopeInfo(cast<CXXMethodDecl>(Decl));
++ LSI->AfterParameterList = false;
++ } else {
+ FuncScope.disable();
++ }
+
+ llvm::SmallVector<Expr *, 1> Converted;
+ return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
+diff --git clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDecl.cpp
+index 3925e2a7f338..0d5f696bf040 100644
+--- clang/lib/Sema/SemaDecl.cpp
++++ clang/lib/Sema/SemaDecl.cpp
+@@ -15289,11 +15289,10 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
+ FD->setInvalidDecl();
+ }
+
+-static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
+- Sema &S) {
+- CXXRecordDecl *const LambdaClass = CallOperator->getParent();
++LambdaScopeInfo *Sema::RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator) {
++ CXXRecordDecl *LambdaClass = CallOperator->getParent();
+
+- LambdaScopeInfo *LSI = S.PushLambdaScope();
++ LambdaScopeInfo *LSI = PushLambdaScope();
+ LSI->CallOperator = CallOperator;
+ LSI->Lambda = LambdaClass;
+ LSI->ReturnType = CallOperator->getReturnType();
+@@ -15317,7 +15316,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
+ if (C.capturesVariable()) {
+ ValueDecl *VD = C.getCapturedVar();
+ if (VD->isInitCapture())
+- S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);
++ CurrentInstantiationScope->InstantiatedLocal(VD, VD);
+ const bool ByRef = C.getCaptureKind() == LCK_ByRef;
+ LSI->addCapture(VD, /*IsBlock*/false, ByRef,
+ /*RefersToEnclosingVariableOrCapture*/true, C.getLocation(),
+@@ -15334,6 +15333,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
+ }
+ ++I;
+ }
++ return LSI;
+ }
+
+ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
+@@ -15437,7 +15437,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
+ assert(inTemplateInstantiation() &&
+ "There should be an active template instantiation on the stack "
+ "when instantiating a generic lambda!");
+- RebuildLambdaScopeInfo(cast<CXXMethodDecl>(D), *this);
++ RebuildLambdaScopeInfo(cast<CXXMethodDecl>(D));
+ } else {
+ // Enter a new function scope
+ PushFunctionScope();
+diff --git clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaExpr.cpp
+index 34284a8d9381..ac6c3ba6b357 100644
+--- clang/lib/Sema/SemaExpr.cpp
++++ clang/lib/Sema/SemaExpr.cpp
+@@ -19722,13 +19722,6 @@ bool Sema::tryCaptureVariable(
+ FunctionScopesIndex == MaxFunctionScopesIndex && VarDC == DC)
+ return true;
+
+- // When evaluating some attributes (like enable_if) we might refer to a
+- // function parameter appertaining to the same declaration as that
+- // attribute.
+- if (const auto *Parm = dyn_cast<ParmVarDecl>(Var);
+- Parm && Parm->getDeclContext() == DC)
+- return true;
+-
+ // Only block literals, captured statements, and lambda expressions can
+ // capture; other scopes don't work.
+ DeclContext *ParentDC =
+@@ -19756,6 +19749,14 @@ bool Sema::tryCaptureVariable(
+ CSI->getCapture(Var).markUsed(BuildAndDiagnose);
+ break;
+ }
++
++ // When evaluating some attributes (like enable_if) we might refer to a
++ // function parameter appertaining to the same declaration as that
++ // attribute.
++ if (const auto *Parm = dyn_cast<ParmVarDecl>(Var);
++ Parm && Parm->getDeclContext() == DC)
++ return true;
++
+ // If we are instantiating a generic lambda call operator body,
+ // we do not want to capture new variables. What was captured
+ // during either a lambdas transformation or initial parsing
+diff --git clang/test/SemaCXX/lambda-capture-type-deduction.cpp clang/test/SemaCXX/lambda-capture-type-deduction.cpp
+index e524d3bc20ab..9855122c9627 100644
+--- clang/test/SemaCXX/lambda-capture-type-deduction.cpp
++++ clang/test/SemaCXX/lambda-capture-type-deduction.cpp
+@@ -246,3 +246,17 @@ void check_params_tpl() {
+ static_assert(is_same<int&, decltype((ap))>);
+ };
+ }
++
++namespace GH61267 {
++template <typename> concept C = true;
++
++template<typename>
++void f(int) {
++ int i;
++ [i]<C P>(P) {}(0);
++ i = 4;
++}
++
++void test() { f<int>(0); }
++
++}
diff --git a/devel/llvm17/files/patch-backport-3ed9e9e3ace6 b/devel/llvm17/files/patch-backport-3ed9e9e3ace6
new file mode 100644
index 000000000000..420be920ab90
--- /dev/null
+++ b/devel/llvm17/files/patch-backport-3ed9e9e3ace6
@@ -0,0 +1,342 @@
+commit 3ed9e9e3ace6f9ce320cf4e75cffa04a7c7241b5
+Author: Corentin Jabot <corentinjabot@gmail.com>
+Date: Tue Aug 29 19:53:19 2023 +0200
+
+ [Clang] Add captures to the instantiation scope of lambda call operators
+
+ Like concepts checking, a trailing return type of a lambda
+ in a dependent context may refer to captures in which case
+ they may need to be rebuilt, so the map of local decl
+ should include captures.
+
+ This patch reveal a pre-existing issue.
+ `this` is always recomputed by TreeTransform.
+
+ `*this` (like all captures) only become `const`
+ after the parameter list.
+
+ However, if try to recompute the value of `this` (in a parameter)
+ during template instantiation while determining the type of the call operator,
+ we will determine it to be const (unless the lambda is mutable).
+
+ There is no good way to know at that point that we are in a parameter
+ or not, the easiest/best solution is to transform the type of this.
+
+ Note that doing so break a handful of HLSL tests.
+ So this is a prototype at this point.
+
+ Fixes #65067
+ Fixes #63675
+
+ Reviewed By: erichkeane
+
+ Differential Revision: https://reviews.llvm.org/D159126
+
+diff --git clang/docs/ReleaseNotes.rst clang/docs/ReleaseNotes.rst
+index 2d0302c399fb..6a3a6bb8ad42 100644
+--- clang/docs/ReleaseNotes.rst
++++ clang/docs/ReleaseNotes.rst
+@@ -270,6 +270,11 @@ Bug Fixes to C++ Support
+ - Fix crash when parsing the requires clause of some generic lambdas.
+ (`#64689 <https://github.com/llvm/llvm-project/issues/64689>`_)
+
++- Fix crash when the trailing return type of a generic and dependent
++ lambda refers to an init-capture.
++ (`#65067 <https://github.com/llvm/llvm-project/issues/65067>`_` and
++ `#63675 <https://github.com/llvm/llvm-project/issues/63675>`_`)
++
+ Bug Fixes to AST Handling
+ ^^^^^^^^^^^^^^^^^^^^^^^^^
+ - Fixed an import failure of recursive friend class template.
+diff --git clang/include/clang/Sema/Sema.h clang/include/clang/Sema/Sema.h
+index 1bb096c667e3..566655818a85 100644
+--- clang/include/clang/Sema/Sema.h
++++ clang/include/clang/Sema/Sema.h
+@@ -7365,6 +7365,14 @@ public:
+
+ sema::LambdaScopeInfo *RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator);
+
++ class LambdaScopeForCallOperatorInstantiationRAII
++ : private FunctionScopeRAII {
++ public:
++ LambdaScopeForCallOperatorInstantiationRAII(
++ Sema &SemasRef, FunctionDecl *FD, MultiLevelTemplateArgumentList MLTAL,
++ LocalInstantiationScope &Scope);
++ };
++
+ /// Check whether the given expression is a valid constraint expression.
+ /// A diagnostic is emitted if it is not, false is returned, and
+ /// PossibleNonPrimary will be set to true if the failure might be due to a
+diff --git clang/lib/Sema/SemaConcept.cpp clang/lib/Sema/SemaConcept.cpp
+index fa3dadf68229..d1fa8e783122 100644
+--- clang/lib/Sema/SemaConcept.cpp
++++ clang/lib/Sema/SemaConcept.cpp
+@@ -600,11 +600,6 @@ bool Sema::SetupConstraintScope(
+ if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(),
+ Scope, MLTAL))
+ return true;
+- // Make sure the captures are also added to the instantiation scope.
+- if (isLambdaCallOperator(FD) &&
+- addInstantiatedCapturesToScope(FD, FromMemTempl->getTemplatedDecl(),
+- Scope, MLTAL))
+- return true;
+ }
+
+ return false;
+@@ -629,11 +624,6 @@ bool Sema::SetupConstraintScope(
+ // child-function.
+ if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL))
+ return true;
+-
+- // Make sure the captures are also added to the instantiation scope.
+- if (isLambdaCallOperator(FD) &&
+- addInstantiatedCapturesToScope(FD, InstantiatedFrom, Scope, MLTAL))
+- return true;
+ }
+
+ return false;
+@@ -712,20 +702,8 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
+ }
+ CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
+
+- // When checking the constraints of a lambda, we need to restore a
+- // LambdaScopeInfo populated with correct capture information so that the type
+- // of a variable referring to a capture is correctly const-adjusted.
+- FunctionScopeRAII FuncScope(*this);
+- if (isLambdaCallOperator(FD)) {
+- LambdaScopeInfo *LSI = RebuildLambdaScopeInfo(
+- const_cast<CXXMethodDecl *>(cast<CXXMethodDecl>(FD)));
+- // Constraints are checked from the parent context of the lambda, so we set
+- // AfterParameterList to false, so that `tryCaptureVariable` finds
+- // explicit captures in the appropriate context.
+- LSI->AfterParameterList = false;
+- } else {
+- FuncScope.disable();
+- }
++ LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
++ *this, const_cast<FunctionDecl *>(FD), *MLTAL, Scope);
+
+ return CheckConstraintSatisfaction(
+ FD, {FD->getTrailingRequiresClause()}, *MLTAL,
+@@ -913,15 +891,10 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
+ ThisQuals = Method->getMethodQualifiers();
+ Record = Method->getParent();
+ }
+- CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
+- FunctionScopeRAII FuncScope(*this);
+
+- if (isLambdaCallOperator(Decl)) {
+- LambdaScopeInfo *LSI = RebuildLambdaScopeInfo(cast<CXXMethodDecl>(Decl));
+- LSI->AfterParameterList = false;
+- } else {
+- FuncScope.disable();
+- }
++ CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
++ LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
++ *this, const_cast<FunctionDecl *>(Decl), *MLTAL, Scope);
+
+ llvm::SmallVector<Expr *, 1> Converted;
+ return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
+diff --git clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDecl.cpp
+index 027c6c3e4222..998060542609 100644
+--- clang/lib/Sema/SemaDecl.cpp
++++ clang/lib/Sema/SemaDecl.cpp
+@@ -15382,6 +15382,10 @@ LambdaScopeInfo *Sema::RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator) {
+ LSI->CallOperator = CallOperator;
+ LSI->Lambda = LambdaClass;
+ LSI->ReturnType = CallOperator->getReturnType();
++ // This function in calls in situation where the context of the call operator
++ // is not entered, so we set AfterParameterList to false, so that
++ // `tryCaptureVariable` finds explicit captures in the appropriate context.
++ LSI->AfterParameterList = false;
+ const LambdaCaptureDefault LCD = LambdaClass->getLambdaCaptureDefault();
+
+ if (LCD == LCD_None)
+diff --git clang/lib/Sema/SemaLambda.cpp clang/lib/Sema/SemaLambda.cpp
+index 5256d91a19a0..1702ddb3ee0f 100644
+--- clang/lib/Sema/SemaLambda.cpp
++++ clang/lib/Sema/SemaLambda.cpp
+@@ -20,6 +20,7 @@
+ #include "clang/Sema/ScopeInfo.h"
+ #include "clang/Sema/SemaInternal.h"
+ #include "clang/Sema/SemaLambda.h"
++#include "clang/Sema/Template.h"
+ #include "llvm/ADT/STLExtras.h"
+ #include <optional>
+ using namespace clang;
+@@ -2254,3 +2255,34 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
+
+ return BuildBlock;
+ }
++
++Sema::LambdaScopeForCallOperatorInstantiationRAII::
++ LambdaScopeForCallOperatorInstantiationRAII(
++ Sema &SemasRef, FunctionDecl *FD, MultiLevelTemplateArgumentList MLTAL,
++ LocalInstantiationScope &Scope)
++ : FunctionScopeRAII(SemasRef) {
++ if (!isLambdaCallOperator(FD)) {
++ FunctionScopeRAII::disable();
++ return;
++ }
++
++ if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
++ FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
++ if (const auto *FromMemTempl =
++ PrimaryTemplate->getInstantiatedFromMemberTemplate()) {
++ SemasRef.addInstantiatedCapturesToScope(
++ FD, FromMemTempl->getTemplatedDecl(), Scope, MLTAL);
++ }
++ }
++
++ else if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization ||
++ FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) {
++ FunctionDecl *InstantiatedFrom =
++ FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization
++ ? FD->getInstantiatedFromMemberFunction()
++ : FD->getInstantiatedFromDecl();
++ SemasRef.addInstantiatedCapturesToScope(FD, InstantiatedFrom, Scope, MLTAL);
++ }
++
++ SemasRef.RebuildLambdaScopeInfo(cast<CXXMethodDecl>(FD));
++}
+diff --git clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+index 63f022d5c2ff..37a7d6204413 100644
+--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
++++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+@@ -2426,6 +2426,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
+ cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
+ LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
+
++ Sema::LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
++ SemaRef, const_cast<CXXMethodDecl *>(D), TemplateArgs, Scope);
++
+ // Instantiate enclosing template arguments for friends.
+ SmallVector<TemplateParameterList *, 4> TempParamLists;
+ unsigned NumTempParamLists = 0;
+diff --git clang/lib/Sema/TreeTransform.h clang/lib/Sema/TreeTransform.h
+index 7323140bc336..603a23275889 100644
+--- clang/lib/Sema/TreeTransform.h
++++ clang/lib/Sema/TreeTransform.h
+@@ -12325,7 +12325,16 @@ TreeTransform<Derived>::TransformCXXNullPtrLiteralExpr(
+ template<typename Derived>
+ ExprResult
+ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
+- QualType T = getSema().getCurrentThisType();
++
++ // In lambdas, the qualifiers of the type depends of where in
++ // the call operator `this` appear, and we do not have a good way to
++ // rebuild this information, so we transform the type.
++ //
++ // In other contexts, the type of `this` may be overrided
++ // for type deduction, so we need to recompute it.
++ QualType T = getSema().getCurLambda() ?
++ getDerived().TransformType(E->getType())
++ : getSema().getCurrentThisType();
+
+ if (!getDerived().AlwaysRebuild() && T == E->getType()) {
+ // Mark it referenced in the new context regardless.
+diff --git clang/test/SemaCXX/lambda-capture-type-deduction.cpp clang/test/SemaCXX/lambda-capture-type-deduction.cpp
+index 9855122c9627..7bf36a6a9cab 100644
+--- clang/test/SemaCXX/lambda-capture-type-deduction.cpp
++++ clang/test/SemaCXX/lambda-capture-type-deduction.cpp
+@@ -260,3 +260,40 @@ void f(int) {
+ void test() { f<int>(0); }
+
+ }
++
++namespace GH65067 {
++
++template <typename> class a {
++public:
++ template <typename b> void c(b f) { d<int>(f)(0); }
++ template <typename, typename b> auto d(b f) {
++ return [f = f](auto arg) -> a<decltype(f(arg))> { return {}; };
++ }
++};
++a<void> e;
++auto fn1() {
++ e.c([](int) {});
++}
++
++}
++
++namespace GH63675 {
++
++template <class _Tp> _Tp __declval();
++struct __get_tag {
++ template <class _Tag> void operator()(_Tag);
++};
++template <class _ImplFn> struct __basic_sender {
++ using __tag_t = decltype(__declval<_ImplFn>()(__declval<__get_tag>()));
++ _ImplFn __impl_;
++};
++auto __make_basic_sender = []<class... _Children>(
++ _Children... __children) {
++ return __basic_sender{[... __children = __children]<class _Fun>(
++ _Fun __fun) -> decltype(__fun(__children...)) {}};
++};
++void __trans_tmp_1() {
++ __make_basic_sender(__trans_tmp_1);
++}
++
++}
+diff --git clang/test/SemaCXX/this-type-deduction-concept.cpp clang/test/SemaCXX/this-type-deduction-concept.cpp
+new file mode 100644
+index 000000000000..a0c1f605ccef
+--- /dev/null
++++ clang/test/SemaCXX/this-type-deduction-concept.cpp
+@@ -0,0 +1,54 @@
++
++// This test case came up in the review of
++// https://reviews.llvm.org/D159126
++// when transforming `this` within a
++// requires expression, we need to make sure
++// the type of this (and its qualifiers) is respected.
++namespace D159126 {
++
++template <class _Tp>
++concept __member_begin = requires(_Tp __t) {
++ __t.begin();
++};
++
++struct {
++ template <class _Tp>
++ requires __member_begin<_Tp>
++ auto operator()(_Tp &&) {}
++} inline begin;
++
++template <class>
++concept range = requires {
++ begin;
++};
++
++template <class _Tp>
++concept __can_compare_begin = requires(_Tp __t) {
++ begin(__t);
++};
++
++struct {
++ template <__can_compare_begin _Tp> void operator()(_Tp &&);
++} empty;
++
++template <range _Rp> struct owning_view {
++ _Rp __r_;
++public:
++ void empty() const requires requires { empty(__r_); };
++};
++
++template <class T>
++concept HasEmpty = requires(T t) {
++ t.empty();
++};
++
++struct ComparableIters {
++ void begin();
++};
++
++static_assert(HasEmpty<owning_view<ComparableIters&>>);
++static_assert(HasEmpty<owning_view<ComparableIters&&>>);
++static_assert(!HasEmpty<owning_view<const ComparableIters&>>);
++static_assert(!HasEmpty<owning_view<const ComparableIters&&>>);
++
++}