Skip to content

Commit

Permalink
Auto merge of rust-lang#67464 - Centril:rollup-j3mkl1m, r=Centril
Browse files Browse the repository at this point in the history
Rollup of 6 pull requests

Successful merges:

 - rust-lang#67130 (Const prop should finish propagation into user defined variables)
 - rust-lang#67163 (Split up ptr/mod.rs in libcore...)
 - rust-lang#67314 (Don't suppress move errors for union fields)
 - rust-lang#67392 (Fix unresolved type span inside async object)
 - rust-lang#67404 (Separate region inference logic from error handling better)
 - rust-lang#67428 (`is_binding_pat`: use explicit match & include or-pats in grammar)

Failed merges:

r? @ghost
bors committed Dec 21, 2019

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents ccd2383 + f465f95 commit 9ff30a7
Showing 18 changed files with 2,090 additions and 1,828 deletions.
755 changes: 755 additions & 0 deletions src/libcore/ptr/const_ptr.rs

Large diffs are not rendered by default.

1,696 changes: 5 additions & 1,691 deletions src/libcore/ptr/mod.rs

Large diffs are not rendered by default.

925 changes: 925 additions & 0 deletions src/libcore/ptr/mut_ptr.rs

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
@@ -1857,6 +1857,16 @@ impl fmt::Display for YieldSource {
}
}

impl From<GeneratorKind> for YieldSource {
fn from(kind: GeneratorKind) -> Self {
match kind {
// Guess based on the kind of the current generator.
GeneratorKind::Gen => Self::Yield,
GeneratorKind::Async(_) => Self::Await,
}
}
}

// N.B., if you change this, you'll probably want to change the corresponding
// type structure in middle/ty.rs as well.
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
10 changes: 9 additions & 1 deletion src/librustc/middle/region.rs
Original file line number Diff line number Diff line change
@@ -1173,6 +1173,7 @@ fn resolve_local<'tcx>(
/// | VariantName(..., P&, ...)
/// | [ ..., P&, ... ]
/// | ( ..., P&, ... )
/// | ... "|" P& "|" ...
/// | box P&
fn is_binding_pat(pat: &hir::Pat) -> bool {
// Note that the code below looks for *explicit* refs only, that is, it won't
@@ -1212,6 +1213,7 @@ fn resolve_local<'tcx>(
pats3.iter().any(|p| is_binding_pat(&p))
}

PatKind::Or(ref subpats) |
PatKind::TupleStruct(_, ref subpats, _) |
PatKind::Tuple(ref subpats, _) => {
subpats.iter().any(|p| is_binding_pat(&p))
@@ -1221,7 +1223,13 @@ fn resolve_local<'tcx>(
is_binding_pat(&subpat)
}

_ => false,
PatKind::Ref(_, _) |
PatKind::Binding(hir::BindingAnnotation::Unannotated, ..) |
PatKind::Binding(hir::BindingAnnotation::Mutable, ..) |
PatKind::Wild |
PatKind::Path(_) |
PatKind::Lit(_) |
PatKind::Range(_, _, _) => false,
}
}

37 changes: 33 additions & 4 deletions src/librustc_mir/borrow_check/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
//! Error reporting machinery for lifetime errors.
use rustc::hir::def_id::DefId;
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc::infer::InferCtxt;
use rustc::infer::NLLRegionVariableOrigin;
use rustc::mir::{ConstraintCategory, Local, Location, Body};
use rustc::infer::{
error_reporting::nice_region_error::NiceRegionError,
InferCtxt, NLLRegionVariableOrigin,
};
use rustc::mir::{
ConstraintCategory, Local, Location, Body,
};
use rustc::ty::{self, RegionVid};
use rustc_index::vec::IndexVec;
use rustc_errors::DiagnosticBuilder;
@@ -93,6 +96,32 @@ pub struct ErrorConstraintInfo {
}

impl<'tcx> RegionInferenceContext<'tcx> {
/// Converts a region inference variable into a `ty::Region` that
/// we can use for error reporting. If `r` is universally bound,
/// then we use the name that we have on record for it. If `r` is
/// existentially bound, then we check its inferred value and try
/// to find a good name from that. Returns `None` if we can't find
/// one (e.g., this is just some random part of the CFG).
pub fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
self.to_error_region_vid(r).and_then(|r| self.definitions[r].external_name)
}

/// Returns the [RegionVid] corresponding to the region returned by
/// `to_error_region`.
pub fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
if self.universal_regions.is_universal_region(r) {
Some(r)
} else {
let r_scc = self.constraint_sccs.scc(r);
let upper_bound = self.universal_upper_bound(r);
if self.scc_values.contains(r_scc, upper_bound) {
self.to_error_region_vid(upper_bound)
} else {
None
}
}
}

/// Tries to find the best constraint to blame for the fact that
/// `R: from_region`, where `R` is some region that meets
/// `target_test`. This works by following the constraint graph,
147 changes: 63 additions & 84 deletions src/librustc_mir/borrow_check/region_infer/mod.rs
Original file line number Diff line number Diff line change
@@ -928,32 +928,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}

/// Converts a region inference variable into a `ty::Region` that
/// we can use for error reporting. If `r` is universally bound,
/// then we use the name that we have on record for it. If `r` is
/// existentially bound, then we check its inferred value and try
/// to find a good name from that. Returns `None` if we can't find
/// one (e.g., this is just some random part of the CFG).
pub fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
self.to_error_region_vid(r).and_then(|r| self.definitions[r].external_name)
}

/// Returns the [RegionVid] corresponding to the region returned by
/// `to_error_region`.
pub fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
if self.universal_regions.is_universal_region(r) {
Some(r)
} else {
let r_scc = self.constraint_sccs.scc(r);
let upper_bound = self.universal_upper_bound(r);
if self.scc_values.contains(r_scc, upper_bound) {
self.to_error_region_vid(upper_bound)
} else {
None
}
}
}

/// Invoked when we have some type-test (e.g., `T: 'X`) that we cannot
/// prove to be satisfied. If this is a closure, we will attempt to
/// "promote" this type-test into our `ClosureRegionRequirements` and
@@ -1164,7 +1138,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// include the CFG anyhow.
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
/// a result `'y`.
fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
pub (in crate::borrow_check) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r));

// Find the smallest universal region that contains all other
@@ -1458,19 +1432,34 @@ impl<'tcx> RegionInferenceContext<'tcx> {
debug!("check_polonius_subset_errors: subset_error longer_fr={:?},\
shorter_fr={:?}", longer_fr, shorter_fr);

self.report_or_propagate_universal_region_error(
let propagated = self.try_propagate_universal_region_error(
*longer_fr,
*shorter_fr,
infcx,
body,
local_names,
upvars,
mir_def_id,
&mut propagated_outlives_requirements,
&mut outlives_suggestion,
errors_buffer,
region_naming,
);
if !propagated {
// If we are not in a context where we can't propagate errors, or we
// could not shrink `fr` to something smaller, then just report an
// error.
//
// Note: in this case, we use the unapproximated regions to report the
// error. This gives better error messages in some cases.
let db = self.report_error(
body,
local_names,
upvars,
infcx,
mir_def_id,
*longer_fr,
NLLRegionVariableOrigin::FreeRegion,
*shorter_fr,
&mut outlives_suggestion,
region_naming,
);

db.buffer(errors_buffer);
}
}

// Handle the placeholder errors as usual, until the chalk-rustc-polonius triumvirate has
@@ -1594,48 +1583,59 @@ impl<'tcx> RegionInferenceContext<'tcx> {
return None;
}

self.report_or_propagate_universal_region_error(
let propagated = self.try_propagate_universal_region_error(
longer_fr,
shorter_fr,
infcx,
body,
local_names,
upvars,
mir_def_id,
propagated_outlives_requirements,
outlives_suggestion,
errors_buffer,
region_naming,
)
);

if propagated {
None
} else {
// If we are not in a context where we can't propagate errors, or we
// could not shrink `fr` to something smaller, then just report an
// error.
//
// Note: in this case, we use the unapproximated regions to report the
// error. This gives better error messages in some cases.
let db = self.report_error(
body,
local_names,
upvars,
infcx,
mir_def_id,
longer_fr,
NLLRegionVariableOrigin::FreeRegion,
shorter_fr,
outlives_suggestion,
region_naming,
);

db.buffer(errors_buffer);

Some(ErrorReported)
}
}

fn report_or_propagate_universal_region_error(
/// Attempt to propagate a region error (e.g. `'a: 'b`) that is not met to a closure's
/// creator. If we cannot, then the caller should report an error to the user.
///
/// Returns `true` if the error was propagated, and `false` otherwise.
fn try_propagate_universal_region_error(
&self,
longer_fr: RegionVid,
shorter_fr: RegionVid,
infcx: &InferCtxt<'_, 'tcx>,
body: &Body<'tcx>,
local_names: &IndexVec<Local, Option<Symbol>>,
upvars: &[Upvar],
mir_def_id: DefId,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
outlives_suggestion: &mut OutlivesSuggestionBuilder<'_>,
errors_buffer: &mut Vec<Diagnostic>,
region_naming: &mut RegionErrorNamingCtx,
) -> Option<ErrorReported> {
debug!(
"report_or_propagate_universal_region_error: fr={:?} does not outlive shorter_fr={:?}",
longer_fr, shorter_fr,
);

) -> bool {
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
// Shrink `longer_fr` until we find a non-local region (if we do).
// We'll call it `fr-` -- it's ever so slightly smaller than
// `longer_fr`.

if let Some(fr_minus) =
self.universal_region_relations.non_local_lower_bound(longer_fr) {
debug!("report_or_propagate_universal_region_error: fr_minus={:?}", fr_minus);
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);

let blame_span_category =
self.find_outlives_blame_span(body, longer_fr,
@@ -1648,7 +1648,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.universal_region_relations
.non_local_upper_bounds(&shorter_fr);
debug!(
"report_or_propagate_universal_region_error: shorter_fr_plus={:?}",
"try_propagate_universal_region_error: shorter_fr_plus={:?}",
shorter_fr_plus
);
for &&fr in &shorter_fr_plus {
@@ -1660,32 +1660,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
category: blame_span_category.0,
});
}
return None;
return true;
}
}

// If we are not in a context where we can't propagate errors, or we
// could not shrink `fr` to something smaller, then just report an
// error.
//
// Note: in this case, we use the unapproximated regions to report the
// error. This gives better error messages in some cases.
let db = self.report_error(
body,
local_names,
upvars,
infcx,
mir_def_id,
longer_fr,
NLLRegionVariableOrigin::FreeRegion,
shorter_fr,
outlives_suggestion,
region_naming,
);

db.buffer(errors_buffer);

Some(ErrorReported)
false
}

fn check_bound_universal_region(
31 changes: 22 additions & 9 deletions src/librustc_mir/dataflow/move_paths/builder.rs
Original file line number Diff line number Diff line change
@@ -103,6 +103,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
}
};

// The move path index of the first union that we find. Once this is
// some we stop creating child move paths, since moves from unions
// move the whole thing.
// We continue looking for other move errors though so that moving
// from `*(u.f: &_)` isn't allowed.
let mut union_path = None;

for (i, elem) in place.projection.iter().enumerate() {
let proj_base = &place.projection[..i];
let body = self.builder.body;
@@ -127,9 +134,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
InteriorOfTypeWithDestructor { container_ty: place_ty },
));
}
// move out of union - always move the entire union
ty::Adt(adt, _) if adt.is_union() => {
return Err(MoveError::UnionMove { path: base });
union_path.get_or_insert(base);
}
ty::Slice(_) => {
return Err(MoveError::cannot_move_out_of(
@@ -155,15 +161,22 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
_ => {}
};

base = self.add_move_path(base, elem, |tcx| {
Place {
base: place.base.clone(),
projection: tcx.intern_place_elems(&place.projection[..i+1]),
}
});
if union_path.is_none() {
base = self.add_move_path(base, elem, |tcx| {
Place {
base: place.base.clone(),
projection: tcx.intern_place_elems(&place.projection[..i+1]),
}
});
}
}

Ok(base)
if let Some(base) = union_path {
// Move out of union - always move the entire union.
Err(MoveError::UnionMove { path: base })
} else {
Ok(base)
}
}

fn add_move_path(
52 changes: 34 additions & 18 deletions src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
@@ -262,7 +262,7 @@ struct ConstPropagator<'mir, 'tcx> {
ecx: InterpCx<'mir, 'tcx, ConstPropMachine>,
tcx: TyCtxt<'tcx>,
source: MirSource<'tcx>,
can_const_prop: IndexVec<Local, bool>,
can_const_prop: IndexVec<Local, ConstPropMode>,
param_env: ParamEnv<'tcx>,
// FIXME(eddyb) avoid cloning these two fields more than once,
// by accessing them through `ecx` instead.
@@ -708,17 +708,28 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
}
}

/// The mode that `ConstProp` is allowed to run in for a given `Local`.
#[derive(Clone, Copy, Debug, PartialEq)]
enum ConstPropMode {
/// The `Local` can be propagated into and reads of this `Local` can also be propagated.
FullConstProp,
/// The `Local` can be propagated into but reads cannot be propagated.
OnlyPropagateInto,
/// No propagation is allowed at all.
NoPropagation,
}

struct CanConstProp {
can_const_prop: IndexVec<Local, bool>,
can_const_prop: IndexVec<Local, ConstPropMode>,
// false at the beginning, once set, there are not allowed to be any more assignments
found_assignment: IndexVec<Local, bool>,
}

impl CanConstProp {
/// returns true if `local` can be propagated
fn check(body: ReadOnlyBodyAndCache<'_, '_>) -> IndexVec<Local, bool> {
fn check(body: ReadOnlyBodyAndCache<'_, '_>) -> IndexVec<Local, ConstPropMode> {
let mut cpv = CanConstProp {
can_const_prop: IndexVec::from_elem(true, &body.local_decls),
can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
found_assignment: IndexVec::from_elem(false, &body.local_decls),
};
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
@@ -728,10 +739,10 @@ impl CanConstProp {
// FIXME(oli-obk): lint variables until they are used in a condition
// FIXME(oli-obk): lint if return value is constant
let local_kind = body.local_kind(local);
*val = local_kind == LocalKind::Temp || local_kind == LocalKind::ReturnPointer;

if !*val {
trace!("local {:?} can't be propagated because it's not a temporary", local);
if local_kind == LocalKind::Arg || local_kind == LocalKind::Var {
*val = ConstPropMode::OnlyPropagateInto;
trace!("local {:?} can't be const propagated because it's not a temporary", local);
}
}
cpv.visit_body(body);
@@ -753,7 +764,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
// only occur in independent execution paths
MutatingUse(MutatingUseContext::Store) => if self.found_assignment[local] {
trace!("local {:?} can't be propagated because of multiple assignments", local);
self.can_const_prop[local] = false;
self.can_const_prop[local] = ConstPropMode::NoPropagation;
} else {
self.found_assignment[local] = true
},
@@ -766,7 +777,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
NonUse(_) => {},
_ => {
trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
self.can_const_prop[local] = false;
self.can_const_prop[local] = ConstPropMode::NoPropagation;
},
}
}
@@ -800,10 +811,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
if let Some(local) = place.as_local() {
let source = statement.source_info;
let can_const_prop = self.can_const_prop[local];
if let Some(()) = self.const_prop(rval, place_layout, source, place) {
if self.can_const_prop[local] {
trace!("propagated into {:?}", local);

if can_const_prop == ConstPropMode::FullConstProp ||
can_const_prop == ConstPropMode::OnlyPropagateInto {
if let Some(value) = self.get_const(local) {
if self.should_const_prop(value) {
trace!("replacing {:?} with {:?}", rval, value);
@@ -812,21 +823,26 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
value,
statement.source_info,
);

if can_const_prop == ConstPropMode::FullConstProp {
trace!("propagated into {:?}", local);
}
}
}
} else {
trace!("can't propagate into {:?}", local);
if local != RETURN_PLACE {
self.remove_const(local);
}
}
}
if self.can_const_prop[local] != ConstPropMode::FullConstProp {
trace!("can't propagate into {:?}", local);
if local != RETURN_PLACE {
self.remove_const(local);
}
}
}
}
} else {
match statement.kind {
StatementKind::StorageLive(local) |
StatementKind::StorageDead(local) if self.can_const_prop[local] => {
StatementKind::StorageDead(local) => {
let frame = self.ecx.frame_mut();
frame.locals[local].value =
if let StatementKind::StorageLive(_) = statement.kind {
21 changes: 14 additions & 7 deletions src/librustc_typeck/check/generator_interior.rs
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ struct InteriorVisitor<'a, 'tcx> {
region_scope_tree: &'tcx region::ScopeTree,
expr_count: usize,
kind: hir::GeneratorKind,
prev_unresolved_span: Option<Span>,
}

impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
@@ -32,7 +33,6 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
debug!("generator_interior: attempting to record type {:?} {:?} {:?} {:?}",
ty, scope, expr, source_span);


let live_across_yield = scope.map(|s| {
self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| {
// If we are recording an expression that is the last yield
@@ -54,15 +54,11 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
}).unwrap_or_else(|| Some(YieldData {
span: DUMMY_SP,
expr_and_pat_count: 0,
source: match self.kind { // Guess based on the kind of the current generator.
hir::GeneratorKind::Gen => hir::YieldSource::Yield,
hir::GeneratorKind::Async(_) => hir::YieldSource::Await,
},
source: self.kind.into(),
}));

if let Some(yield_data) = live_across_yield {
let ty = self.fcx.resolve_vars_if_possible(&ty);

debug!("type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
expr, scope, ty, self.expr_count, yield_data.span);

@@ -74,9 +70,12 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
yield_data.source);

// If unresolved type isn't a ty_var then unresolved_type_span is None
let span = self.prev_unresolved_span.unwrap_or_else(
|| unresolved_type_span.unwrap_or(source_span)
);
self.fcx.need_type_info_err_in_generator(
self.kind,
unresolved_type_span.unwrap_or(source_span),
span,
unresolved_type,
)
.span_note(yield_data.span, &*note)
@@ -94,6 +93,13 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
} else {
debug!("no type in expr = {:?}, count = {:?}, span = {:?}",
expr, self.expr_count, expr.map(|e| e.span));
let ty = self.fcx.resolve_vars_if_possible(&ty);
if let Some((unresolved_type, unresolved_type_span))
= self.fcx.unresolved_type_vars(&ty) {
debug!("remained unresolved_type = {:?}, unresolved_type_span: {:?}",
unresolved_type, unresolved_type_span);
self.prev_unresolved_span = unresolved_type_span;
}
}
}
}
@@ -112,6 +118,7 @@ pub fn resolve_interior<'a, 'tcx>(
region_scope_tree: fcx.tcx.region_scope_tree(def_id),
expr_count: 0,
kind,
prev_unresolved_span: None,
};
intravisit::walk_body(&mut visitor, body);

2 changes: 1 addition & 1 deletion src/test/mir-opt/const_prop/aggregate.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ fn main() {
// ...
// _3 = (const 0i32, const 1i32, const 2i32);
// _2 = const 1i32;
// _1 = Add(move _2, const 0i32);
// _1 = const 1i32;
// ...
// }
// END rustc.main.ConstProp.after.mir
2 changes: 1 addition & 1 deletion src/test/mir-opt/const_prop/array_index.rs
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ fn main() {
// assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
// }
// bb1: {
// _1 = _2[_3];
// _1 = const 2u32;
// ...
// return;
// }
149 changes: 149 additions & 0 deletions src/test/mir-opt/const_prop/optimizes_into_variable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// compile-flags: -C overflow-checks=on

struct Point {
x: u32,
y: u32,
}

fn main() {
let x = 2 + 2;
let y = [0, 1, 2, 3, 4, 5][3];
let z = (Point { x: 12, y: 42}).y;
}

// END RUST SOURCE
// START rustc.main.ConstProp.before.mir
// let mut _0: ();
// let _1: i32;
// let mut _2: (i32, bool);
// let mut _4: [i32; 6];
// let _5: usize;
// let mut _6: usize;
// let mut _7: bool;
// let mut _9: Point;
// scope 1 {
// debug x => _1;
// let _3: i32;
// scope 2 {
// debug y => _3;
// let _8: u32;
// scope 3 {
// debug z => _8;
// }
// }
// }
// bb0: {
// StorageLive(_1);
// _2 = CheckedAdd(const 2i32, const 2i32);
// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
// }
// bb1: {
// _1 = move (_2.0: i32);
// StorageLive(_3);
// StorageLive(_4);
// _4 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32];
// StorageLive(_5);
// _5 = const 3usize;
// _6 = const 6usize;
// _7 = Lt(_5, _6);
// assert(move _7, "index out of bounds: the len is move _6 but the index is _5") -> bb2;
// }
// bb2: {
// _3 = _4[_5];
// StorageDead(_5);
// StorageDead(_4);
// StorageLive(_8);
// StorageLive(_9);
// _9 = Point { x: const 12u32, y: const 42u32 };
// _8 = (_9.1: u32);
// StorageDead(_9);
// _0 = ();
// StorageDead(_8);
// StorageDead(_3);
// StorageDead(_1);
// return;
// }
// END rustc.main.ConstProp.before.mir
// START rustc.main.ConstProp.after.mir
// let mut _0: ();
// let _1: i32;
// let mut _2: (i32, bool);
// let mut _4: [i32; 6];
// let _5: usize;
// let mut _6: usize;
// let mut _7: bool;
// let mut _9: Point;
// scope 1 {
// debug x => _1;
// let _3: i32;
// scope 2 {
// debug y => _3;
// let _8: u32;
// scope 3 {
// debug z => _8;
// }
// }
// }
// bb0: {
// StorageLive(_1);
// _2 = (const 4i32, const false);
// assert(!const false, "attempt to add with overflow") -> bb1;
// }
// bb1: {
// _1 = const 4i32;
// StorageLive(_3);
// StorageLive(_4);
// _4 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32];
// StorageLive(_5);
// _5 = const 3usize;
// _6 = const 6usize;
// _7 = const true;
// assert(const true, "index out of bounds: the len is move _6 but the index is _5") -> bb2;
// }
// bb2: {
// _3 = const 3i32;
// StorageDead(_5);
// StorageDead(_4);
// StorageLive(_8);
// StorageLive(_9);
// _9 = Point { x: const 12u32, y: const 42u32 };
// _8 = const 42u32;
// StorageDead(_9);
// _0 = ();
// StorageDead(_8);
// StorageDead(_3);
// StorageDead(_1);
// return;
// }
// END rustc.main.ConstProp.after.mir
// START rustc.main.SimplifyLocals.after.mir
// let mut _0: ();
// let _1: i32;
// let mut _3: [i32; 6];
// scope 1 {
// debug x => _1;
// let _2: i32;
// scope 2 {
// debug y => _2;
// let _4: u32;
// scope 3 {
// debug z => _4;
// }
// }
// }
// bb0: {
// StorageLive(_1);
// _1 = const 4i32;
// StorageLive(_2);
// StorageLive(_3);
// _3 = [const 0i32, const 1i32, const 2i32, const 3i32, const 4i32, const 5i32];
// _2 = const 3i32;
// StorageDead(_3);
// StorageLive(_4);
// _4 = const 42u32;
// StorageDead(_4);
// StorageDead(_2);
// StorageDead(_1);
// return;
// }
// END rustc.main.SimplifyLocals.after.mir
2 changes: 1 addition & 1 deletion src/test/mir-opt/const_prop/read_immutable_static.rs
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ fn main() {
// _2 = const 2u8;
// ...
// _4 = const 2u8;
// _1 = Add(move _2, move _4);
// _1 = const 4u8;
// ...
// }
// END rustc.main.ConstProp.after.mir
2 changes: 1 addition & 1 deletion src/test/mir-opt/const_prop/repeat.rs
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ fn main() {
// }
// bb1: {
// _2 = const 42u32;
// _1 = Add(move _2, const 0u32);
// _1 = const 42u32;
// ...
// return;
// }
30 changes: 30 additions & 0 deletions src/test/ui/borrowck/move-from-union-field-issue-66500.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Moving from a reference/raw pointer should be an error, even when they're
// the field of a union.

#![feature(untagged_unions)]

union Pointers {
a: &'static String,
b: &'static mut String,
c: *const String,
d: *mut String,
}

unsafe fn move_ref(u: Pointers) -> String {
*u.a
//~^ ERROR cannot move out of `*u.a`
}
unsafe fn move_ref_mut(u: Pointers) -> String {
*u.b
//~^ ERROR cannot move out of `*u.b`
}
unsafe fn move_ptr(u: Pointers) -> String {
*u.c
//~^ ERROR cannot move out of `*u.c`
}
unsafe fn move_ptr_mut(u: Pointers) -> String {
*u.d
//~^ ERROR cannot move out of `*u.d`
}

fn main() {}
27 changes: 27 additions & 0 deletions src/test/ui/borrowck/move-from-union-field-issue-66500.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error[E0507]: cannot move out of `*u.a` which is behind a shared reference
--> $DIR/move-from-union-field-issue-66500.rs:14:5
|
LL | *u.a
| ^^^^ move occurs because `*u.a` has type `std::string::String`, which does not implement the `Copy` trait

error[E0507]: cannot move out of `*u.b` which is behind a mutable reference
--> $DIR/move-from-union-field-issue-66500.rs:18:5
|
LL | *u.b
| ^^^^ move occurs because `*u.b` has type `std::string::String`, which does not implement the `Copy` trait

error[E0507]: cannot move out of `*u.c` which is behind a raw pointer
--> $DIR/move-from-union-field-issue-66500.rs:22:5
|
LL | *u.c
| ^^^^ move occurs because `*u.c` has type `std::string::String`, which does not implement the `Copy` trait

error[E0507]: cannot move out of `*u.d` which is behind a raw pointer
--> $DIR/move-from-union-field-issue-66500.rs:26:5
|
LL | *u.d
| ^^^^ move occurs because `*u.d` has type `std::string::String`, which does not implement the `Copy` trait

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0507`.
20 changes: 10 additions & 10 deletions src/test/ui/consts/offset_from_ub.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error: any use of this value will cause an error
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
LL | intrinsics::ptr_offset_from(self, origin)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| ptr_offset_from cannot compute offset of pointers into different allocations.
| inside call to `std::ptr::<impl *const Struct>::offset_from` at $DIR/offset_from_ub.rs:19:27
| inside call to `std::ptr::const_ptr::<impl *const Struct>::offset_from` at $DIR/offset_from_ub.rs:19:27
|
::: $DIR/offset_from_ub.rs:13:1
|
@@ -21,13 +21,13 @@ LL | | };
= note: `#[deny(const_err)]` on by default

error: any use of this value will cause an error
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
LL | intrinsics::ptr_offset_from(self, origin)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| a memory access tried to interpret some bytes as a pointer
| inside call to `std::ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:25:14
| inside call to `std::ptr::const_ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:25:14
|
::: $DIR/offset_from_ub.rs:23:1
|
@@ -38,13 +38,13 @@ LL | | };
| |__-

error: any use of this value will cause an error
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
LL | intrinsics::ptr_offset_from(self, origin)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| exact_div: 1 cannot be divided by 2 without remainder
| inside call to `std::ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:33:14
| inside call to `std::ptr::const_ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:33:14
|
::: $DIR/offset_from_ub.rs:28:1
|
@@ -58,13 +58,13 @@ LL | | };
| |__-

error: any use of this value will cause an error
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
LL | intrinsics::ptr_offset_from(self, origin)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| invalid use of NULL pointer
| inside call to `std::ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:39:14
| inside call to `std::ptr::const_ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:39:14
|
::: $DIR/offset_from_ub.rs:36:1
|
@@ -76,13 +76,13 @@ LL | | };
| |__-

error: any use of this value will cause an error
--> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
--> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL
|
LL | intrinsics::ptr_offset_from(self, origin)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| a memory access tried to interpret some bytes as a pointer
| inside call to `std::ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:46:14
| inside call to `std::ptr::const_ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:46:14
|
::: $DIR/offset_from_ub.rs:42:1
|

0 comments on commit 9ff30a7

Please sign in to comment.