Skip to content

Commit 5816dc3

Browse files
committed
Refactor inner allocation logic of temp dandling pointer lint
1 parent bfe809d commit 5816dc3

File tree

3 files changed

+89
-29
lines changed

3 files changed

+89
-29
lines changed

compiler/rustc_lint/src/dangling.rs

+32-27
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use rustc_ast::visit::{visit_opt, walk_list};
22
use rustc_hir::def_id::LocalDefId;
33
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
4-
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem};
5-
use rustc_middle::ty::{Ty, TyCtxt};
4+
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl};
5+
use rustc_middle::ty::Ty;
6+
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
67
use rustc_session::{declare_lint, impl_lint_pass};
78
use rustc_span::Span;
89
use rustc_span::symbol::sym;
@@ -134,7 +135,8 @@ fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
134135
&& cx.tcx.has_attr(fn_id, sym::rustc_as_ptr)
135136
&& is_temporary_rvalue(receiver)
136137
&& let ty = cx.typeck_results().expr_ty(receiver)
137-
&& owns_allocation(cx.tcx, ty)
138+
&& let adjs = cx.typeck_results().expr_adjustments(receiver)
139+
&& is_inner_allocation_owned(ty, adjs)
138140
{
139141
// FIXME: use `emit_node_lint` when `#[primary_span]` is added.
140142
cx.tcx.emit_node_span_lint(
@@ -151,6 +153,33 @@ fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
151153
}
152154
}
153155

156+
/// Determine if a `#[rustc_as_ptr]` receiver type (with adjustments) is only applied
157+
/// to owned allocations.
158+
fn is_inner_allocation_owned(input_ty: Ty<'_>, adjs: &[Adjustment<'_>]) -> bool {
159+
// 1. Exclude any pointer types (as they cannot be owned)
160+
//
161+
// - `&[u8]`: NOT WARN
162+
// - `*const u8`: NOT WARN
163+
// - `Box<u8>`: WARN
164+
!input_ty.is_any_ptr()
165+
// 2. Look at all the deref-ed types and exclude any pointer types
166+
//
167+
// - `Box<u8>` -> `u8`: WARN
168+
// - `Box<&u8>` -> `&u8`: NOT WARN
169+
// - `Box<Box<u8>>` -> `Box<u8>` -> `u8`: WARN
170+
// - `MaybeUninit<MaybeUninit<&u8>>`: WARN
171+
// - `Box<MaybeUninit<&u8>>` -> `MaybeUninit<&u8>`: WARN
172+
&& adjs.iter()
173+
.filter_map(|adj| match adj.kind {
174+
Adjust::Deref(_) => Some(adj.target),
175+
Adjust::NeverToAny
176+
| Adjust::Borrow(_)
177+
| Adjust::Pointer(_)
178+
| Adjust::ReborrowPin(_) => None,
179+
})
180+
.all(|deref_ty| !deref_ty.is_any_ptr())
181+
}
182+
154183
fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
155184
match expr.kind {
156185
// Const is not temporary.
@@ -196,27 +225,3 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
196225
ExprKind::Type(..) | ExprKind::Err(..) => false,
197226
}
198227
}
199-
200-
// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>, UnsafeCell,
201-
// SyncUnsafeCell, or any of the above in arbitrary many nested Box'es.
202-
fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
203-
if ty.is_array() {
204-
true
205-
} else if let Some(inner) = ty.boxed_ty() {
206-
inner.is_slice()
207-
|| inner.is_str()
208-
|| inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr))
209-
|| owns_allocation(tcx, inner)
210-
} else if let Some(def) = ty.ty_adt_def() {
211-
for lang_item in [LangItem::String, LangItem::MaybeUninit, LangItem::UnsafeCell] {
212-
if tcx.is_lang_item(def.did(), lang_item) {
213-
return true;
214-
}
215-
}
216-
tcx.get_diagnostic_name(def.did()).is_some_and(|name| {
217-
matches!(name, sym::cstring_type | sym::Vec | sym::Cell | sym::SyncUnsafeCell)
218-
})
219-
} else {
220-
false
221-
}
222-
}

