Rollup merge of #132732 - gavincrawford:as_ptr_attribute, r=Urgau
Use attributes for `dangling_pointers_from_temporaries` lint Checking for dangling pointers by function name isn't ideal, and leaves out certain pointer-returning methods that don't follow the `as_ptr` naming convention. Using an attribute for this lint cleans things up and allows more thorough coverage of other methods, such as `UnsafeCell::get()`.
This commit is contained in:
commit
25dc4d0394
13 changed files with 83 additions and 32 deletions
|
@ -879,6 +879,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, EncodeCrossCrate::No, lang_items,
|
||||
"lang items are subject to change",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
|
|
|
@ -43,13 +43,10 @@ declare_lint! {
|
|||
}
|
||||
|
||||
/// FIXME: false negatives (i.e. the lint is not emitted when it should be)
|
||||
/// 1. Method calls that are not checked for:
|
||||
/// - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`]
|
||||
/// - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`]
|
||||
/// 2. Ways to get a temporary that are not recognized:
|
||||
/// 1. Ways to get a temporary that are not recognized:
|
||||
/// - `owning_temporary.field`
|
||||
/// - `owning_temporary[index]`
|
||||
/// 3. No checks for ref-to-ptr conversions:
|
||||
/// 2. No checks for ref-to-ptr conversions:
|
||||
/// - `&raw [mut] temporary`
|
||||
/// - `&temporary as *(const|mut) _`
|
||||
/// - `ptr::from_ref(&temporary)` and friends
|
||||
|
@ -133,10 +130,11 @@ impl DanglingPointerSearcher<'_, '_> {
|
|||
|
||||
fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind
|
||||
&& matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr)
|
||||
&& let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||
&& cx.tcx.has_attr(fn_id, sym::rustc_as_ptr)
|
||||
&& is_temporary_rvalue(receiver)
|
||||
&& let ty = cx.typeck_results().expr_ty(receiver)
|
||||
&& is_interesting(cx.tcx, ty)
|
||||
&& owns_allocation(cx.tcx, ty)
|
||||
{
|
||||
// FIXME: use `emit_node_lint` when `#[primary_span]` is added.
|
||||
cx.tcx.emit_node_span_lint(
|
||||
|
@ -199,24 +197,25 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>,
|
||||
// or any of the above in arbitrary many nested Box'es.
|
||||
fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
|
||||
// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>, UnsafeCell,
|
||||
// SyncUnsafeCell, or any of the above in arbitrary many nested Box'es.
|
||||
fn owns_allocation(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
|
||||
if ty.is_array() {
|
||||
true
|
||||
} else if let Some(inner) = ty.boxed_ty() {
|
||||
inner.is_slice()
|
||||
|| inner.is_str()
|
||||
|| inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr))
|
||||
|| is_interesting(tcx, inner)
|
||||
|| owns_allocation(tcx, inner)
|
||||
} else if let Some(def) = ty.ty_adt_def() {
|
||||
for lang_item in [LangItem::String, LangItem::MaybeUninit] {
|
||||
for lang_item in [LangItem::String, LangItem::MaybeUninit, LangItem::UnsafeCell] {
|
||||
if tcx.is_lang_item(def.did(), lang_item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
tcx.get_diagnostic_name(def.did())
|
||||
.is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell))
|
||||
tcx.get_diagnostic_name(def.did()).is_some_and(|name| {
|
||||
matches!(name, sym::cstring_type | sym::Vec | sym::Cell | sym::SyncUnsafeCell)
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
|
@ -162,6 +162,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
self.check_rustc_std_internal_symbol(attr, span, target)
|
||||
}
|
||||
[sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs),
|
||||
[sym::rustc_as_ptr, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
||||
}
|
||||
[sym::rustc_never_returns_null_ptr, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
|
||||
}
|
||||
|
|
|
@ -316,6 +316,7 @@ symbols! {
|
|||
SubdiagMessage,
|
||||
Subdiagnostic,
|
||||
Sync,
|
||||
SyncUnsafeCell,
|
||||
T,
|
||||
Target,
|
||||
ToOwned,
|
||||
|
@ -409,7 +410,6 @@ symbols! {
|
|||
arm,
|
||||
arm_target_feature,
|
||||
array,
|
||||
as_mut_ptr,
|
||||
as_ptr,
|
||||
as_ref,
|
||||
as_str,
|
||||
|
@ -1655,6 +1655,7 @@ symbols! {
|
|||
rustc_allow_const_fn_unstable,
|
||||
rustc_allow_incoherent_impl,
|
||||
rustc_allowed_through_unstable_modules,
|
||||
rustc_as_ptr,
|
||||
rustc_attrs,
|
||||
rustc_autodiff,
|
||||
rustc_box,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue