Skip to content

Commit e45d997

Browse files
committed
Auto merge of #97860 - Dylan-DPC:rollup-t3vxos8, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #97595 (Remove unwrap from get_vtable) - #97597 (Preserve unused pointer to address casts) - #97819 (Recover `import` instead of `use` in item) - #97823 (Recover missing comma after match arm) - #97851 (Use repr(C) when depending on struct layout in ptr tests) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 64a7aa7 + 1660b4b commit e45d997

File tree

20 files changed

+335
-65
lines changed

20 files changed

+335
-65
lines changed

compiler/rustc_middle/src/mir/mod.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -2605,9 +2605,34 @@ pub enum Rvalue<'tcx> {
26052605
static_assert_size!(Rvalue<'_>, 40);
26062606

26072607
impl<'tcx> Rvalue<'tcx> {
2608+
/// Returns true if rvalue can be safely removed when the result is unused.
26082609
#[inline]
2609-
pub fn is_pointer_int_cast(&self) -> bool {
2610-
matches!(self, Rvalue::Cast(CastKind::PointerExposeAddress, _, _))
2610+
pub fn is_safe_to_remove(&self) -> bool {
2611+
match self {
2612+
// Pointer to int casts may be side-effects due to exposing the provenance.
2613+
// While the model is undecided, we should be conservative. See
2614+
// <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
2615+
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
2616+
2617+
Rvalue::Use(_)
2618+
| Rvalue::Repeat(_, _)
2619+
| Rvalue::Ref(_, _, _)
2620+
| Rvalue::ThreadLocalRef(_)
2621+
| Rvalue::AddressOf(_, _)
2622+
| Rvalue::Len(_)
2623+
| Rvalue::Cast(
2624+
CastKind::Misc | CastKind::Pointer(_) | CastKind::PointerFromExposedAddress,
2625+
_,
2626+
_,
2627+
)
2628+
| Rvalue::BinaryOp(_, _)
2629+
| Rvalue::CheckedBinaryOp(_, _)
2630+
| Rvalue::NullaryOp(_, _)
2631+
| Rvalue::UnaryOp(_, _)
2632+
| Rvalue::Discriminant(_)
2633+
| Rvalue::Aggregate(_, _)
2634+
| Rvalue::ShallowInitBox(_, _) => true,
2635+
}
26112636
}
26122637
}
26132638

compiler/rustc_mir_dataflow/src/impls/liveness.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,10 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
244244
// Compute the place that we are storing to, if any
245245
let destination = match &statement.kind {
246246
StatementKind::Assign(assign) => {
247-
if assign.1.is_pointer_int_cast() {
248-
// Pointer to int casts may be side-effects due to exposing the provenance.
249-
// While the model is undecided, we should be conservative. See
250-
// <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
251-
None
252-
} else {
247+
if assign.1.is_safe_to_remove() {
253248
Some(assign.0)
249+
} else {
250+
None
254251
}
255252
}
256253
StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {

compiler/rustc_mir_transform/src/dead_store_elimination.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
3434
for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() {
3535
let loc = Location { block: bb, statement_index };
3636
if let StatementKind::Assign(assign) = &statement.kind {
37-
if assign.1.is_pointer_int_cast() {
37+
if !assign.1.is_safe_to_remove() {
3838
continue;
3939
}
4040
}

compiler/rustc_mir_transform/src/simplify.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -494,8 +494,12 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
494494
StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {}
495495

496496
StatementKind::Assign(box (ref place, ref rvalue)) => {
497-
self.visit_lhs(place, location);
498-
self.visit_rvalue(rvalue, location);
497+
if rvalue.is_safe_to_remove() {
498+
self.visit_lhs(place, location);
499+
self.visit_rvalue(rvalue, location);
500+
} else {
501+
self.super_statement(statement, location);
502+
}
499503
}
500504

501505
StatementKind::SetDiscriminant { ref place, variant_index: _ }

compiler/rustc_parse/src/parser/expr.rs

+38-13
Original file line numberDiff line numberDiff line change
@@ -2718,13 +2718,12 @@ impl<'a> Parser<'a> {
27182718
));
27192719
}
27202720
this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)])
2721-
.map_err(|mut err| {
2722-
match (sm.span_to_lines(expr.span), sm.span_to_lines(arm_start_span)) {
2723-
(Ok(ref expr_lines), Ok(ref arm_start_lines))
2724-
if arm_start_lines.lines[0].end_col
2725-
== expr_lines.lines[0].end_col
2726-
&& expr_lines.lines.len() == 2
2727-
&& this.token == token::FatArrow =>
2721+
.or_else(|mut err| {
2722+
if this.token == token::FatArrow {
2723+
if let Ok(expr_lines) = sm.span_to_lines(expr.span)
2724+
&& let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
2725+
&& arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col
2726+
&& expr_lines.lines.len() == 2
27282727
{
27292728
// We check whether there's any trailing code in the parse span,
27302729
// if there isn't, we very likely have the following:
@@ -2743,15 +2742,41 @@ impl<'a> Parser<'a> {
27432742
",".to_owned(),
27442743
Applicability::MachineApplicable,
27452744
);
2745+
return Err(err);
27462746
}
2747-
_ => {
2748-
err.span_label(
2749-
arrow_span,
2750-
"while parsing the `match` arm starting here",
2751-
);
2747+
} else {
2748+
// FIXME(compiler-errors): We could also recover `; PAT =>` here
2749+
2750+
// Try to parse a following `PAT =>`, if successful
2751+
// then we should recover.
2752+
let mut snapshot = this.create_snapshot_for_diagnostic();
2753+
let pattern_follows = snapshot
2754+
.parse_pat_allow_top_alt(
2755+
None,
2756+
RecoverComma::Yes,
2757+
RecoverColon::Yes,
2758+
CommaRecoveryMode::EitherTupleOrPipe,
2759+
)
2760+
.map_err(|err| err.cancel())
2761+
.is_ok();
2762+
if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
2763+
err.cancel();
2764+
this.struct_span_err(
2765+
hi.shrink_to_hi(),
2766+
"expected `,` following `match` arm",
2767+
)
2768+
.span_suggestion(
2769+
hi.shrink_to_hi(),
2770+
"missing a comma here to end this `match` arm",
2771+
",".to_owned(),
2772+
Applicability::MachineApplicable,
2773+
)
2774+
.emit();
2775+
return Ok(true);
27522776
}
27532777
}
2754-
err
2778+
err.span_label(arrow_span, "while parsing the `match` arm starting here");
2779+
Err(err)
27552780
})?;
27562781
} else {
27572782
this.eat(&token::Comma);

compiler/rustc_parse/src/parser/item.rs

+49-20
Original file line numberDiff line numberDiff line change
@@ -204,25 +204,7 @@ impl<'a> Parser<'a> {
204204
let mut def = || mem::replace(def, Defaultness::Final);
205205

206206
let info = if self.eat_keyword(kw::Use) {
207-
// USE ITEM
208-
let tree = self.parse_use_tree()?;
209-
210-
// If wildcard or glob-like brace syntax doesn't have `;`,
211-
// the user may not know `*` or `{}` should be the last.
212-
if let Err(mut e) = self.expect_semi() {
213-
match tree.kind {
214-
UseTreeKind::Glob => {
215-
e.note("the wildcard token must be last on the path");
216-
}
217-
UseTreeKind::Nested(..) => {
218-
e.note("glob-like brace syntax must be last on the path");
219-
}
220-
_ => (),
221-
}
222-
return Err(e);
223-
}
224-
225-
(Ident::empty(), ItemKind::Use(tree))
207+
self.parse_use_item()?
226208
} else if self.check_fn_front_matter(def_final) {
227209
// FUNCTION ITEM
228210
let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
@@ -288,7 +270,12 @@ impl<'a> Parser<'a> {
288270
} else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
289271
// MACRO_RULES ITEM
290272
self.parse_item_macro_rules(vis, has_bang)?
291-
} else if vis.kind.is_pub() && self.isnt_macro_invocation() {
273+
} else if self.isnt_macro_invocation()
274+
&& (self.token.is_ident_named(Symbol::intern("import"))
275+
|| self.token.is_ident_named(Symbol::intern("using")))
276+
{
277+
return self.recover_import_as_use();
278+
} else if self.isnt_macro_invocation() && vis.kind.is_pub() {
292279
self.recover_missing_kw_before_item()?;
293280
return Ok(None);
294281
} else if macros_allowed && self.check_path() {
@@ -300,6 +287,48 @@ impl<'a> Parser<'a> {
300287
Ok(Some(info))
301288
}
302289

290+
fn recover_import_as_use(&mut self) -> PResult<'a, Option<(Ident, ItemKind)>> {
291+
let span = self.token.span;
292+
let token_name = super::token_descr(&self.token);
293+
let snapshot = self.create_snapshot_for_diagnostic();
294+
self.bump();
295+
match self.parse_use_item() {
296+
Ok(u) => {
297+
self.struct_span_err(span, format!("expected item, found {token_name}"))
298+
.span_suggestion_short(
299+
span,
300+
"items are imported using the `use` keyword",
301+
"use".to_owned(),
302+
Applicability::MachineApplicable,
303+
)
304+
.emit();
305+
Ok(Some(u))
306+
}
307+
Err(e) => {
308+
e.cancel();
309+
self.restore_snapshot(snapshot);
310+
Ok(None)
311+
}
312+
}
313+
}
314+
315+
fn parse_use_item(&mut self) -> PResult<'a, (Ident, ItemKind)> {
316+
let tree = self.parse_use_tree()?;
317+
if let Err(mut e) = self.expect_semi() {
318+
match tree.kind {
319+
UseTreeKind::Glob => {
320+
e.note("the wildcard token must be last on the path");
321+
}
322+
UseTreeKind::Nested(..) => {
323+
e.note("glob-like brace syntax must be last on the path");
324+
}
325+
_ => (),
326+
}
327+
return Err(e);
328+
}
329+
Ok((Ident::empty(), ItemKind::Use(tree)))
330+
}
331+
303332
/// When parsing a statement, would the start of a path be an item?
304333
pub(super) fn is_path_start_item(&mut self) -> bool {
305334
self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`

compiler/rustc_trait_selection/src/traits/util.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -304,22 +304,24 @@ pub fn get_vtable_index_of_object_method<'tcx, N>(
304304
tcx: TyCtxt<'tcx>,
305305
object: &super::ImplSourceObjectData<'tcx, N>,
306306
method_def_id: DefId,
307-
) -> usize {
307+
) -> Option<usize> {
308308
let existential_trait_ref = object
309309
.upcast_trait_ref
310310
.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
311311
let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
312+
312313
// Count number of methods preceding the one we are selecting and
313314
// add them to the total offset.
314-
let index = tcx
315+
if let Some(index) = tcx
315316
.own_existential_vtable_entries(existential_trait_ref)
316317
.iter()
317318
.copied()
318319
.position(|def_id| def_id == method_def_id)
319-
.unwrap_or_else(|| {
320-
bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
321-
});
322-
object.vtable_base + index
320+
{
321+
Some(object.vtable_base + index)
322+
} else {
323+
None
324+
}
323325
}
324326

325327
pub fn closure_trait_ref_and_return_type<'tcx>(

compiler/rustc_ty_utils/src/instance.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,15 @@ fn resolve_associated_item<'tcx>(
349349
_ => None,
350350
},
351351
traits::ImplSource::Object(ref data) => {
352-
let index = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id);
353-
Some(Instance {
354-
def: ty::InstanceDef::Virtual(trait_item_id, index),
355-
substs: rcvr_substs,
356-
})
352+
if let Some(index) = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id)
353+
{
354+
Some(Instance {
355+
def: ty::InstanceDef::Virtual(trait_item_id, index),
356+
substs: rcvr_substs,
357+
})
358+
} else {
359+
None
360+
}
357361
}
358362
traits::ImplSource::Builtin(..) => {
359363
if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {

library/core/tests/ptr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ fn test_const_from_raw_parts() {
1919
#[test]
2020
fn test() {
2121
unsafe {
22+
#[repr(C)]
2223
struct Pair {
2324
fst: isize,
2425
snd: isize,

src/test/mir-opt/simplify-locals.rs

+7
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ fn t4() -> u32 {
6262
unsafe { X + 1 }
6363
}
6464

65+
// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals.diff
66+
fn expose_addr(p: *const usize) {
67+
// Used pointer to address cast. Has a side effect of exposing the provenance.
68+
p as usize;
69+
}
70+
6571
fn main() {
6672
c();
6773
d1();
@@ -71,4 +77,5 @@ fn main() {
7177
t2();
7278
t3();
7379
t4();
80+
expose_addr(&0);
7481
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
- // MIR for `expose_addr` before SimplifyLocals
2+
+ // MIR for `expose_addr` after SimplifyLocals
3+
4+
fn expose_addr(_1: *const usize) -> () {
5+
debug p => _1; // in scope 0 at $DIR/simplify-locals.rs:66:16: 66:17
6+
let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:66:33: 66:33
7+
let _2: usize; // in scope 0 at $DIR/simplify-locals.rs:68:5: 68:15
8+
let mut _3: *const usize; // in scope 0 at $DIR/simplify-locals.rs:68:5: 68:6
9+
10+
bb0: {
11+
StorageLive(_2); // scope 0 at $DIR/simplify-locals.rs:68:5: 68:15
12+
StorageLive(_3); // scope 0 at $DIR/simplify-locals.rs:68:5: 68:6
13+
_3 = _1; // scope 0 at $DIR/simplify-locals.rs:68:5: 68:6
14+
_2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/simplify-locals.rs:68:5: 68:15
15+
StorageDead(_3); // scope 0 at $DIR/simplify-locals.rs:68:14: 68:15
16+
StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:68:15: 68:16
17+
_0 = const (); // scope 0 at $DIR/simplify-locals.rs:66:33: 69:2
18+
return; // scope 0 at $DIR/simplify-locals.rs:69:2: 69:2
19+
}
20+
}
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// run-rustfix
2+
3+
use std::{
4+
//~^ ERROR expected item, found `import`
5+
io::Write,
6+
rc::Rc,
7+
};
8+
9+
pub use std::io;
10+
//~^ ERROR expected item, found `using`
11+
12+
fn main() {
13+
let x = Rc::new(1);
14+
let _ = write!(io::stdout(), "{:?}", x);
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// run-rustfix
2+
3+
import std::{
4+
//~^ ERROR expected item, found `import`
5+
io::Write,
6+
rc::Rc,
7+
};
8+
9+
pub using std::io;
10+
//~^ ERROR expected item, found `using`
11+
12+
fn main() {
13+
let x = Rc::new(1);
14+
let _ = write!(io::stdout(), "{:?}", x);
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: expected item, found `import`
2+
--> $DIR/use_instead_of_import.rs:3:1
3+
|
4+
LL | import std::{
5+
| ^^^^^^ help: items are imported using the `use` keyword
6+
7+
error: expected item, found `using`
8+
--> $DIR/use_instead_of_import.rs:9:5
9+
|
10+
LL | pub using std::io;
11+
| ^^^^^ help: items are imported using the `use` keyword
12+
13+
error: aborting due to 2 previous errors
14+

src/test/ui/parser/match-arm-without-braces.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ fn main() {
4545
15;
4646
}
4747
match S::get(16) {
48-
Some(Val::Foo) => 17
49-
_ => 18, //~ ERROR expected one of
50-
}
48+
Some(Val::Foo) => 17 //~ ERROR expected `,` following `match` arm
49+
_ => 18,
50+
};
5151
match S::get(19) {
5252
Some(Val::Foo) =>
5353
20; //~ ERROR `match` arm body without braces

0 commit comments

Comments
 (0)