Skip to content

Commit edd8e73

Browse files
committed
[clang] Improve the lifetime_capture_by diagnostic on the constructor.
1 parent 1b2c8f1 commit edd8e73

File tree

3 files changed

+36
-0
lines changed

3 files changed

+36
-0
lines changed

clang/lib/Sema/CheckExprLifetime.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,9 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
535535

536536
bool EnableGSLAnalysis = !Callee->getASTContext().getDiagnostics().isIgnored(
537537
diag::warn_dangling_lifetime_pointer, SourceLocation());
538+
bool EnableDanglingCapture =
539+
!Callee->getASTContext().getDiagnostics().isIgnored(
540+
diag::warn_dangling_reference_captured, SourceLocation());
538541
Expr *ObjectArg = nullptr;
539542
if (isa<CXXOperatorCallExpr>(Call) && Callee->isCXXInstanceMember()) {
540543
ObjectArg = Args[0];
@@ -623,6 +626,14 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
623626
}
624627
if (CheckCoroCall || Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
625628
VisitLifetimeBoundArg(Callee->getParamDecl(I), Arg);
629+
else if (const auto *CaptureAttr =
630+
Callee->getParamDecl(I)->getAttr<LifetimeCaptureByAttr>();
631+
EnableDanglingCapture && CaptureAttr &&
632+
isa<CXXConstructorDecl>(Callee) &&
633+
llvm::any_of(CaptureAttr->params(), [](int ArgIdx) {
634+
return ArgIdx == LifetimeCaptureByAttr::THIS;
635+
}))
636+
VisitLifetimeBoundArg(Callee->getParamDecl(I), Arg);
626637
else if (EnableGSLAnalysis && I == 0) {
627638
// Perform GSL analysis for the first argument
628639
if (shouldTrackFirstArgument(Callee)) {

clang/lib/Sema/SemaChecking.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3240,8 +3240,14 @@ void Sema::checkLifetimeCaptureBy(FunctionDecl *FD, bool IsMemberFunction,
32403240
unsigned ArgIdx) {
32413241
if (!Attr)
32423242
return;
3243+
32433244
Expr *Captured = const_cast<Expr *>(GetArgAt(ArgIdx));
32443245
for (int CapturingParamIdx : Attr->params()) {
3246+
// lifetime_capture_by(this) case is handled in the lifetimebound expr
3247+
// initialization codepath.
3248+
if (CapturingParamIdx == LifetimeCaptureByAttr::THIS &&
3249+
isa<CXXConstructorDecl>(FD))
3250+
continue;
32453251
Expr *Capturing = const_cast<Expr *>(GetArgAt(CapturingParamIdx));
32463252
CapturingEntity CE{Capturing};
32473253
// Ensure that 'Captured' outlives the 'Capturing' entity.

clang/test/Sema/warn-lifetime-analysis-capture-by.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,3 +411,22 @@ void use() {
411411
}
412412
} // namespace with_span
413413
} // namespace inferred_capture_by
414+
415+
namespace on_constructor {
416+
struct T {
417+
T(const int& t [[clang::lifetime_capture_by(this)]]);
418+
};
419+
struct T2 {
420+
T2(const int& t [[clang::lifetime_capture_by(x)]], int& x);
421+
};
422+
int foo(const T& t);
423+
424+
void test() {
425+
auto x = foo(T(1)); // OK. no diagnosic
426+
T(1); // OK. no diagnostic
427+
T t(1); // expected-warning {{temporary whose address is used}}
428+
429+
int a;
430+
T2(1, a); // expected-warning {{object whose reference is captured by}}
431+
}
432+
} // namespace on_constructor

0 commit comments

Comments
 (0)