[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
This commit is contained in:
Younan Zhang 2024-12-04 15:31:15 +08:00 committed by GitHub
parent 94d6b1cce5
commit 154c7c0bf2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 26 additions and 2 deletions

View File

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

View File

@ -18431,7 +18431,11 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI,
// are mutable in the sense that user can change their value - they are
// private instances of the captured declarations.
const Capture &Cap = CSI->getCapture(Var);
if (Cap.isCopyCapture() &&
// C++ [expr.prim.lambda]p10:
// The type of such a data member is [...] an lvalue reference to the
// referenced function type if the entity is a reference to a function.
// [...]
if (Cap.isCopyCapture() && !DeclRefType->isFunctionType() &&
!(isa<LambdaScopeInfo>(CSI) &&
!cast<LambdaScopeInfo>(CSI)->lambdaCaptureShouldBeConst()) &&
!(isa<CapturedRegionScopeInfo>(CSI) &&
@ -18741,7 +18745,12 @@ static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var,
// parameter-declaration-clause is not followed by mutable.
DeclRefType = CaptureType.getNonReferenceType();
bool Const = LSI->lambdaCaptureShouldBeConst();
if (Const && !CaptureType->isReferenceType())
// C++ [expr.prim.lambda]p10:
// The type of such a data member is [...] an lvalue reference to the
// referenced function type if the entity is a reference to a function.
// [...]
if (Const && !CaptureType->isReferenceType() &&
!DeclRefType->isFunctionType())
DeclRefType.addConst();
}

View File

@ -335,3 +335,17 @@ constexpr void foo() {
}
} // namespace GH47400
namespace GH84961 {
template <typename T> void g(const T &t) {}
template <typename T> void f(const T &t) {
[t] { g(t); }();
}
void h() {
f(h);
}
} // namespace GH84961