Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 07b7dc9

Browse files
committed
Auto merge of #144876 - Zalathar:rollup-jhv9rir, r=Zalathar
Rollup of 12 pull requests Successful merges: - #142205 (Mark `slice::swap_with_slice` unstably const) - #144188 (`available_parallelism`: Add documentation for why we don't look at `ulimit`) - #144322 (Add lint against dangling pointers from local variables) - #144497 (tests: Add test for basic line-by-line stepping in a debugger) - #144559 (Enable extract-insert-dyn.rs test on RISC-V (riscv64)) - #144667 (`AlignmentEnum` should just be `repr(usize)` now) - #144706 (Do not give function allocations alignment in consteval and Miri.) - #144746 (resolve: Cleanups and micro-optimizations to extern prelude) - #144785 (Regression test for LLVM error with unsupported expression in static initializer for const pointer in array on macOS.) - #144811 (Stylize `*-lynxos178-*` target maintainer handle to make it easier to copy/paste) - #144848 (For "stage 1" ui-fulldeps, use the stage 1 compiler to query target info) - #144853 (Remove unnecessary `rust_` prefixes) Failed merges: - #144794 (Port `#[coroutine]` to the new attribute system) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 383b9c4 + 7fbb303 commit 07b7dc9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+850
-173
lines changed

‎Cargo.lock‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4519,6 +4519,7 @@ name = "rustc_resolve"
45194519
version = "0.0.0"
45204520
dependencies = [
45214521
"bitflags",
4522+
"indexmap",
45224523
"itertools",
45234524
"pulldown-cmark",
45244525
"rustc_arena",

‎compiler/rustc_const_eval/src/interpret/memory.rs‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -937,8 +937,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
937937
// (both global from `alloc_map` and local from `extra_fn_ptr_map`)
938938
if let Some(fn_val) = self.get_fn_alloc(id) {
939939
let align = match fn_val {
940-
FnVal::Instance(instance) => {
941-
self.tcx.codegen_instance_attrs(instance.def).alignment.unwrap_or(Align::ONE)
940+
FnVal::Instance(_instance) => {
941+
// FIXME: Until we have a clear design for the effects of align(N) functions
942+
// on the address of function pointers, we don't consider the align(N)
943+
// attribute on functions in the interpreter.
944+
// See <https://github.com/rust-lang/rust/issues/144661> for more context.
945+
Align::ONE
942946
}
943947
// Machine-specific extra functions currently do not support alignment restrictions.
944948
FnVal::Other(_) => Align::ONE,

‎compiler/rustc_lint/messages.ftl‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,12 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
207207
208208
lint_custom_inner_attribute_unstable = custom inner attributes are unstable
209209
210+
lint_dangling_pointers_from_locals = a dangling pointer will be produced because the local variable `{$local_var_name}` will be dropped
211+
.ret_ty = return type of the {$fn_kind} is `{$ret_ty}`
212+
.local_var = `{$local_var_name}` is part the {$fn_kind} and will be dropped at the end of the {$fn_kind}
213+
.created_at = dangling pointer created here
214+
.note = pointers do not have a lifetime; after returning, the `{$local_var_ty}` will be deallocated at the end of the {$fn_kind} because nothing is referencing it as far as the type system is concerned
215+
210216
lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped
211217
.label_ptr = this pointer will immediately be invalid
212218
.label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime

‎compiler/rustc_lint/src/dangling.rs‎

Lines changed: 142 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use rustc_ast::visit::{visit_opt, walk_list};
22
use rustc_hir::attrs::AttributeKind;
3+
use rustc_hir::def::Res;
34
use rustc_hir::def_id::LocalDefId;
45
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
5-
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, find_attr};
6-
use rustc_middle::ty::{Ty, TyCtxt};
6+
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy,LangItem,TyKind, find_attr};
7+
use rustc_middle::ty::{self,Ty, TyCtxt};
78
use rustc_session::{declare_lint, impl_lint_pass};
89
use rustc_span::{Span, sym};
910

10-
use crate::lints::DanglingPointersFromTemporaries;
11+
use crate::lints::{DanglingPointersFromLocals,DanglingPointersFromTemporaries};
1112
use crate::{LateContext, LateLintPass};
1213

1314
declare_lint! {
@@ -42,6 +43,36 @@ declare_lint! {
4243
"detects getting a pointer from a temporary"
4344
}
4445

46+
declare_lint! {
47+
/// The `dangling_pointers_from_locals` lint detects getting a pointer to data
48+
/// of a local that will be dropped at the end of the function.
49+
///
50+
/// ### Example
51+
///
52+
/// ```rust
53+
/// fn f() -> *const u8 {
54+
/// let x = 0;
55+
/// &x // returns a dangling ptr to `x`
56+
/// }
57+
/// ```
58+
///
59+
/// {{produces}}
60+
///
61+
/// ### Explanation
62+
///
63+
/// Returning a pointer from a local value will not prolong its lifetime,
64+
/// which means that the value can be dropped and the allocation freed
65+
/// while the pointer still exists, making the pointer dangling.
66+
/// This is not an error (as far as the type system is concerned)
67+
/// but probably is not what the user intended either.
68+
///
69+
/// If you need stronger guarantees, consider using references instead,
70+
/// as they are statically verified by the borrow-checker to never dangle.
71+
pub DANGLING_POINTERS_FROM_LOCALS,
72+
Warn,
73+
"detects returning a pointer from a local variable"
74+
}
75+
4576
/// FIXME: false negatives (i.e. the lint is not emitted when it should be)
4677
/// 1. Ways to get a temporary that are not recognized:
4778
/// - `owning_temporary.field`
@@ -53,20 +84,123 @@ declare_lint! {
5384
#[derive(Clone, Copy, Default)]
5485
pub(crate) struct DanglingPointers;
5586

56-
impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]);
87+
impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES,DANGLING_POINTERS_FROM_LOCALS]);
5788

