Skip to content

Commit

Permalink
Fix lifetimebound for field access (llvm#100197)
Browse files Browse the repository at this point in the history
Fixes: llvm#81589

There is no way to switch this off without  `-Wno-dangling`.
  • Loading branch information
usx95 authored and tru committed Jul 29, 2024
1 parent f53633b commit e1d0501
Showing 3 changed files with 38 additions and 0 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
@@ -767,6 +767,9 @@ Improvements to Clang's diagnostics

- Clang now diagnoses undefined behavior in constant expressions more consistently. This includes invalid shifts, and signed overflow in arithmetic.

- Clang now diagnoses dangling references to fields of temporary objects. Fixes #GH81589.


Improvements to Clang's time-trace
----------------------------------

9 changes: 9 additions & 0 deletions clang/lib/Sema/CheckExprLifetime.cpp
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "CheckExprLifetime.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Sema/Initialization.h"
@@ -548,6 +549,14 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
EnableLifetimeWarnings);
}

if (auto *M = dyn_cast<MemberExpr>(Init)) {
// Lifetime of a non-reference type field is same as base object.
if (auto *F = dyn_cast<FieldDecl>(M->getMemberDecl());
F && !F->getType()->isReferenceType())
visitLocalsRetainedByInitializer(Path, M->getBase(), Visit, true,
EnableLifetimeWarnings);
}

if (isa<CallExpr>(Init)) {
if (EnableLifetimeWarnings)
handleGslAnnotatedTypes(Path, Init, Visit);
26 changes: 26 additions & 0 deletions clang/test/SemaCXX/attr-lifetimebound.cpp
Original file line number Diff line number Diff line change
@@ -47,6 +47,31 @@ namespace usage_ok {
q = A(); // expected-warning {{object backing the pointer q will be destroyed at the end of the full-expression}}
r = A(1); // expected-warning {{object backing the pointer r will be destroyed at the end of the full-expression}}
}

struct FieldCheck {
struct Set {
int a;
};
struct Pair {
const int& a;
int b;
Set c;
int * d;
};
Pair p;
FieldCheck(const int& a): p(a){}
Pair& getR() [[clang::lifetimebound]] { return p; }
Pair* getP() [[clang::lifetimebound]] { return &p; }
Pair* getNoLB() { return &p; }
};
void test_field_access() {
int x = 0;
const int& a = FieldCheck{x}.getR().a;
const int& b = FieldCheck{x}.getP()->b; // expected-warning {{temporary bound to local reference 'b' will be destroyed at the end of the full-expression}}
const int& c = FieldCheck{x}.getP()->c.a; // expected-warning {{temporary bound to local reference 'c' will be destroyed at the end of the full-expression}}
const int& d = FieldCheck{x}.getNoLB()->c.a;
const int* e = FieldCheck{x}.getR().d;
}
}

# 1 "<std>" 1 3
@@ -239,3 +264,4 @@ namespace move_forward_et_al_examples {
S X;
S *AddressOfOk = std::addressof(X);
} // namespace move_forward_et_al_examples

0 comments on commit e1d0501

Please sign in to comment.