Auto merge of #42276 - Mark-Simulacrum:rollup, r=Mark-Simulacrum
Rollup of 6 pull requests - Successful merges: #42207, #42217, #42249, #42251, #42260, #42266 - Failed merges:
This commit is contained in:
commit
41e74a2282
@ -43,8 +43,11 @@
|
||||
//! // instead of a max-heap.
|
||||
//! impl Ord for State {
|
||||
//! fn cmp(&self, other: &State) -> Ordering {
|
||||
//! // Notice that the we flip the ordering here
|
||||
//! // Notice that the we flip the ordering on costs.
|
||||
//! // In case of a tie we compare positions - this step is necessary
|
||||
//! // to make implementations of `PartialEq` and `Ord` consistent.
|
||||
//! other.cost.cmp(&self.cost)
|
||||
//! .then_with(|| self.position.cmp(&other.position))
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
|
@ -67,6 +67,10 @@ use self::Ordering::*;
|
||||
/// the rule that `eq` is a strict inverse of `ne`; that is, `!(a == b)` if and
|
||||
/// only if `a != b`.
|
||||
///
|
||||
/// Implementations of `PartialEq`, `PartialOrd`, and `Ord` *must* agree with
|
||||
/// each other. It's easy to accidentally make them disagree by deriving some
|
||||
/// of the traits and manually implementing others.
|
||||
///
|
||||
/// An example implementation for a domain in which two books are considered
|
||||
/// the same book if their ISBN matches, even if the formats differ:
|
||||
///
|
||||
@ -386,6 +390,10 @@ impl<T: Ord> Ord for Reverse<T> {
|
||||
/// Then you must define an implementation for `cmp()`. You may find it useful to use
|
||||
/// `cmp()` on your type's fields.
|
||||
///
|
||||
/// Implementations of `PartialEq`, `PartialOrd`, and `Ord` *must* agree with each other. It's
|
||||
/// easy to accidentally make them disagree by deriving some of the traits and manually
|
||||
/// implementing others.
|
||||
///
|
||||
/// Here's an example where you want to sort people by height only, disregarding `id`
|
||||
/// and `name`:
|
||||
///
|
||||
@ -474,8 +482,8 @@ impl PartialOrd for Ordering {
|
||||
///
|
||||
/// ## How can I implement `PartialOrd`?
|
||||
///
|
||||
/// PartialOrd only requires implementation of the `partial_cmp` method, with the others generated
|
||||
/// from default implementations.
|
||||
/// `PartialOrd` only requires implementation of the `partial_cmp` method, with the others
|
||||
/// generated from default implementations.
|
||||
///
|
||||
/// However it remains possible to implement the others separately for types which do not have a
|
||||
/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 ==
|
||||
@ -483,6 +491,10 @@ impl PartialOrd for Ordering {
|
||||
///
|
||||
/// `PartialOrd` requires your type to be `PartialEq`.
|
||||
///
|
||||
/// Implementations of `PartialEq`, `PartialOrd`, and `Ord` *must* agree with each other. It's
|
||||
/// easy to accidentally make them disagree by deriving some of the traits and manually
|
||||
/// implementing others.
|
||||
///
|
||||
/// If your type is `Ord`, you can implement `partial_cmp()` by using `cmp()`:
|
||||
///
|
||||
/// ```
|
||||
|
@ -40,7 +40,7 @@ use ty::layout::{Layout, TargetDataLayout};
|
||||
use ty::inhabitedness::DefIdForest;
|
||||
use ty::maps;
|
||||
use ty::steal::Steal;
|
||||
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
|
||||
use util::nodemap::{NodeMap, NodeSet, DefIdSet};
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||
|
||||
@ -499,33 +499,6 @@ pub struct GlobalCtxt<'tcx> {
|
||||
/// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime.
|
||||
pub rvalue_promotable_to_static: RefCell<NodeMap<bool>>,
|
||||
|
||||
/// Maps Fn items to a collection of fragment infos.
|
||||
///
|
||||
/// The main goal is to identify data (each of which may be moved
|
||||
/// or assigned) whose subparts are not moved nor assigned
|
||||
/// (i.e. their state is *unfragmented*) and corresponding ast
|
||||
/// nodes where the path to that data is moved or assigned.
|
||||
///
|
||||
/// In the long term, unfragmented values will have their
|
||||
/// destructor entirely driven by a single stack-local drop-flag,
|
||||
/// and their parents, the collections of the unfragmented values
|
||||
/// (or more simply, "fragmented values"), are mapped to the
|
||||
/// corresponding collections of stack-local drop-flags.
|
||||
///
|
||||
/// (However, in the short term that is not the case; e.g. some
|
||||
/// unfragmented paths still need to be zeroed, namely when they
|
||||
/// reference parent data from an outer scope that was not
|
||||
/// entirely moved, and therefore that needs to be zeroed so that
|
||||
/// we do not get double-drop when we hit the end of the parent
|
||||
/// scope.)
|
||||
///
|
||||
/// Also: currently the table solely holds keys for node-ids of
|
||||
/// unfragmented values (see `FragmentInfo` enum definition), but
|
||||
/// longer-term we will need to also store mappings from
|
||||
/// fragmented data to the set of unfragmented pieces that
|
||||
/// constitute it.
|
||||
pub fragment_infos: RefCell<DefIdMap<Vec<ty::FragmentInfo>>>,
|
||||
|
||||
/// The definite name of the current crate after taking into account
|
||||
/// attributes, commandline parameters, etc.
|
||||
pub crate_name: Symbol,
|
||||
@ -730,7 +703,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
rvalue_promotable_to_static: RefCell::new(NodeMap()),
|
||||
fragment_infos: RefCell::new(DefIdMap()),
|
||||
crate_name: Symbol::intern(crate_name),
|
||||
data_layout: data_layout,
|
||||
layout_cache: RefCell::new(FxHashMap()),
|
||||
|
@ -444,17 +444,6 @@ pub struct CReaderCacheKey {
|
||||
pub pos: usize,
|
||||
}
|
||||
|
||||
/// Describes the fragment-state associated with a NodeId.
|
||||
///
|
||||
/// Currently only unfragmented paths have entries in the table,
|
||||
/// but longer-term this enum is expected to expand to also
|
||||
/// include data for fragmented paths.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum FragmentInfo {
|
||||
Moved { var: NodeId, move_expr: NodeId },
|
||||
Assigned { var: NodeId, assign_expr: NodeId, assignee_id: NodeId },
|
||||
}
|
||||
|
||||
// Flags that we track on types. These flags are propagated upwards
|
||||
// through the type during type construction, so that we can quickly
|
||||
// check whether the type has various kinds of types in it without
|
||||
|
@ -266,13 +266,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
/// if not a structure at all. Corresponds to the only possible unsized
|
||||
/// field, and its type can be used to determine unsizing strategy.
|
||||
pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
while let TyAdt(def, substs) = ty.sty {
|
||||
if !def.is_struct() {
|
||||
break;
|
||||
}
|
||||
match def.struct_variant().fields.last() {
|
||||
Some(f) => ty = f.ty(self, substs),
|
||||
None => break,
|
||||
loop {
|
||||
match ty.sty {
|
||||
ty::TyAdt(def, substs) => {
|
||||
if !def.is_struct() {
|
||||
break;
|
||||
}
|
||||
match def.struct_variant().fields.last() {
|
||||
Some(f) => ty = f.ty(self, substs),
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
||||
ty::TyTuple(tys, _) => {
|
||||
if let Some((&last_ty, _)) = tys.split_last() {
|
||||
ty = last_ty;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ty
|
||||
|
@ -1,542 +0,0 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Helper routines used for fragmenting structural paths due to moves for
|
||||
//! tracking drop obligations. Please see the extensive comments in the
|
||||
//! section "Structural fragments" in `README.md`.
|
||||
|
||||
use self::Fragment::*;
|
||||
|
||||
use borrowck::InteriorKind::{InteriorField, InteriorElement};
|
||||
use borrowck::{self, LoanPath};
|
||||
use borrowck::LoanPathKind::{LpVar, LpUpvar, LpDowncast, LpExtend};
|
||||
use borrowck::LoanPathElem::{LpDeref, LpInterior};
|
||||
use borrowck::move_data::InvalidMovePathIndex;
|
||||
use borrowck::move_data::{MoveData, MovePathIndex};
|
||||
use rustc::hir::def_id::{DefId};
|
||||
use rustc::ty::{self, AdtKind, TyCtxt};
|
||||
use rustc::middle::mem_categorization as mc;
|
||||
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||
enum Fragment {
|
||||
// This represents the path described by the move path index
|
||||
Just(MovePathIndex),
|
||||
|
||||
// This represents the collection of all but one of the elements
|
||||
// from an array at the path described by the move path index.
|
||||
// Note that attached MovePathIndex should have mem_categorization
|
||||
// of InteriorElement (i.e. array dereference `&foo[..]`).
|
||||
AllButOneFrom(MovePathIndex),
|
||||
}
|
||||
|
||||
impl Fragment {
|
||||
fn loan_path_repr(&self, move_data: &MoveData) -> String {
|
||||
let lp = |mpi| move_data.path_loan_path(mpi);
|
||||
match *self {
|
||||
Just(mpi) => format!("{:?}", lp(mpi)),
|
||||
AllButOneFrom(mpi) => format!("$(allbutone {:?})", lp(mpi)),
|
||||
}
|
||||
}
|
||||
|
||||
fn loan_path_user_string(&self, move_data: &MoveData) -> String {
|
||||
let lp = |mpi| move_data.path_loan_path(mpi);
|
||||
match *self {
|
||||
Just(mpi) => lp(mpi).to_string(),
|
||||
AllButOneFrom(mpi) => format!("$(allbutone {})", lp(mpi)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_unfragmented_map(this: &mut borrowck::BorrowckCtxt,
|
||||
move_data: &MoveData,
|
||||
id: ast::NodeId) {
|
||||
let fr = &move_data.fragments.borrow();
|
||||
|
||||
// For now, don't care about other kinds of fragments; the precise
|
||||
// classfication of all paths for non-zeroing *drop* needs them,
|
||||
// but the loose approximation used by non-zeroing moves does not.
|
||||
let moved_leaf_paths = fr.moved_leaf_paths();
|
||||
let assigned_leaf_paths = fr.assigned_leaf_paths();
|
||||
|
||||
let mut fragment_infos = Vec::with_capacity(moved_leaf_paths.len());
|
||||
|
||||
let find_var_id = |move_path_index: MovePathIndex| -> Option<ast::NodeId> {
|
||||
let lp = move_data.path_loan_path(move_path_index);
|
||||
match lp.kind {
|
||||
LpVar(var_id) => Some(var_id),
|
||||
LpUpvar(ty::UpvarId { var_id, closure_expr_id }) => {
|
||||
// The `var_id` is unique *relative to* the current function.
|
||||
// (Check that we are indeed talking about the same function.)
|
||||
assert_eq!(id, closure_expr_id);
|
||||
Some(var_id)
|
||||
}
|
||||
LpDowncast(..) | LpExtend(..) => {
|
||||
// This simple implementation of non-zeroing move does
|
||||
// not attempt to deal with tracking substructure
|
||||
// accurately in the general case.
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let moves = move_data.moves.borrow();
|
||||
for &move_path_index in moved_leaf_paths {
|
||||
let var_id = match find_var_id(move_path_index) {
|
||||
None => continue,
|
||||
Some(var_id) => var_id,
|
||||
};
|
||||
|
||||
move_data.each_applicable_move(move_path_index, |move_index| {
|
||||
let info = ty::FragmentInfo::Moved {
|
||||
var: var_id,
|
||||
move_expr: moves[move_index.get()].id,
|
||||
};
|
||||
debug!("fragment_infos push({:?} \
|
||||
due to move_path_index: {} move_index: {}",
|
||||
info, move_path_index.get(), move_index.get());
|
||||
fragment_infos.push(info);
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
for &move_path_index in assigned_leaf_paths {
|
||||
let var_id = match find_var_id(move_path_index) {
|
||||
None => continue,
|
||||
Some(var_id) => var_id,
|
||||
};
|
||||
|
||||
let var_assigns = move_data.var_assignments.borrow();
|
||||
for var_assign in var_assigns.iter()
|
||||
.filter(|&assign| assign.path == move_path_index)
|
||||
{
|
||||
let info = ty::FragmentInfo::Assigned {
|
||||
var: var_id,
|
||||
assign_expr: var_assign.id,
|
||||
assignee_id: var_assign.assignee_id,
|
||||
};
|
||||
debug!("fragment_infos push({:?} due to var_assignment", info);
|
||||
fragment_infos.push(info);
|
||||
}
|
||||
}
|
||||
|
||||
let mut fraginfo_map = this.tcx.fragment_infos.borrow_mut();
|
||||
let fn_did = this.tcx.hir.local_def_id(id);
|
||||
let prev = fraginfo_map.insert(fn_did, fragment_infos);
|
||||
assert!(prev.is_none());
|
||||
}
|
||||
|
||||
pub struct FragmentSets {
|
||||
/// During move_data construction, `moved_leaf_paths` tracks paths
|
||||
/// that have been used directly by being moved out of. When
|
||||
/// move_data construction has been completed, `moved_leaf_paths`
|
||||
/// tracks such paths that are *leaf fragments* (e.g. `a.j` if we
|
||||
/// never move out any child like `a.j.x`); any parent paths
|
||||
/// (e.g. `a` for the `a.j` example) are moved over to
|
||||
/// `parents_of_fragments`.
|
||||
moved_leaf_paths: Vec<MovePathIndex>,
|
||||
|
||||
/// `assigned_leaf_paths` tracks paths that have been used
|
||||
/// directly by being overwritten, but is otherwise much like
|
||||
/// `moved_leaf_paths`.
|
||||
assigned_leaf_paths: Vec<MovePathIndex>,
|
||||
|
||||
/// `parents_of_fragments` tracks paths that are definitely
|
||||
/// parents of paths that have been moved.
|
||||
///
|
||||
/// FIXME(pnkfelix) probably do not want/need
|
||||
/// `parents_of_fragments` at all, if we can avoid it.
|
||||
///
|
||||
/// Update: I do not see a way to avoid it. Maybe just remove
|
||||
/// above fixme, or at least document why doing this may be hard.
|
||||
parents_of_fragments: Vec<MovePathIndex>,
|
||||
|
||||
/// During move_data construction (specifically the
|
||||
/// fixup_fragment_sets call), `unmoved_fragments` tracks paths
|
||||
/// that have been "left behind" after a sibling has been moved or
|
||||
/// assigned. When move_data construction has been completed,
|
||||
/// `unmoved_fragments` tracks paths that were *only* results of
|
||||
/// being left-behind, and never directly moved themselves.
|
||||
unmoved_fragments: Vec<Fragment>,
|
||||
}
|
||||
|
||||
impl FragmentSets {
|
||||
pub fn new() -> FragmentSets {
|
||||
FragmentSets {
|
||||
unmoved_fragments: Vec::new(),
|
||||
moved_leaf_paths: Vec::new(),
|
||||
assigned_leaf_paths: Vec::new(),
|
||||
parents_of_fragments: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn moved_leaf_paths(&self) -> &[MovePathIndex] {
|
||||
&self.moved_leaf_paths
|
||||
}
|
||||
|
||||
pub fn assigned_leaf_paths(&self) -> &[MovePathIndex] {
|
||||
&self.assigned_leaf_paths
|
||||
}
|
||||
|
||||
pub fn add_move(&mut self, path_index: MovePathIndex) {
|
||||
self.moved_leaf_paths.push(path_index);
|
||||
}
|
||||
|
||||
pub fn add_assignment(&mut self, path_index: MovePathIndex) {
|
||||
self.assigned_leaf_paths.push(path_index);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
id: ast::NodeId) {
|
||||
let span_err = tcx.hir.attrs(id).iter()
|
||||
.any(|a| a.check_name("rustc_move_fragments"));
|
||||
let print = tcx.sess.opts.debugging_opts.print_move_fragments;
|
||||
|
||||
if !span_err && !print { return; }
|
||||
|
||||
let sp = tcx.hir.span(id);
|
||||
|
||||
let instrument_all_paths = |kind, vec_rc: &Vec<MovePathIndex>| {
|
||||
for (i, mpi) in vec_rc.iter().enumerate() {
|
||||
let lp = || this.path_loan_path(*mpi);
|
||||
if span_err {
|
||||
tcx.sess.span_err(sp, &format!("{}: `{}`", kind, lp()));
|
||||
}
|
||||
if print {
|
||||
println!("id:{} {}[{}] `{}`", id, kind, i, lp());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let instrument_all_fragments = |kind, vec_rc: &Vec<Fragment>| {
|
||||
for (i, f) in vec_rc.iter().enumerate() {
|
||||
let render = || f.loan_path_user_string(this);
|
||||
if span_err {
|
||||
tcx.sess.span_err(sp, &format!("{}: `{}`", kind, render()));
|
||||
}
|
||||
if print {
|
||||
println!("id:{} {}[{}] `{}`", id, kind, i, render());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let fragments = this.fragments.borrow();
|
||||
instrument_all_paths("moved_leaf_path", &fragments.moved_leaf_paths);
|
||||
instrument_all_fragments("unmoved_fragment", &fragments.unmoved_fragments);
|
||||
instrument_all_paths("parent_of_fragments", &fragments.parents_of_fragments);
|
||||
instrument_all_paths("assigned_leaf_path", &fragments.assigned_leaf_paths);
|
||||
}
|
||||
|
||||
/// Normalizes the fragment sets in `this`; i.e., removes duplicate entries, constructs the set of
|
||||
/// parents, and constructs the left-over fragments.
|
||||
///
|
||||
/// Note: "left-over fragments" means paths that were not directly referenced in moves nor
|
||||
/// assignments, but must nonetheless be tracked as potential drop obligations.
|
||||
pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
|
||||
let mut fragments = this.fragments.borrow_mut();
|
||||
|
||||
// Swap out contents of fragments so that we can modify the fields
|
||||
// without borrowing the common fragments.
|
||||
let mut unmoved = mem::replace(&mut fragments.unmoved_fragments, vec![]);
|
||||
let mut parents = mem::replace(&mut fragments.parents_of_fragments, vec![]);
|
||||
let mut moved = mem::replace(&mut fragments.moved_leaf_paths, vec![]);
|
||||
let mut assigned = mem::replace(&mut fragments.assigned_leaf_paths, vec![]);
|
||||
|
||||
let path_lps = |mpis: &[MovePathIndex]| -> Vec<String> {
|
||||
mpis.iter().map(|mpi| format!("{:?}", this.path_loan_path(*mpi))).collect()
|
||||
};
|
||||
|
||||
let frag_lps = |fs: &[Fragment]| -> Vec<String> {
|
||||
fs.iter().map(|f| f.loan_path_repr(this)).collect()
|
||||
};
|
||||
|
||||
// First, filter out duplicates
|
||||
moved.sort();
|
||||
moved.dedup();
|
||||
debug!("fragments 1 moved: {:?}", path_lps(&moved));
|
||||
|
||||
assigned.sort();
|
||||
assigned.dedup();
|
||||
debug!("fragments 1 assigned: {:?}", path_lps(&assigned));
|
||||
|
||||
// Second, build parents from the moved and assigned.
|
||||
for m in &moved {
|
||||
let mut p = this.path_parent(*m);
|
||||
while p != InvalidMovePathIndex {
|
||||
parents.push(p);
|
||||
p = this.path_parent(p);
|
||||
}
|
||||
}
|
||||
for a in &assigned {
|
||||
let mut p = this.path_parent(*a);
|
||||
while p != InvalidMovePathIndex {
|
||||
parents.push(p);
|
||||
p = this.path_parent(p);
|
||||
}
|
||||
}
|
||||
|
||||
parents.sort();
|
||||
parents.dedup();
|
||||
debug!("fragments 2 parents: {:?}", path_lps(&parents));
|
||||
|
||||
// Third, filter the moved and assigned fragments down to just the non-parents
|
||||
moved.retain(|f| non_member(*f, &parents));
|
||||
debug!("fragments 3 moved: {:?}", path_lps(&moved));
|
||||
|
||||
assigned.retain(|f| non_member(*f, &parents));
|
||||
debug!("fragments 3 assigned: {:?}", path_lps(&assigned));
|
||||
|
||||
// Fourth, build the leftover from the moved, assigned, and parents.
|
||||
for m in &moved {
|
||||
let lp = this.path_loan_path(*m);
|
||||
add_fragment_siblings(this, tcx, &mut unmoved, lp, None);
|
||||
}
|
||||
for a in &assigned {
|
||||
let lp = this.path_loan_path(*a);
|
||||
add_fragment_siblings(this, tcx, &mut unmoved, lp, None);
|
||||
}
|
||||
for p in &parents {
|
||||
let lp = this.path_loan_path(*p);
|
||||
add_fragment_siblings(this, tcx, &mut unmoved, lp, None);
|
||||
}
|
||||
|
||||
unmoved.sort();
|
||||
unmoved.dedup();
|
||||
debug!("fragments 4 unmoved: {:?}", frag_lps(&unmoved));
|
||||
|
||||
// Fifth, filter the leftover fragments down to its core.
|
||||
unmoved.retain(|f| match *f {
|
||||
AllButOneFrom(_) => true,
|
||||
Just(mpi) => non_member(mpi, &parents) &&
|
||||
non_member(mpi, &moved) &&
|
||||
non_member(mpi, &assigned)
|
||||
});
|
||||
debug!("fragments 5 unmoved: {:?}", frag_lps(&unmoved));
|
||||
|
||||
// Swap contents back in.
|
||||
fragments.unmoved_fragments = unmoved;
|
||||
fragments.parents_of_fragments = parents;
|
||||
fragments.moved_leaf_paths = moved;
|
||||
fragments.assigned_leaf_paths = assigned;
|
||||
|
||||
return;
|
||||
|
||||
fn non_member(elem: MovePathIndex, set: &[MovePathIndex]) -> bool {
|
||||
match set.binary_search(&elem) {
|
||||
Ok(_) => false,
|
||||
Err(_) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds all of the precisely-tracked siblings of `lp` as potential move paths of interest. For
|
||||
/// example, if `lp` represents `s.x.j`, then adds moves paths for `s.x.i` and `s.x.k`, the
|
||||
/// siblings of `s.x.j`.
|
||||
fn add_fragment_siblings<'a, 'tcx>(this: &MoveData<'tcx>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
gathered_fragments: &mut Vec<Fragment>,
|
||||
lp: Rc<LoanPath<'tcx>>,
|
||||
origin_id: Option<ast::NodeId>) {
|
||||
match lp.kind {
|
||||
LpVar(_) | LpUpvar(..) => {} // Local variables have no siblings.
|
||||
|
||||
// Consuming a downcast is like consuming the original value, so propage inward.
|
||||
LpDowncast(ref loan_parent, _) => {
|
||||
add_fragment_siblings(this, tcx, gathered_fragments, loan_parent.clone(), origin_id);
|
||||
}
|
||||
|
||||
// *LV for Unique consumes the contents of the box (at
|
||||
// least when it is non-copy...), so propagate inward.
|
||||
LpExtend(ref loan_parent, _, LpDeref(mc::Unique)) => {
|
||||
add_fragment_siblings(this, tcx, gathered_fragments, loan_parent.clone(), origin_id);
|
||||
}
|
||||
|
||||
// *LV for unsafe and borrowed pointers do not consume their loan path, so stop here.
|
||||
LpExtend(.., LpDeref(mc::UnsafePtr(..))) |
|
||||
LpExtend(.., LpDeref(mc::Implicit(..))) |
|
||||
LpExtend(.., LpDeref(mc::BorrowedPtr(..))) => {}
|
||||
|
||||
// FIXME (pnkfelix): LV[j] should be tracked, at least in the
|
||||
// sense of we will track the remaining drop obligation of the
|
||||
// rest of the array.
|
||||
//
|
||||
// Well, either that or LV[j] should be made illegal.
|
||||
// But even then, we will need to deal with destructuring
|
||||
// bind.
|
||||
//
|
||||
// Anyway, for now: LV[j] is not tracked precisely
|
||||
LpExtend(.., LpInterior(_, InteriorElement(..))) => {
|
||||
let mp = this.move_path(tcx, lp.clone());
|
||||
gathered_fragments.push(AllButOneFrom(mp));
|
||||
}
|
||||
|
||||
// field access LV.x and tuple access LV#k are the cases
|
||||
// we are interested in
|
||||
LpExtend(ref loan_parent, mc,
|
||||
LpInterior(_, InteriorField(ref field_name))) => {
|
||||
let enum_variant_info = match loan_parent.kind {
|
||||
LpDowncast(ref loan_parent_2, variant_def_id) =>
|
||||
Some((variant_def_id, loan_parent_2.clone())),
|
||||
LpExtend(..) | LpVar(..) | LpUpvar(..) =>
|
||||
None,
|
||||
};
|
||||
add_fragment_siblings_for_extension(
|
||||
this,
|
||||
tcx,
|
||||
gathered_fragments,
|
||||
loan_parent, mc, field_name, &lp, origin_id, enum_variant_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// We have determined that `origin_lp` destructures to LpExtend(parent, original_field_name).
|
||||
/// Based on this, add move paths for all of the siblings of `origin_lp`.
|
||||
fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
gathered_fragments: &mut Vec<Fragment>,
|
||||
parent_lp: &Rc<LoanPath<'tcx>>,
|
||||
mc: mc::MutabilityCategory,
|
||||
origin_field_name: &mc::FieldName,
|
||||
origin_lp: &Rc<LoanPath<'tcx>>,
|
||||
origin_id: Option<ast::NodeId>,
|
||||
enum_variant_info: Option<(DefId,
|
||||
Rc<LoanPath<'tcx>>)>) {
|
||||
let parent_ty = parent_lp.to_type();
|
||||
|
||||
let mut add_fragment_sibling_local = |field_name, variant_did| {
|
||||
add_fragment_sibling_core(
|
||||
this, tcx, gathered_fragments, parent_lp.clone(), mc, field_name, origin_lp,
|
||||
variant_did);
|
||||
};
|
||||
|
||||
match parent_ty.sty {
|
||||
ty::TyTuple(ref v, _) => {
|
||||
let tuple_idx = match *origin_field_name {
|
||||
mc::PositionalField(tuple_idx) => tuple_idx,
|
||||
mc::NamedField(_) =>
|
||||
bug!("tuple type {:?} should not have named fields.",
|
||||
parent_ty),
|
||||
};
|
||||
let tuple_len = v.len();
|
||||
for i in 0..tuple_len {
|
||||
if i == tuple_idx { continue }
|
||||
let field_name = mc::PositionalField(i);
|
||||
add_fragment_sibling_local(field_name, None);
|
||||
}
|
||||
}
|
||||
|
||||
ty::TyAdt(def, ..) => match def.adt_kind() {
|
||||
AdtKind::Struct => {
|
||||
match *origin_field_name {
|
||||
mc::NamedField(ast_name) => {
|
||||
for f in &def.struct_variant().fields {
|
||||
if f.name == ast_name {
|
||||
continue;
|
||||
}
|
||||
let field_name = mc::NamedField(f.name);
|
||||
add_fragment_sibling_local(field_name, None);
|
||||
}
|
||||
}
|
||||
mc::PositionalField(tuple_idx) => {
|
||||
for (i, _f) in def.struct_variant().fields.iter().enumerate() {
|
||||
if i == tuple_idx {
|
||||
continue
|
||||
}
|
||||
let field_name = mc::PositionalField(i);
|
||||
add_fragment_sibling_local(field_name, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AdtKind::Union => {
|
||||
// Do nothing, all union fields are moved/assigned together.
|
||||
}
|
||||
AdtKind::Enum => {
|
||||
let variant = match enum_variant_info {
|
||||
Some((vid, ref _lp2)) => def.variant_with_id(vid),
|
||||
None => {
|
||||
assert!(def.is_univariant());
|
||||
&def.variants[0]
|
||||
}
|
||||
};
|
||||
match *origin_field_name {
|
||||
mc::NamedField(ast_name) => {
|
||||
for field in &variant.fields {
|
||||
if field.name == ast_name {
|
||||
continue;
|
||||
}
|
||||
let field_name = mc::NamedField(field.name);
|
||||
add_fragment_sibling_local(field_name, Some(variant.did));
|
||||
}
|
||||
}
|
||||
mc::PositionalField(tuple_idx) => {
|
||||
for (i, _f) in variant.fields.iter().enumerate() {
|
||||
if tuple_idx == i {
|
||||
continue;
|
||||
}
|
||||
let field_name = mc::PositionalField(i);
|
||||
add_fragment_sibling_local(field_name, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ref ty => {
|
||||
let span = origin_id.map_or(DUMMY_SP, |id| tcx.hir.span(id));
|
||||
span_bug!(span,
|
||||
"type {:?} ({:?}) is not fragmentable",
|
||||
parent_ty, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the single sibling `LpExtend(parent, new_field_name)` of `origin_lp` (the original
|
||||
/// loan-path).
|
||||
fn add_fragment_sibling_core<'a, 'tcx>(this: &MoveData<'tcx>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
gathered_fragments: &mut Vec<Fragment>,
|
||||
parent: Rc<LoanPath<'tcx>>,
|
||||
mc: mc::MutabilityCategory,
|
||||
new_field_name: mc::FieldName,
|
||||
origin_lp: &Rc<LoanPath<'tcx>>,
|
||||
enum_variant_did: Option<DefId>)
|
||||
-> MovePathIndex {
|
||||
let opt_variant_did = match parent.kind {
|
||||
LpDowncast(_, variant_did) => Some(variant_did),
|
||||
LpVar(..) | LpUpvar(..) | LpExtend(..) => enum_variant_did,
|
||||
};
|
||||
|
||||
let loan_path_elem = LpInterior(opt_variant_did, InteriorField(new_field_name));
|
||||
let new_lp_type = match new_field_name {
|
||||
mc::NamedField(ast_name) =>
|
||||
tcx.named_element_ty(parent.to_type(), ast_name, opt_variant_did),
|
||||
mc::PositionalField(idx) =>
|
||||
tcx.positional_element_ty(parent.to_type(), idx, opt_variant_did),
|
||||
};
|
||||
let new_lp_variant = LpExtend(parent, mc, loan_path_elem);
|
||||
let new_lp = LoanPath::new(new_lp_variant, new_lp_type.unwrap());
|
||||
debug!("add_fragment_sibling_core(new_lp={:?}, origin_lp={:?})",
|
||||
new_lp, origin_lp);
|
||||
let mp = this.move_path(tcx, Rc::new(new_lp));
|
||||
|
||||
// Do not worry about checking for duplicates here; we will sort
|
||||
// and dedup after all are added.
|
||||
gathered_fragments.push(Just(mp));
|
||||
|
||||
mp
|
||||
}
|
@ -129,13 +129,6 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) {
|
||||
move_data: flowed_moves } =
|
||||
build_borrowck_dataflow_data(bccx, &cfg, body_id);
|
||||
|
||||
move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
|
||||
bccx.tcx,
|
||||
owner_id);
|
||||
move_data::fragments::build_unfragmented_map(bccx,
|
||||
&flowed_moves.move_data,
|
||||
owner_id);
|
||||
|
||||
check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body);
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,6 @@ use syntax_pos::Span;
|
||||
use rustc::hir;
|
||||
use rustc::hir::intravisit::IdRange;
|
||||
|
||||
#[path="fragments.rs"]
|
||||
pub mod fragments;
|
||||
|
||||
pub struct MoveData<'tcx> {
|
||||
/// Move paths. See section "Move paths" in `README.md`.
|
||||
pub paths: RefCell<Vec<MovePath<'tcx>>>,
|
||||
@ -62,9 +59,6 @@ pub struct MoveData<'tcx> {
|
||||
|
||||
/// Assignments to a variable or path, like `x = foo`, but not `x += foo`.
|
||||
pub assignee_ids: RefCell<NodeSet>,
|
||||
|
||||
/// Path-fragments from moves in to or out of parts of structured data.
|
||||
pub fragments: RefCell<fragments::FragmentSets>,
|
||||
}
|
||||
|
||||
pub struct FlowedMoveData<'a, 'tcx: 'a> {
|
||||
@ -223,7 +217,6 @@ impl<'a, 'tcx> MoveData<'tcx> {
|
||||
var_assignments: RefCell::new(Vec::new()),
|
||||
variant_matches: RefCell::new(Vec::new()),
|
||||
assignee_ids: RefCell::new(NodeSet()),
|
||||
fragments: RefCell::new(fragments::FragmentSets::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,8 +394,6 @@ impl<'a, 'tcx> MoveData<'tcx> {
|
||||
let path_index = self.move_path(tcx, lp.clone());
|
||||
let move_index = MoveIndex(self.moves.borrow().len());
|
||||
|
||||
self.fragments.borrow_mut().add_move(path_index);
|
||||
|
||||
let next_move = self.path_first_move(path_index);
|
||||
self.set_path_first_move(path_index, move_index);
|
||||
|
||||
@ -458,8 +449,6 @@ impl<'a, 'tcx> MoveData<'tcx> {
|
||||
|
||||
let path_index = self.move_path(tcx, lp.clone());
|
||||
|
||||
self.fragments.borrow_mut().add_assignment(path_index);
|
||||
|
||||
match mode {
|
||||
MutateMode::Init | MutateMode::JustWrite => {
|
||||
self.assignee_ids.borrow_mut().insert(assignee_id);
|
||||
@ -502,8 +491,6 @@ impl<'a, 'tcx> MoveData<'tcx> {
|
||||
let path_index = self.move_path(tcx, lp.clone());
|
||||
let base_path_index = self.move_path(tcx, base_lp.clone());
|
||||
|
||||
self.fragments.borrow_mut().add_assignment(path_index);
|
||||
|
||||
let variant_match = VariantMatch {
|
||||
path: path_index,
|
||||
base_path: base_path_index,
|
||||
@ -514,10 +501,6 @@ impl<'a, 'tcx> MoveData<'tcx> {
|
||||
self.variant_matches.borrow_mut().push(variant_match);
|
||||
}
|
||||
|
||||
fn fixup_fragment_sets(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
fragments::fixup_fragment_sets(self, tcx)
|
||||
}
|
||||
|
||||
/// Adds the gen/kills for the various moves and
|
||||
/// assignments into the provided data flow contexts.
|
||||
/// Moves are generated by moves and killed by assignments and
|
||||
@ -677,8 +660,6 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
|
||||
id_range,
|
||||
move_data.var_assignments.borrow().len());
|
||||
|
||||
move_data.fixup_fragment_sets(tcx);
|
||||
|
||||
move_data.add_gen_kills(bccx,
|
||||
&mut dfcx_moves,
|
||||
&mut dfcx_assign);
|
||||
|
@ -40,8 +40,8 @@ const CFG: &'static str = "cfg";
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum Disposition { Reused, Translated }
|
||||
|
||||
pub fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
modules: &[ModuleTranslation]) {
|
||||
pub(crate) fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
modules: &[ModuleTranslation]) {
|
||||
let _ignore = tcx.dep_graph.in_ignore();
|
||||
|
||||
if tcx.sess.opts.incremental.is_none() {
|
||||
|
@ -14,18 +14,16 @@ use super::rpath::RPathConfig;
|
||||
use super::rpath;
|
||||
use super::msvc;
|
||||
use metadata::METADATA_FILENAME;
|
||||
use session::config;
|
||||
use session::config::NoDebugInfo;
|
||||
use session::config::{OutputFilenames, Input, OutputType};
|
||||
use session::filesearch;
|
||||
use session::search_paths::PathKind;
|
||||
use session::Session;
|
||||
use middle::cstore::{self, LinkMeta, NativeLibrary, LibSource};
|
||||
use middle::cstore::{LinkagePreference, NativeLibraryKind};
|
||||
use middle::dependency_format::Linkage;
|
||||
use rustc::session::config::{self, NoDebugInfo, OutputFilenames, Input, OutputType};
|
||||
use rustc::session::filesearch;
|
||||
use rustc::session::search_paths::PathKind;
|
||||
use rustc::session::Session;
|
||||
use rustc::middle::cstore::{self, LinkMeta, NativeLibrary, LibSource, LinkagePreference,
|
||||
NativeLibraryKind};
|
||||
use rustc::middle::dependency_format::Linkage;
|
||||
use CrateTranslation;
|
||||
use util::common::time;
|
||||
use util::fs::fix_windows_verbatim_for_gcc;
|
||||
use rustc::util::common::time;
|
||||
use rustc::util::fs::fix_windows_verbatim_for_gcc;
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::hir::def_id::CrateNum;
|
||||
use rustc::hir::svh::Svh;
|
||||
|
@ -20,11 +20,11 @@ use context::SharedCrateContext;
|
||||
|
||||
use back::archive;
|
||||
use back::symbol_export::{self, ExportedSymbols};
|
||||
use middle::dependency_format::Linkage;
|
||||
use rustc::middle::dependency_format::Linkage;
|
||||
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
|
||||
use rustc_back::LinkerFlavor;
|
||||
use session::Session;
|
||||
use session::config::{self, CrateType, OptLevel, DebugInfoLevel};
|
||||
use rustc::session::Session;
|
||||
use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel};
|
||||
use serialize::{json, Encoder};
|
||||
|
||||
/// For all the linkers we support, and information they might
|
||||
|
@ -52,7 +52,7 @@ mod platform {
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use session::Session;
|
||||
use rustc::session::Session;
|
||||
use super::arch::{host_arch, Arch};
|
||||
use super::registry::LOCAL_MACHINE;
|
||||
|
||||
@ -296,7 +296,7 @@ mod platform {
|
||||
mod platform {
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use session::Session;
|
||||
use rustc::session::Session;
|
||||
pub fn link_exe_cmd(_sess: &Session) -> (Command, Option<PathBuf>) {
|
||||
(Command::new("link.exe"), None)
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
use context::SharedCrateContext;
|
||||
use monomorphize::Instance;
|
||||
use util::nodemap::FxHashMap;
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
|
||||
use rustc::session::config;
|
||||
use rustc::ty::TyCtxt;
|
||||
|
@ -348,16 +348,6 @@ impl ItemPathBuffer for SymbolPathBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exported_name_from_type_and_prefix<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
t: Ty<'tcx>,
|
||||
prefix: &str)
|
||||
-> String {
|
||||
let hash = get_symbol_hash(tcx, None, t, None);
|
||||
let mut buffer = SymbolPathBuffer::new();
|
||||
buffer.push(prefix);
|
||||
buffer.finish(hash)
|
||||
}
|
||||
|
||||
// Name sanitation. LLVM will happily accept identifiers with weird names, but
|
||||
// gas doesn't!
|
||||
// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
|
||||
|
@ -12,16 +12,15 @@ use back::lto;
|
||||
use back::link::{get_linker, remove};
|
||||
use back::symbol_export::ExportedSymbols;
|
||||
use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
|
||||
use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses, Sanitizer};
|
||||
use session::Session;
|
||||
use session::config::{self, OutputType};
|
||||
use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
|
||||
AllPasses, Sanitizer};
|
||||
use rustc::session::Session;
|
||||
use llvm;
|
||||
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
|
||||
use llvm::SMDiagnosticRef;
|
||||
use {CrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation};
|
||||
use util::common::{time, time_depth, set_time_depth};
|
||||
use util::common::path2cstr;
|
||||
use util::fs::link_or_copy;
|
||||
use rustc::util::common::{time, time_depth, set_time_depth, path2cstr};
|
||||
use rustc::util::fs::link_or_copy;
|
||||
use errors::{self, Handler, Level, DiagnosticBuilder};
|
||||
use errors::emitter::Emitter;
|
||||
use syntax_pos::MultiSpan;
|
||||
|
@ -36,16 +36,16 @@ use llvm::{ContextRef, Linkage, ModuleRef, ValueRef, Vector, get_param};
|
||||
use llvm;
|
||||
use metadata;
|
||||
use rustc::hir::def_id::LOCAL_CRATE;
|
||||
use middle::lang_items::StartFnLangItem;
|
||||
use middle::cstore::EncodedMetadata;
|
||||
use rustc::middle::lang_items::StartFnLangItem;
|
||||
use rustc::middle::cstore::EncodedMetadata;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::dep_graph::AssertDepGraphSafe;
|
||||
use rustc::middle::cstore::LinkMeta;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::util::common::time;
|
||||
use session::config::{self, NoDebugInfo};
|
||||
use rustc::session::config::{self, NoDebugInfo};
|
||||
use rustc::session::{self, DataTypeKind, Session};
|
||||
use rustc_incremental::IncrementalHashesMap;
|
||||
use session::{self, DataTypeKind, Session};
|
||||
use abi;
|
||||
use mir::lvalue::LvalueRef;
|
||||
use attributes;
|
||||
@ -71,7 +71,7 @@ use trans_item::{TransItem, DefPathBasedNames};
|
||||
use type_::Type;
|
||||
use type_of;
|
||||
use value::Value;
|
||||
use util::nodemap::{NodeSet, FxHashMap, FxHashSet};
|
||||
use rustc::util::nodemap::{NodeSet, FxHashMap, FxHashSet};
|
||||
|
||||
use libc::c_uint;
|
||||
use std::ffi::{CStr, CString};
|
||||
|
@ -204,7 +204,7 @@ use rustc::mir::visit::Visitor as MirVisitor;
|
||||
use context::SharedCrateContext;
|
||||
use common::{def_ty, instance_ty};
|
||||
use monomorphize::{self, Instance};
|
||||
use util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
|
||||
use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
|
||||
|
||||
use trans_item::{TransItem, DefPathBasedNames, InstantiationMode};
|
||||
|
||||
|
@ -17,7 +17,7 @@ use llvm::{ValueRef, ContextRef, TypeKind};
|
||||
use llvm::{True, False, Bool, OperandBundleDef};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::map::DefPathData;
|
||||
use middle::lang_items::LangItem;
|
||||
use rustc::middle::lang_items::LangItem;
|
||||
use base;
|
||||
use builder::Builder;
|
||||
use consts;
|
||||
|
@ -26,10 +26,9 @@ use rustc_data_structures::base_n;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::layout::{LayoutTyper, TyLayout};
|
||||
use session::config::NoDebugInfo;
|
||||
use session::Session;
|
||||
use session::config;
|
||||
use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
|
||||
use rustc::session::config::{self, NoDebugInfo};
|
||||
use rustc::session::Session;
|
||||
use rustc::util::nodemap::{NodeSet, DefIdMap, FxHashMap};
|
||||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
@ -16,7 +16,7 @@ use common::{C_bytes, CrateContext, C_i32};
|
||||
use builder::Builder;
|
||||
use declare;
|
||||
use type_::Type;
|
||||
use session::config::NoDebugInfo;
|
||||
use rustc::session::config::NoDebugInfo;
|
||||
|
||||
use std::ptr;
|
||||
use syntax::attr;
|
||||
|
@ -19,7 +19,6 @@ use super::namespace::mangled_name_of_item;
|
||||
use super::type_names::compute_debuginfo_type_name;
|
||||
use super::{CrateDebugContext};
|
||||
use context::SharedCrateContext;
|
||||
use session::Session;
|
||||
|
||||
use llvm::{self, ValueRef};
|
||||
use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor,
|
||||
@ -37,8 +36,8 @@ use common::{self, CrateContext};
|
||||
use type_::Type;
|
||||
use rustc::ty::{self, AdtKind, Ty};
|
||||
use rustc::ty::layout::{self, LayoutTyper};
|
||||
use session::config;
|
||||
use util::nodemap::FxHashMap;
|
||||
use rustc::session::{Session, config};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
|
||||
use libc::{c_uint, c_longlong};
|
||||
use std::ffi::CString;
|
||||
|
@ -32,8 +32,8 @@ use builder::Builder;
|
||||
use monomorphize::Instance;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::mir;
|
||||
use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
|
||||
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
|
||||
use rustc::session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
|
||||
use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
|
||||
|
||||
use libc::c_uint;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
@ -63,11 +63,6 @@ extern crate syntax_pos;
|
||||
extern crate rustc_errors as errors;
|
||||
extern crate serialize;
|
||||
|
||||
pub use rustc::session;
|
||||
pub use rustc::middle;
|
||||
pub use rustc::lint;
|
||||
pub use rustc::util;
|
||||
|
||||
pub use base::trans_crate;
|
||||
pub use back::symbol_names::provide;
|
||||
|
||||
@ -75,20 +70,18 @@ pub use metadata::LlvmMetadataLoader;
|
||||
pub use llvm_util::{init, target_features, print_version, print_passes, print, enable_llvm_debug};
|
||||
|
||||
pub mod back {
|
||||
pub use rustc::hir::svh;
|
||||
|
||||
pub mod archive;
|
||||
pub mod linker;
|
||||
mod archive;
|
||||
pub(crate) mod linker;
|
||||
pub mod link;
|
||||
pub mod lto;
|
||||
pub mod symbol_export;
|
||||
pub mod symbol_names;
|
||||
mod lto;
|
||||
pub(crate) mod symbol_export;
|
||||
pub(crate) mod symbol_names;
|
||||
pub mod write;
|
||||
pub mod msvc;
|
||||
pub mod rpath;
|
||||
mod msvc;
|
||||
mod rpath;
|
||||
}
|
||||
|
||||
pub mod diagnostics;
|
||||
mod diagnostics;
|
||||
|
||||
mod abi;
|
||||
mod adt;
|
||||
@ -171,8 +164,8 @@ pub struct CrateTranslation {
|
||||
pub crate_name: Symbol,
|
||||
pub modules: Vec<ModuleTranslation>,
|
||||
pub metadata_module: ModuleTranslation,
|
||||
pub link: middle::cstore::LinkMeta,
|
||||
pub metadata: middle::cstore::EncodedMetadata,
|
||||
pub link: rustc::middle::cstore::LinkMeta,
|
||||
pub metadata: rustc::middle::cstore::EncodedMetadata,
|
||||
pub exported_symbols: back::symbol_export::ExportedSymbols,
|
||||
pub no_builtins: bool,
|
||||
pub windows_subsystem: Option<String>,
|
||||
|
@ -17,7 +17,7 @@ use rustc::mir::{self, Mir};
|
||||
use rustc::mir::tcx::LvalueTy;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::infer::TransNormalize;
|
||||
use session::config::FullDebugInfo;
|
||||
use rustc::session::config::FullDebugInfo;
|
||||
use base;
|
||||
use builder::Builder;
|
||||
use common::{self, CrateContext, Funclet};
|
||||
|
@ -14,7 +14,7 @@ use rustc::ty::cast::{CastTy, IntTy};
|
||||
use rustc::ty::layout::{Layout, LayoutTyper};
|
||||
use rustc::mir::tcx::LvalueTy;
|
||||
use rustc::mir;
|
||||
use middle::lang_items::ExchangeMallocFnLangItem;
|
||||
use rustc::middle::lang_items::ExchangeMallocFnLangItem;
|
||||
|
||||
use base;
|
||||
use builder::Builder;
|
||||
|
@ -118,7 +118,7 @@ use std::sync::Arc;
|
||||
use syntax::ast::NodeId;
|
||||
use syntax::symbol::{Symbol, InternedString};
|
||||
use trans_item::{TransItem, InstantiationMode};
|
||||
use util::nodemap::{FxHashMap, FxHashSet};
|
||||
use rustc::util::nodemap::{FxHashMap, FxHashSet};
|
||||
|
||||
pub enum PartitioningStrategy {
|
||||
/// Generate one codegen unit per source-level module.
|
||||
|
@ -4078,7 +4078,7 @@ register_diagnostics! {
|
||||
// E0217, // ambiguous associated type, defined in multiple supertraits
|
||||
// E0218, // no associated type defined
|
||||
// E0219, // associated type defined in higher-ranked supertrait
|
||||
// E0222, // Error code E0045 (variadic function must have C calling
|
||||
// E0222, // Error code E0045 (variadic function must have C or cdecl calling
|
||||
// convention) duplicate
|
||||
E0224, // at least one non-builtin train is required for an object type
|
||||
E0227, // ambiguous lifetime bound, explicit lifetime bound required
|
||||
|
@ -141,11 +141,10 @@ fn require_c_abi_if_variadic(tcx: TyCtxt,
|
||||
decl: &hir::FnDecl,
|
||||
abi: Abi,
|
||||
span: Span) {
|
||||
if decl.variadic && abi != Abi::C {
|
||||
if decl.variadic && !(abi == Abi::C || abi == Abi::Cdecl) {
|
||||
let mut err = struct_span_err!(tcx.sess, span, E0045,
|
||||
"variadic function must have C calling convention");
|
||||
err.span_label(span, "variadics require C calling conventions")
|
||||
.emit();
|
||||
"variadic function must have C or cdecl calling convention");
|
||||
err.span_label(span, "variadics require C or cdecl calling convention").emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -664,12 +664,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
|
||||
"rustc_attrs",
|
||||
"internal rustc attributes will never be stable",
|
||||
cfg_fn!(rustc_attrs))),
|
||||
("rustc_move_fragments", Normal, Gated(Stability::Unstable,
|
||||
"rustc_attrs",
|
||||
"the `#[rustc_move_fragments]` attribute \
|
||||
is just used for rustc unit tests \
|
||||
and will never be stable",
|
||||
cfg_fn!(rustc_attrs))),
|
||||
("rustc_mir", Whitelisted, Gated(Stability::Unstable,
|
||||
"rustc_attrs",
|
||||
"the `#[rustc_mir]` attribute \
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
extern "Rust" { fn foo(x: u8, ...); } //~ ERROR E0045
|
||||
//~| NOTE variadics require C calling conventions
|
||||
//~| NOTE variadics require C or cdecl calling convention
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable
|
||||
#[rustc_error] //~ ERROR the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable
|
||||
#[rustc_move_fragments] //~ ERROR the `#[rustc_move_fragments]` attribute is just used for rustc unit tests and will never be stable
|
||||
#[rustc_foo]
|
||||
//~^ ERROR unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics
|
||||
|
||||
|
21
src/test/compile-fail/issue-39974.rs
Normal file
21
src/test/compile-fail/issue-39974.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
const LENGTH: f64 = 2;
|
||||
|
||||
struct Thing {
|
||||
f: [[f64; 2]; LENGTH],
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected usize, found f64
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _t = Thing { f: [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]] };
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that we correctly compute the move fragments for a fn.
|
||||
//
|
||||
// Note that the code below is not actually incorrect; the
|
||||
// `rustc_move_fragments` attribute is a hack that uses the error
|
||||
// reporting mechanisms as a channel for communicating from the
|
||||
// internals of the compiler.
|
||||
|
||||
// These are all fairly trivial cases: unused variables or direct
|
||||
// drops of substructure.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
pub struct D { d: isize }
|
||||
impl Drop for D { fn drop(&mut self) { } }
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_noop() {
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_take(_x: D) {
|
||||
//~^ ERROR assigned_leaf_path: `$(local _x)`
|
||||
}
|
||||
|
||||
pub struct Pair<X,Y> { x: X, y: Y }
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_take_struct(_p: Pair<D, D>) {
|
||||
//~^ ERROR assigned_leaf_path: `$(local _p)`
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_drop_struct_part(p: Pair<D, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR moved_leaf_path: `$(local p).x`
|
||||
//~| ERROR unmoved_fragment: `$(local p).y`
|
||||
drop(p.x);
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_drop_tuple_part(p: (D, D)) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR moved_leaf_path: `$(local p).#0`
|
||||
//~| ERROR unmoved_fragment: `$(local p).#1`
|
||||
drop(p.0);
|
||||
}
|
||||
|
||||
pub fn main() { }
|
@ -1,87 +0,0 @@
|
||||
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that we correctly compute the move fragments for a fn.
|
||||
//
|
||||
// Note that the code below is not actually incorrect; the
|
||||
// `rustc_move_fragments` attribute is a hack that uses the error
|
||||
// reporting mechanisms as a channel for communicating from the
|
||||
// internals of the compiler.
|
||||
|
||||
// These are checking that enums are tracked; note that their output
|
||||
// paths include "downcasts" of the path to a particular enum.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use self::Lonely::{Zero, One, Two};
|
||||
|
||||
pub struct D { d: isize }
|
||||
impl Drop for D { fn drop(&mut self) { } }
|
||||
|
||||
pub enum Lonely<X,Y> { Zero, One(X), Two(X, Y) }
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_match_partial(p: Lonely<D, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR assigned_leaf_path: `($(local p) as Lonely::Zero)`
|
||||
match p {
|
||||
Zero => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_match_full(p: Lonely<D, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR assigned_leaf_path: `($(local p) as Lonely::Zero)`
|
||||
//~| ERROR assigned_leaf_path: `($(local p) as Lonely::One)`
|
||||
//~| ERROR assigned_leaf_path: `($(local p) as Lonely::Two)`
|
||||
match p {
|
||||
Zero => {}
|
||||
One(..) => {}
|
||||
Two(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_match_bind_one(p: Lonely<D, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR assigned_leaf_path: `($(local p) as Lonely::Zero)`
|
||||
//~| ERROR parent_of_fragments: `($(local p) as Lonely::One)`
|
||||
//~| ERROR moved_leaf_path: `($(local p) as Lonely::One).#0`
|
||||
//~| ERROR assigned_leaf_path: `($(local p) as Lonely::Two)`
|
||||
//~| ERROR assigned_leaf_path: `$(local data)`
|
||||
match p {
|
||||
Zero => {}
|
||||
One(data) => {}
|
||||
Two(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_match_bind_many(p: Lonely<D, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR assigned_leaf_path: `($(local p) as Lonely::Zero)`
|
||||
//~| ERROR parent_of_fragments: `($(local p) as Lonely::One)`
|
||||
//~| ERROR moved_leaf_path: `($(local p) as Lonely::One).#0`
|
||||
//~| ERROR assigned_leaf_path: `$(local data)`
|
||||
//~| ERROR parent_of_fragments: `($(local p) as Lonely::Two)`
|
||||
//~| ERROR moved_leaf_path: `($(local p) as Lonely::Two).#0`
|
||||
//~| ERROR moved_leaf_path: `($(local p) as Lonely::Two).#1`
|
||||
//~| ERROR assigned_leaf_path: `$(local left)`
|
||||
//~| ERROR assigned_leaf_path: `$(local right)`
|
||||
match p {
|
||||
Zero => {}
|
||||
One(data) => {}
|
||||
Two(left, right) => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() { }
|
@ -1,49 +0,0 @@
|
||||
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that we correctly compute the move fragments for a fn.
|
||||
//
|
||||
// Note that the code below is not actually incorrect; the
|
||||
// `rustc_move_fragments` attribute is a hack that uses the error
|
||||
// reporting mechanisms as a channel for communicating from the
|
||||
// internals of the compiler.
|
||||
|
||||
// This checks the handling of `_` within variants, especially when mixed
|
||||
// with bindings.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use self::Lonely::{Zero, One, Two};
|
||||
|
||||
pub struct D { d: isize }
|
||||
impl Drop for D { fn drop(&mut self) { } }
|
||||
|
||||
pub enum Lonely<X,Y> { Zero, One(X), Two(X, Y) }
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_match_bind_and_underscore(p: Lonely<D, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR assigned_leaf_path: `($(local p) as Lonely::Zero)`
|
||||
//~| ERROR assigned_leaf_path: `($(local p) as Lonely::One)`
|
||||
//~| ERROR parent_of_fragments: `($(local p) as Lonely::Two)`
|
||||
//~| ERROR moved_leaf_path: `($(local p) as Lonely::Two).#0`
|
||||
//~| ERROR unmoved_fragment: `($(local p) as Lonely::Two).#1`
|
||||
//~| ERROR assigned_leaf_path: `$(local left)`
|
||||
|
||||
match p {
|
||||
Zero => {}
|
||||
|
||||
One(_) => {} // <-- does not fragment `($(local p) as One)` ...
|
||||
|
||||
Two(left, _) => {} // <-- ... *does* fragment `($(local p) as Two)`.
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() { }
|
@ -1,41 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that we correctly compute the move fragments for a fn.
|
||||
//
|
||||
// Note that the code below is not actually incorrect; the
|
||||
// `rustc_move_fragments` attribute is a hack that uses the error
|
||||
// reporting mechanisms as a channel for communicating from the
|
||||
// internals of the compiler.
|
||||
|
||||
// This checks that a move of deep structure is properly tracked. (An
|
||||
// early draft of the code did not properly traverse up through all of
|
||||
// the parents of the leaf fragment.)
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
pub struct D { d: isize }
|
||||
impl Drop for D { fn drop(&mut self) { } }
|
||||
|
||||
pub struct Pair<X,Y> { x: X, y: Y }
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_move_substructure(pppp: Pair<Pair<Pair<Pair<D,D>, D>, D>, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local pppp)`
|
||||
//~| ERROR parent_of_fragments: `$(local pppp).x`
|
||||
//~| ERROR parent_of_fragments: `$(local pppp).x.x`
|
||||
//~| ERROR unmoved_fragment: `$(local pppp).x.x.x`
|
||||
//~| ERROR moved_leaf_path: `$(local pppp).x.x.y`
|
||||
//~| ERROR unmoved_fragment: `$(local pppp).x.y`
|
||||
//~| ERROR unmoved_fragment: `$(local pppp).y`
|
||||
drop(pppp.x.x.y);
|
||||
}
|
||||
|
||||
pub fn main() { }
|
@ -1,94 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that we correctly compute the move fragments for a fn.
|
||||
//
|
||||
// Note that the code below is not actually incorrect; the
|
||||
// `rustc_move_fragments` attribute is a hack that uses the error
|
||||
// reporting mechanisms as a channel for communicating from the
|
||||
// internals of the compiler.
|
||||
|
||||
// This is the first test that checks moving into local variables.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
pub struct D { d: isize }
|
||||
impl Drop for D { fn drop(&mut self) { } }
|
||||
|
||||
pub struct Pair<X,Y> { x: X, y: Y }
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_move_field_to_local(p: Pair<D, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR moved_leaf_path: `$(local p).x`
|
||||
//~| ERROR unmoved_fragment: `$(local p).y`
|
||||
//~| ERROR assigned_leaf_path: `$(local _x)`
|
||||
let _x = p.x;
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_move_field_to_local_to_local(p: Pair<D, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR moved_leaf_path: `$(local p).x`
|
||||
//~| ERROR unmoved_fragment: `$(local p).y`
|
||||
//~| ERROR assigned_leaf_path: `$(local _x)`
|
||||
//~| ERROR moved_leaf_path: `$(local _x)`
|
||||
//~| ERROR assigned_leaf_path: `$(local _y)`
|
||||
let _x = p.x;
|
||||
let _y = _x;
|
||||
}
|
||||
|
||||
// In the following fn's `test_move_field_to_local_delayed` and
|
||||
// `test_uninitialized_local` , the instrumentation reports that `_x`
|
||||
// is moved. This is unlike `test_move_field_to_local`, where `_x` is
|
||||
// just reported as an assigned_leaf_path. Presumably because this is
|
||||
// how we represent that it did not have an initializing expression at
|
||||
// the binding site.
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_uninitialized_local(_p: Pair<D, D>) {
|
||||
//~^ ERROR assigned_leaf_path: `$(local _p)`
|
||||
//~| ERROR moved_leaf_path: `$(local _x)`
|
||||
let _x: D;
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_move_field_to_local_delayed(p: Pair<D, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR moved_leaf_path: `$(local p).x`
|
||||
//~| ERROR unmoved_fragment: `$(local p).y`
|
||||
//~| ERROR assigned_leaf_path: `$(local _x)`
|
||||
//~| ERROR moved_leaf_path: `$(local _x)`
|
||||
let _x;
|
||||
_x = p.x;
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_move_field_mut_to_local(mut p: Pair<D, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local mut p)`
|
||||
//~| ERROR moved_leaf_path: `$(local mut p).x`
|
||||
//~| ERROR unmoved_fragment: `$(local mut p).y`
|
||||
//~| ERROR assigned_leaf_path: `$(local _x)`
|
||||
let _x = p.x;
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_move_field_to_local_to_local_mut(p: Pair<D, D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR moved_leaf_path: `$(local p).x`
|
||||
//~| ERROR unmoved_fragment: `$(local p).y`
|
||||
//~| ERROR assigned_leaf_path: `$(local mut _x)`
|
||||
//~| ERROR moved_leaf_path: `$(local mut _x)`
|
||||
//~| ERROR assigned_leaf_path: `$(local _y)`
|
||||
let mut _x = p.x;
|
||||
let _y = _x;
|
||||
}
|
||||
|
||||
pub fn main() {}
|
@ -1,61 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that we correctly compute the move fragments for a fn.
|
||||
//
|
||||
// Note that the code below is not actually incorrect; the
|
||||
// `rustc_move_fragments` attribute is a hack that uses the error
|
||||
// reporting mechanisms as a channel for communicating from the
|
||||
// internals of the compiler.
|
||||
|
||||
// Test that moving into a field (i.e. overwriting it) fragments the
|
||||
// receiver.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::mem::drop;
|
||||
|
||||
pub struct Pair<X,Y> { x: X, y: Y }
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_overwrite_uninit_field<Z>(z: Z) {
|
||||
//~^ ERROR parent_of_fragments: `$(local mut p)`
|
||||
//~| ERROR assigned_leaf_path: `$(local z)`
|
||||
//~| ERROR moved_leaf_path: `$(local z)`
|
||||
//~| ERROR assigned_leaf_path: `$(local mut p).x`
|
||||
//~| ERROR unmoved_fragment: `$(local mut p).y`
|
||||
|
||||
let mut p: Pair<Z,Z>;
|
||||
p.x = z;
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_overwrite_moved_field<Z>(mut p: Pair<Z,Z>, z: Z) {
|
||||
//~^ ERROR parent_of_fragments: `$(local mut p)`
|
||||
//~| ERROR assigned_leaf_path: `$(local z)`
|
||||
//~| ERROR moved_leaf_path: `$(local z)`
|
||||
//~| ERROR assigned_leaf_path: `$(local mut p).y`
|
||||
//~| ERROR unmoved_fragment: `$(local mut p).x`
|
||||
|
||||
drop(p);
|
||||
p.y = z;
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_overwrite_same_field<Z>(mut p: Pair<Z,Z>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local mut p)`
|
||||
//~| ERROR moved_leaf_path: `$(local mut p).x`
|
||||
//~| ERROR assigned_leaf_path: `$(local mut p).x`
|
||||
//~| ERROR unmoved_fragment: `$(local mut p).y`
|
||||
|
||||
p.x = p.x;
|
||||
}
|
||||
|
||||
pub fn main() { }
|
@ -1,48 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that we correctly compute the move fragments for a fn.
|
||||
//
|
||||
// Note that the code below is not actually incorrect; the
|
||||
// `rustc_move_fragments` attribute is a hack that uses the error
|
||||
// reporting mechanisms as a channel for communicating from the
|
||||
// internals of the compiler.
|
||||
|
||||
// Test that moving a Box<T> fragments its containing structure, for
|
||||
// both moving out of the structure (i.e. reading `*p.x`) and writing
|
||||
// into the container (i.e. writing `*p.x`).
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
pub struct D { d: isize }
|
||||
impl Drop for D { fn drop(&mut self) { } }
|
||||
|
||||
pub struct Pair<X,Y> { x: X, y: Y }
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_deref_box_field(p: Pair<Box<D>, Box<D>>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR parent_of_fragments: `$(local p).x`
|
||||
//~| ERROR moved_leaf_path: `$(local p).x.*`
|
||||
//~| ERROR unmoved_fragment: `$(local p).y`
|
||||
//~| ERROR assigned_leaf_path: `$(local i)`
|
||||
let i : D = *p.x;
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_overwrite_deref_box_field(mut p: Pair<Box<D>, Box<D>>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local mut p)`
|
||||
//~| ERROR parent_of_fragments: `$(local mut p).x`
|
||||
//~| ERROR assigned_leaf_path: `$(local mut p).x.*`
|
||||
//~| ERROR unmoved_fragment: `$(local mut p).y`
|
||||
*p.x = D { d: 3 };
|
||||
}
|
||||
|
||||
pub fn main() { }
|
@ -1,41 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that we correctly compute the move fragments for a fn.
|
||||
//
|
||||
// Note that the code below is not actually incorrect; the
|
||||
// `rustc_move_fragments` attribute is a hack that uses the error
|
||||
// reporting mechanisms as a channel for communicating from the
|
||||
// internals of the compiler.
|
||||
|
||||
// Test that assigning into a `&T` within structured container does
|
||||
// *not* fragment its containing structure.
|
||||
//
|
||||
// Compare against the `Box<T>` handling in move-fragments-7.rs. Note
|
||||
// also that in this case we cannot do a move out of `&T`, so we only
|
||||
// test writing `*p.x` here.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
pub struct D { d: isize }
|
||||
impl Drop for D { fn drop(&mut self) { } }
|
||||
|
||||
pub struct Pair<X,Y> { x: X, y: Y }
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_overwrite_deref_ampersand_field<'a>(p: Pair<&'a mut D, &'a D>) {
|
||||
//~^ ERROR parent_of_fragments: `$(local p)`
|
||||
//~| ERROR parent_of_fragments: `$(local p).x`
|
||||
//~| ERROR assigned_leaf_path: `$(local p).x.*`
|
||||
//~| ERROR unmoved_fragment: `$(local p).y`
|
||||
*p.x = D { d: 3 };
|
||||
}
|
||||
|
||||
pub fn main() { }
|
@ -1,49 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test moving array structures, e.g. `[T; 3]` as well as moving
|
||||
// elements in and out of such arrays.
|
||||
//
|
||||
// Note also that the `test_move_array_then_overwrite` tests represent
|
||||
// cases that we probably should make illegal.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
pub struct D { d: isize }
|
||||
impl Drop for D { fn drop(&mut self) { } }
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_move_array_via_return(a: [D; 3]) -> [D; 3] {
|
||||
//~^ ERROR assigned_leaf_path: `$(local a)`
|
||||
//~| ERROR moved_leaf_path: `$(local a)`
|
||||
return a;
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_move_array_into_recv(a: [D; 3], recv: &mut [D; 3]) {
|
||||
//~^ ERROR parent_of_fragments: `$(local recv)`
|
||||
//~| ERROR assigned_leaf_path: `$(local a)`
|
||||
//~| ERROR moved_leaf_path: `$(local a)`
|
||||
//~| ERROR assigned_leaf_path: `$(local recv).*`
|
||||
*recv = a;
|
||||
}
|
||||
|
||||
#[rustc_move_fragments]
|
||||
pub fn test_overwrite_array_elem(mut a: [D; 3], i: usize, d: D) {
|
||||
//~^ ERROR parent_of_fragments: `$(local mut a)`
|
||||
//~| ERROR assigned_leaf_path: `$(local i)`
|
||||
//~| ERROR assigned_leaf_path: `$(local d)`
|
||||
//~| ERROR moved_leaf_path: `$(local d)`
|
||||
//~| ERROR assigned_leaf_path: `$(local mut a).[]`
|
||||
//~| ERROR unmoved_fragment: `$(allbutone $(local mut a).[])`
|
||||
a[i] = d;
|
||||
}
|
||||
|
||||
pub fn main() { }
|
@ -8,8 +8,10 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn baz(f: extern "cdecl" fn(usize, ...)) {
|
||||
//~^ ERROR: variadic function must have C calling convention
|
||||
// ignore-arm stdcall isn't suppported
|
||||
|
||||
fn baz(f: extern "stdcall" fn(usize, ...)) {
|
||||
//~^ ERROR: variadic function must have C or cdecl calling convention
|
||||
f(22, 44);
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,10 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern "cdecl" {
|
||||
fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C calling convention
|
||||
// ignore-arm stdcall isn't suppported
|
||||
|
||||
extern "stdcall" {
|
||||
fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C or cdecl calling
|
||||
}
|
||||
|
||||
extern {
|
||||
|
29
src/test/run-pass/issue-42210.rs
Normal file
29
src/test/run-pass/issue-42210.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Regression test for #42210.
|
||||
|
||||
// compile-flags: -g
|
||||
|
||||
trait Foo {
|
||||
fn foo() { }
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
trait Baz {
|
||||
}
|
||||
|
||||
impl Foo for (Bar, Baz) { }
|
||||
|
||||
|
||||
fn main() {
|
||||
<(Bar, Baz) as Foo>::foo()
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user