5889
// This skips over const blocks, but they cannot use or return a dangling pointer anyways.
5990
impl<'tcx> LateLintPass<'tcx> for DanglingPointers {
6091
fn check_fn(
6192
&mut self,
6293
cx: &LateContext<'tcx>,
63-
_: FnKind<'tcx>,
64-
_: &'tcx FnDecl<'tcx>,
94+
fn_kind: FnKind<'tcx>,
95+
fn_decl: &'tcx FnDecl<'tcx>,
6596
body: &'tcx Body<'tcx>,
6697
_: Span,
67-
_: LocalDefId,
98+
def_id: LocalDefId,
6899
) {
69-
DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body)
100+
DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body);
101+
102+
if let FnRetTy::Return(ret_ty) = &fn_decl.output
103+
&& let TyKind::Ptr(_) = ret_ty.kind
104+
{
105+
// get the return type of the function or closure
106+
let ty = match cx.tcx.type_of(def_id).instantiate_identity().kind() {
107+
ty::FnDef(..) => cx.tcx.fn_sig(def_id).instantiate_identity(),
108+
ty::Closure(_, args) => args.as_closure().sig(),
109+
_ => return,
110+
};
111+
let ty = ty.output();
112+
113+
// this type is only used for layout computation and pretty-printing, neither of them rely on regions
114+
let ty = cx.tcx.instantiate_bound_regions_with_erased(ty);
115+
116+
// verify that we have a pointer type
117+
let inner_ty = match ty.kind() {
118+
ty::RawPtr(inner_ty, _) => *inner_ty,
119+
_ => return,
120+
};
121+
122+
if cx
123+
.tcx
124+
.layout_of(cx.typing_env().as_query_input(inner_ty))
125+
.is_ok_and(|layout| !layout.is_1zst())
126+
{
127+
let dcx = &DanglingPointerLocalContext {
128+
body: def_id,
129+
fn_ret: ty,
130+
fn_ret_span: ret_ty.span,
131+
fn_ret_inner: inner_ty,
132+
fn_kind: match fn_kind {
133+
FnKind::ItemFn(..) => "function",
134+
FnKind::Method(..) => "method",
135+
FnKind::Closure => "closure",
136+
},
137+
};
138+
139+
// look for `return`s
140+
DanglingPointerReturnSearcher { cx, dcx }.visit_body(body);
141+
142+
// analyze implicit return expression
143+
if let ExprKind::Block(block, None) = &body.value.kind
144+
&& let innermost_block = block.innermost_block()
145+
&& let Some(expr) = innermost_block.expr
146+
{
147+
lint_addr_of_local(cx, dcx, expr);
148+
}
149+
}
150+
}
151+
}
152+
}
153+
154+
struct DanglingPointerLocalContext<'tcx> {
155+
body: LocalDefId,
156+
fn_ret: Ty<'tcx>,
157+
fn_ret_span: Span,
158+
fn_ret_inner: Ty<'tcx>,
159+
fn_kind: &'static str,
160+
}
161+
162+
struct DanglingPointerReturnSearcher<'lcx, 'tcx> {
163+
cx: &'lcx LateContext<'tcx>,
164+
dcx: &'lcx DanglingPointerLocalContext<'tcx>,
165+
}
166+
167+
impl<'tcx> Visitor<'tcx> for DanglingPointerReturnSearcher<'_, 'tcx> {
168+
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result {
169+
if let ExprKind::Ret(Some(expr)) = expr.kind {
170+
lint_addr_of_local(self.cx, self.dcx, expr);
171+
}
172+
walk_expr(self, expr)
173+
}
174+
}
175+
176+
/// Look for `&<path_to_local_in_same_body>` pattern and emit lint for it
177+
fn lint_addr_of_local<'a>(
178+
cx: &LateContext<'a>,
179+
dcx: &DanglingPointerLocalContext<'a>,
180+
expr: &'a Expr<'a>,
181+
) {
182+
// peel casts as they do not interest us here, we want the inner expression.
183+
let (inner, _) = super::utils::peel_casts(cx, expr);
184+
185+
if let ExprKind::AddrOf(_, _, inner_of) = inner.kind
186+
&& let ExprKind::Path(ref qpath) = inner_of.peel_blocks().kind
187+
&& let Res::Local(from) = cx.qpath_res(qpath, inner_of.hir_id)
188+
&& cx.tcx.hir_enclosing_body_owner(from) == dcx.body
189+
{
190+
cx.tcx.emit_node_span_lint(
191+
DANGLING_POINTERS_FROM_LOCALS,
192+
expr.hir_id,
193+
expr.span,
194+
DanglingPointersFromLocals {
195+
ret_ty: dcx.fn_ret,
196+
ret_ty_span: dcx.fn_ret_span,
197+
fn_kind: dcx.fn_kind,
198+
local_var: cx.tcx.hir_span(from),
199+
local_var_name: cx.tcx.hir_ident(from),
200+
local_var_ty: dcx.fn_ret_inner,
201+
created_at: (expr.hir_id != inner.hir_id).then_some(inner.span),
202+
},
203+
);
70204
}
71205
}
72206

‎compiler/rustc_lint/src/lints.rs‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,22 @@ pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
11881188
pub temporary_span: Span,
11891189
}
11901190

1191+
#[derive(LintDiagnostic)]
1192+
#[diag(lint_dangling_pointers_from_locals)]
1193+
#[note]
1194+
pub(crate) struct DanglingPointersFromLocals<'tcx> {
1195+
pub ret_ty: Ty<'tcx>,
1196+
#[label(lint_ret_ty)]
1197+
pub ret_ty_span: Span,
1198+
pub fn_kind: &'static str,
1199+
#[label(lint_local_var)]
1200+
pub local_var: Span,
1201+
pub local_var_name: Ident,
1202+
pub local_var_ty: Ty<'tcx>,
1203+
#[label(lint_created_at)]
1204+
pub created_at: Option<Span>,
1205+
}
1206+
11911207
// multiple_supertrait_upcastable.rs
11921208
#[derive(LintDiagnostic)]
11931209
#[diag(lint_multiple_supertrait_upcastable)]

‎compiler/rustc_resolve/Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2024"
66
[dependencies]
77
# tidy-alphabetical-start
88
bitflags = "2.4.1"
9+
indexmap = "2.4.0"
910
itertools = "0.12"
1011
pulldown-cmark = { version = "0.11", features = ["html"], default-features = false }
1112
rustc_arena = { path = "../rustc_arena" }