tests/ui/lint/dangling-pointers-from-temporaries/types.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ fn main() {
5252
//~^ ERROR a dangling pointer will be produced because the temporary `UnsafeCell<u8>` will be dropped
5353
declval::<SyncUnsafeCell<u8>>().get();
5454
//~^ ERROR a dangling pointer will be produced because the temporary `SyncUnsafeCell<u8>` will be dropped
55-
declval::<Box<AsPtrFake>>().as_ptr();
55+
declval::<MaybeUninit<MaybeUninit<&u8>>>().as_ptr();
56+
//~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit<MaybeUninit<&u8>>` will be dropped
57+
declval::<Box<MaybeUninit<&u8>>>().as_ptr();
58+
//~^ ERROR a dangling pointer will be produced because the temporary `Box<MaybeUninit<&u8>>` will be dropped
59+
declval::<MaybeUninit<&u8>>().as_ptr();
60+
//~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit<&u8>` will be dropped
61+
declval::<[&u8; 10]>().as_ptr();
62+
//~^ ERROR a dangling pointer will be produced because the temporary `[&u8; 10]` will be dropped
63+
64+
// should not lint
65+
declval::<&[u8]>().as_ptr();
5666
declval::<AsPtrFake>().as_ptr();
67+
declval::<Box<AsPtrFake>>().as_ptr();
5768
}

tests/ui/lint/dangling-pointers-from-temporaries/types.stderr

+45-1
Original file line numberDiff line numberDiff line change
@@ -190,5 +190,49 @@ LL | declval::<SyncUnsafeCell<u8>>().get();
190190
= note: pointers do not have a lifetime; when calling `get` the `SyncUnsafeCell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
191191
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
192192

193-
error: aborting due to 17 previous errors
193+
error: a dangling pointer will be produced because the temporary `MaybeUninit<MaybeUninit<&u8>>` will be dropped
194+
--> $DIR/types.rs:55:48
195+
|
196+
LL | declval::<MaybeUninit<MaybeUninit<&u8>>>().as_ptr();
197+
| ------------------------------------------ ^^^^^^ this pointer will immediately be invalid
198+
| |
199+
| this `MaybeUninit<MaybeUninit<&u8>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
200+
|
201+
= note: pointers do not have a lifetime; when calling `as_ptr` the `MaybeUninit<MaybeUninit<&u8>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
202+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
203+
204+
error: a dangling pointer will be produced because the temporary `Box<MaybeUninit<&u8>>` will be dropped
205+
--> $DIR/types.rs:57:40
206+
|
207+
LL | declval::<Box<MaybeUninit<&u8>>>().as_ptr();
208+
| ---------------------------------- ^^^^^^ this pointer will immediately be invalid
209+
| |
210+
| this `Box<MaybeUninit<&u8>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
211+
|
212+
= note: pointers do not have a lifetime; when calling `as_ptr` the `Box<MaybeUninit<&u8>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
213+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
214+
215+
error: a dangling pointer will be produced because the temporary `MaybeUninit<&u8>` will be dropped
216+
--> $DIR/types.rs:59:35
217+
|
218+
LL | declval::<MaybeUninit<&u8>>().as_ptr();
219+
| ----------------------------- ^^^^^^ this pointer will immediately be invalid
220+
| |
221+
| this `MaybeUninit<&u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
222+
|
223+
= note: pointers do not have a lifetime; when calling `as_ptr` the `MaybeUninit<&u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
224+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
225+
226+
error: a dangling pointer will be produced because the temporary `[&u8; 10]` will be dropped
227+
--> $DIR/types.rs:61:28
228+
|
229+
LL | declval::<[&u8; 10]>().as_ptr();
230+
| ---------------------- ^^^^^^ this pointer will immediately be invalid
231+
| |
232+
| this `[&u8; 10]` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
233+
|
234+
= note: pointers do not have a lifetime; when calling `as_ptr` the `[&u8; 10]` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
235+
= help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
236+
237+
error: aborting due to 21 previous errors
194238

0 commit comments

Comments
 (0)