Skip to content

Commit 154c7c0

Browse files
authored
[Clang] Don't add top-level const qualifiers to captured function types (#118050)
This aligns with the logic in `TreeTransform::RebuildQualifiedType()` where we refrain from adding const qualifiers to function types. Previously, we seemed to overlook this edge case when copy-capturing a variable that is of function type within a const-qualified lambda. This issue also reveals other related problems as in incorrect type printout and a suspicious implementation in DeduceTemplateArguments. I decide to leave them in follow-up work. Fixes #84961
1 parent 94d6b1c commit 154c7c0

File tree

3 files changed

+26
-2
lines changed

3 files changed

+26
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@ Bug Fixes to C++ Support
761761
- Name independent data members were not correctly initialized from default member initializers. (#GH114069)
762762
- Fixed expression transformation for ``[[assume(...)]]``, allowing using pack indexing expressions within the
763763
assumption if they also occur inside of a dependent lambda. (#GH114787)
764+
- Lambdas now capture function types without considering top-level const qualifiers. (#GH84961)
764765
- Clang now uses valid deduced type locations when diagnosing functions with trailing return type
765766
missing placeholder return type. (#GH78694)
766767
- Fixed a bug where bounds of partially expanded pack indexing expressions were checked too early. (#GH116105)

clang/lib/Sema/SemaExpr.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18431,7 +18431,11 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI,
1843118431
// are mutable in the sense that user can change their value - they are
1843218432
// private instances of the captured declarations.
1843318433
const Capture &Cap = CSI->getCapture(Var);
18434-
if (Cap.isCopyCapture() &&
18434+
// C++ [expr.prim.lambda]p10:
18435+
// The type of such a data member is [...] an lvalue reference to the
18436+
// referenced function type if the entity is a reference to a function.
18437+
// [...]
18438+
if (Cap.isCopyCapture() && !DeclRefType->isFunctionType() &&
1843518439
!(isa<LambdaScopeInfo>(CSI) &&
1843618440
!cast<LambdaScopeInfo>(CSI)->lambdaCaptureShouldBeConst()) &&
1843718441
!(isa<CapturedRegionScopeInfo>(CSI) &&
@@ -18741,7 +18745,12 @@ static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var,
1874118745
// parameter-declaration-clause is not followed by mutable.
1874218746
DeclRefType = CaptureType.getNonReferenceType();
1874318747
bool Const = LSI->lambdaCaptureShouldBeConst();
18744-
if (Const && !CaptureType->isReferenceType())
18748+
// C++ [expr.prim.lambda]p10:
18749+
// The type of such a data member is [...] an lvalue reference to the
18750+
// referenced function type if the entity is a reference to a function.
18751+
// [...]
18752+
if (Const && !CaptureType->isReferenceType() &&
18753+
!DeclRefType->isFunctionType())
1874518754
DeclRefType.addConst();
1874618755
}
1874718756

clang/test/SemaCXX/lambda-capture-type-deduction.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,17 @@ constexpr void foo() {
335335
}
336336

337337
} // namespace GH47400
338+
339+
namespace GH84961 {
340+
341+
template <typename T> void g(const T &t) {}
342+
343+
template <typename T> void f(const T &t) {
344+
[t] { g(t); }();
345+
}
346+
347+
void h() {
348+
f(h);
349+
}
350+
351+
} // namespace GH84961

0 commit comments

Comments
 (0)