Skip to content

Commit cd219f4

Browse files
committed
Restore the original temporary_cstring_as_ptr behavior
1 parent 5581359 commit cd219f4

File tree

1 file changed

+59
-54
lines changed

1 file changed

+59
-54
lines changed

compiler/rustc_lint/src/dangling.rs

Lines changed: 59 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use rustc_hir::{Expr, ExprKind, LangItem};
2-
use rustc_middle::ty::Ty;
2+
use rustc_middle::ty::{self, Ty};
33
use rustc_session::{declare_lint, declare_lint_pass};
4-
use rustc_span::symbol::{sym, Ident};
4+
use rustc_span::symbol::sym;
55

66
use crate::lints::InstantlyDangling;
77
use crate::{LateContext, LateLintPass, LintContext};
@@ -45,42 +45,57 @@ declare_lint_pass!(DanglingPointers => [TEMPORARY_CSTRING_AS_PTR, INSTANTLY_DANG
4545

4646
impl<'tcx> LateLintPass<'tcx> for DanglingPointers {
4747
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
48-
// We have a method call.
49-
let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind else {
50-
return;
51-
};
52-
let Ident { name: method_name, span: method_span } = method.ident;
53-
54-
// The method is `.as_ptr()` or `.as_mut_ptr`.
55-
if method_name != sym::as_ptr && method_name != sym::as_mut_ptr {
56-
return;
48+
if let ExprKind::MethodCall(as_ptr_path, as_ptr_receiver, ..) = expr.kind
49+
&& as_ptr_path.ident.name == sym::as_ptr
50+
&& let ExprKind::MethodCall(unwrap_path, unwrap_receiver, ..) = as_ptr_receiver.kind
51+
&& (unwrap_path.ident.name == sym::unwrap || unwrap_path.ident.name == sym::expect)
52+
&& lint_cstring_as_ptr(cx, unwrap_receiver)
53+
{
54+
cx.emit_span_lint(
55+
TEMPORARY_CSTRING_AS_PTR,
56+
as_ptr_path.ident.span,
57+
InstantlyDangling {
58+
callee: as_ptr_path.ident.name,
59+
ty: "CString".into(),
60+
ptr_span: as_ptr_path.ident.span,
61+
temporary_span: as_ptr_receiver.span,
62+
},
63+
);
64+
return; // One lint is enough
5765
}
5866

59-
// It is called on a temporary rvalue.
60-
if !is_temporary_rvalue(receiver) {
61-
return;
67+
if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind
68+
&& matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr)
69+
&& is_temporary_rvalue(receiver)
70+
&& let ty = cx.typeck_results().expr_ty(receiver)
71+
&& is_interesting(cx, ty)
72+
{
73+
cx.emit_span_lint(
74+
INSTANTLY_DANGLING_POINTER,
75+
method.ident.span,
76+
InstantlyDangling {
77+
callee: method.ident.name,
78+
ty: ty.to_string(),
79+
ptr_span: method.ident.span,
80+
temporary_span: receiver.span,
81+
},
82+
)
6283
}
84+
}
85+
}
6386

64-
// The temporary value's type is array, box, Vec, String, or CString
65-
let ty = cx.typeck_results().expr_ty(receiver);
66-
let Some(is_cstring) = as_container(cx, ty) else {
67-
return;
68-
};
69-
70-
let span = method_span;
71-
let decorator = InstantlyDangling {
72-
callee: method_name,
73-
ty: ty.to_string(),
74-
ptr_span: method_span,
75-
temporary_span: receiver.span,
76-
};
77-
78-
if is_cstring {
79-
cx.emit_span_lint(TEMPORARY_CSTRING_AS_PTR, span, decorator);
80-
} else {
81-
cx.emit_span_lint(INSTANTLY_DANGLING_POINTER, span, decorator);
82-
};
87+
fn lint_cstring_as_ptr(cx: &LateContext<'_>, source: &rustc_hir::Expr<'_>) -> bool {
88+
let source_type = cx.typeck_results().expr_ty(source);
89+
if let ty::Adt(def, args) = source_type.kind() {
90+
if cx.tcx.is_diagnostic_item(sym::Result, def.did()) {
91+
if let ty::Adt(adt, _) = args.type_at(0).kind() {
92+
if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
93+
return true;
94+
}
95+
}
96+
}
8397
}
98+
false
8499
}
85100

86101
fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
@@ -131,37 +146,27 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
131146
}
132147
}
133148

134-
// None => not a container
135-
// Some(true) => CString
136-
// Some(false) => String, Vec, box, array, MaybeUninit, Cell
137-
fn as_container(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<bool> {
149+
// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>,
150+
// or any of the above in arbitrary many nested Box'es.
151+
fn is_interesting(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
138152
if ty.is_array() {
139-
Some(false)
153+
true
140154
} else if ty.is_box() {
141155
let inner = ty.boxed_ty();
142-
// We only care about Box<[..]>, Box<str>, Box<CStr>,
143-
// or Box<T> iff T is another type we care about
144-
if inner.is_slice()
156+
inner.is_slice()
145157
|| inner.is_str()
146158
|| inner.ty_adt_def().is_some_and(|def| cx.tcx.is_lang_item(def.did(), LangItem::CStr))
147-
|| as_container(cx, inner).is_some()
148-
{
149-
Some(false)
150-
} else {
151-
None
152-
}
159+
|| is_interesting(cx, inner)
153160
} else if let Some(def) = ty.ty_adt_def() {
154161
for lang_item in [LangItem::String, LangItem::MaybeUninit] {
155162
if cx.tcx.is_lang_item(def.did(), lang_item) {
156-
return Some(false);
163+
return true;
157164
}
158165
}
159-
match cx.tcx.get_diagnostic_name(def.did()) {
160-
Some(sym::cstring_type) => Some(true),
161-
Some(sym::Vec | sym::Cell) => Some(false),
162-
_ => None,
163-
}
166+
cx.tcx
167+
.get_diagnostic_name(def.did())
168+
.is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell))
164169
} else {
165-
None
170+
false
166171
}
167172
}

0 commit comments

Comments
 (0)