‎compiler/rustc_resolve/src/build_reduced_graph.rs‎

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
968968
}
969969
self.r.potentially_unused_imports.push(import);
970970
let imported_binding = self.r.import(binding, import);
971-
if parent == self.r.graph_root {
971+
if ident.name != kw::Underscore && parent == self.r.graph_root {
972972
let ident = ident.normalize_to_macros_2_0();
973973
if let Some(entry) = self.r.extern_prelude.get(&ident)
974974
&& expansion != LocalExpnId::ROOT
@@ -984,23 +984,29 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
984984
// more details: https://github.com/rust-lang/rust/pull/111761
985985
return;
986986
}
987-
let entry = self.r.extern_prelude.entry(ident).or_insert(ExternPreludeEntry {
988-
binding: Cell::new(None),
989-
introduced_by_item: true,
990-
});
991-
if orig_name.is_some() {
992-
entry.introduced_by_item = true;
993-
}
994-
// Binding from `extern crate` item in source code can replace
995-
// a binding from `--extern` on command line here.
996-
if !entry.is_import() {
997-
entry.binding.set(Some(imported_binding));
998-
} else if ident.name != kw::Underscore {
999-
self.r.dcx().span_delayed_bug(
1000-
item.span,
1001-
format!("it had been define the external module '{ident}' multiple times"),
1002-
);
1003-
}
987+
988+
use indexmap::map::Entry;
989+
match self.r.extern_prelude.entry(ident) {
990+
Entry::Occupied(mut occupied) => {
991+
let entry = occupied.get_mut();
992+
if let Some(old_binding) = entry.binding.get()
993+
&& old_binding.is_import()
994+
{
995+
let msg = format!("extern crate `{ident}` already in extern prelude");
996+
self.r.tcx.dcx().span_delayed_bug(item.span, msg);
997+
} else {
998+
// Binding from `extern crate` item in source code can replace
999+
// a binding from `--extern` on command line here.
1000+
entry.binding.set(Some(imported_binding));
1001+
entry.introduced_by_item = orig_name.is_some();
1002+
}
1003+
entry
1004+
}
1005+
Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry {
1006+
binding: Cell::new(Some(imported_binding)),
1007+
introduced_by_item: true,
1008+
}),
1009+
};
10041010
}
10051011
self.r.define_binding_local(parent, ident, TypeNS, imported_binding);
10061012
}

‎compiler/rustc_resolve/src/diagnostics.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,7 +1098,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
10981098
}
10991099
}
11001100
Scope::ExternPrelude => {
1101-
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
1101+
suggestions.extend(this.extern_prelude.keys().filter_map(|ident| {
11021102
let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
11031103
filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
11041104
}));
@@ -1409,7 +1409,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
14091409
);
14101410

14111411
if lookup_ident.span.at_least_rust_2018() {
1412-
for ident in self.extern_prelude.clone().into_keys() {
1412+
for &ident in self.extern_prelude.keys() {
14131413
if ident.span.from_expansion() {
14141414
// Idents are adjusted to the root context before being
14151415
// resolved in the extern prelude, so reporting this to the

‎compiler/rustc_resolve/src/late/diagnostics.rs‎

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2476,19 +2476,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
24762476
} else {
24772477
// Items from the prelude
24782478
if !module.no_implicit_prelude {
2479-
let extern_prelude = self.r.extern_prelude.clone();
2480-
names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
2481-
self.r
2482-
.cstore_mut()
2483-
.maybe_process_path_extern(self.r.tcx, ident.name)
2484-
.and_then(|crate_id| {
2485-
let crate_mod =
2486-
Res::Def(DefKind::Mod, crate_id.as_def_id());
2487-
2488-
filter_fn(crate_mod).then(|| {
2489-
TypoSuggestion::typo_from_ident(*ident, crate_mod)
2490-
})
2491-
})
2479+
names.extend(self.r.extern_prelude.keys().flat_map(|ident| {
2480+
let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
2481+
filter_fn(res)
2482+
.then_some(TypoSuggestion::typo_from_ident(*ident, res))
24922483
}));
24932484

24942485
if let Some(prelude) = self.r.prelude {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /