Auto merge of - jonathandturner:rollup, r=jonathandturner

Rollup of 15 pull requests

- Successful merges: , , , , , , , , , , , , , , 
- Failed merges:
This commit is contained in:
bors 2016-10-06 11:42:34 -07:00 committed by GitHub
commit ad19c32a58
31 changed files with 925 additions and 267 deletions
src
bootstrap
doc/book
libcollections
libcore/hash
librustc_const_eval
librustc_incremental/calculate_svh
librustc_mir/transform
librustc_trans
librustc_typeck/variance
librustdoc/clean
libstd
io
sys/common
test

@ -90,16 +90,16 @@ pub fn std_link(build: &Build,
add_to_sysroot(&out_dir, &libdir);
if target.contains("musl") && !target.contains("mips") {
copy_musl_third_party_objects(build, &libdir);
copy_musl_third_party_objects(build, target, &libdir);
}
}
/// Copies the crt(1,i,n).o startup objects
///
/// Only required for musl targets that statically link to libc
fn copy_musl_third_party_objects(build: &Build, into: &Path) {
fn copy_musl_third_party_objects(build: &Build, target: &str, into: &Path) {
for &obj in &["crt1.o", "crti.o", "crtn.o"] {
copy(&build.config.musl_root.as_ref().unwrap().join("lib").join(obj), &into.join(obj));
copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
}
}

@ -158,6 +158,7 @@ struct TomlTarget {
cc: Option<String>,
cxx: Option<String>,
android_ndk: Option<String>,
musl_root: Option<String>,
}
impl Config {
@ -268,6 +269,7 @@ impl Config {
}
target.cxx = cfg.cxx.clone().map(PathBuf::from);
target.cc = cfg.cc.clone().map(PathBuf::from);
target.musl_root = cfg.musl_root.clone().map(PathBuf::from);
config.target_config.insert(triple.clone(), target);
}

@ -146,8 +146,8 @@ pub fn check(build: &mut Build) {
}
}
None => {
panic!("when targeting MUSL either the build.musl-root \
option or the target.$TARGET.musl-root one must \
panic!("when targeting MUSL either the rust.musl-root \
option or the target.$TARGET.musl-root option must \
be specified in config.toml")
}
}

@ -4,7 +4,7 @@ Concurrency and parallelism are incredibly important topics in computer
science, and are also a hot topic in industry today. Computers are gaining more
and more cores, yet many programmers aren't prepared to fully utilize them.
Rust's memory safety features also apply to its concurrency story too. Even
Rust's memory safety features also apply to its concurrency story. Even
concurrent Rust programs must be memory safe, having no data races. Rust's type
system is up to the task, and gives you powerful ways to reason about
concurrent code at compile time.
@ -281,8 +281,8 @@ And... still gives us an error.
```
`Arc<T>` by default has immutable contents. It allows the _sharing_ of data
between threads, but shared mutable data is unsafe and when threads are
involved can cause data races!
between threads, but shared mutable data is unsafeand when threads are
involvedcan cause data races!
Usually when we wish to make something in an immutable position mutable, we use

@ -1053,10 +1053,10 @@ impl str {
}
/// An iterator over substrings of the given string slice, separated by a
/// pattern, restricted to returning at most `count` items.
/// pattern, restricted to returning at most `n` items.
///
/// The last element returned, if any, will contain the remainder of the
/// string slice.
/// If `n` substrings are returned, the last substring (the `n`th substring)
/// will contain the remainder of the string.
///
/// The pattern can be a `&str`, [`char`], or a closure that determines the
/// split.
@ -1098,16 +1098,16 @@ impl str {
/// assert_eq!(v, ["abc", "defXghi"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
core_str::StrExt::splitn(self, count, pat)
pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
core_str::StrExt::splitn(self, n, pat)
}
/// An iterator over substrings of this string slice, separated by a
/// pattern, starting from the end of the string, restricted to returning
/// at most `count` items.
/// at most `n` items.
///
/// The last element returned, if any, will contain the remainder of the
/// string slice.
/// If `n` substrings are returned, the last substring (the `n`th substring)
/// will contain the remainder of the string.
///
/// The pattern can be a `&str`, [`char`], or a closure that
/// determines the split.
@ -1145,10 +1145,10 @@ impl str {
/// assert_eq!(v, ["ghi", "abc1def"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
where P::Searcher: ReverseSearcher<'a>
{
core_str::StrExt::rsplitn(self, count, pat)
core_str::StrExt::rsplitn(self, n, pat)
}
/// An iterator over the matches of a pattern within the given string

@ -17,6 +17,9 @@ use ptr;
/// An implementation of SipHash 1-3.
///
/// This is currently the default hashing function used by standard library
/// (eg. `collections::HashMap` uses it by default).
///
/// See: https://131002.net/siphash/
#[unstable(feature = "sip_hash_13", issue = "34767")]
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
@ -39,9 +42,6 @@ pub struct SipHasher24 {
///
/// See: https://131002.net/siphash/
///
/// This is currently the default hashing function used by standard library
/// (eg. `collections::HashMap` uses it by default).
///
/// SipHash is a general-purpose hashing function: it runs at a good
/// speed (competitive with Spooky and City) and permits strong _keyed_
/// hashing. This lets you key your hashtables from a strong RNG, such as
@ -117,23 +117,18 @@ unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
data.to_le()
}
macro_rules! rotl {
($x:expr, $b:expr) =>
(($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
}
macro_rules! compress {
($state:expr) => ({
compress!($state.v0, $state.v1, $state.v2, $state.v3)
});
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
({
$v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
$v0 = rotl!($v0, 32);
$v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
$v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
$v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
$v2 = rotl!($v2, 32);
$v0 = $v0.wrapping_add($v1); $v1 = $v1.rotate_left(13); $v1 ^= $v0;
$v0 = $v0.rotate_left(32);
$v2 = $v2.wrapping_add($v3); $v3 = $v3.rotate_left(16); $v3 ^= $v2;
$v0 = $v0.wrapping_add($v3); $v3 = $v3.rotate_left(21); $v3 ^= $v0;
$v2 = $v2.wrapping_add($v1); $v1 = $v1.rotate_left(17); $v1 ^= $v2;
$v2 = $v2.rotate_left(32);
});
}

@ -25,8 +25,10 @@ use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization::{cmt};
use rustc::hir::pat_util::*;
use rustc::session::Session;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt};
use rustc_errors::DiagnosticBuilder;
use std::cmp::Ordering;
use std::fmt;
use std::iter::{FromIterator, IntoIterator, repeat};
@ -163,6 +165,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
tcx.sess.abort_if_errors();
}
fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> DiagnosticBuilder<'a> {
struct_span_err!(sess, sp, E0004, "{}", &error_message)
}
fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
intravisit::walk_expr(cx, ex);
match ex.node {
@ -215,9 +221,10 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
if inlined_arms.is_empty() {
if !pat_ty.is_uninhabited(cx.tcx) {
// We know the type is inhabited, so this must be wrong
let mut err = struct_span_err!(cx.tcx.sess, ex.span, E0002,
"non-exhaustive patterns: type {} is non-empty",
pat_ty);
let mut err = create_e0004(cx.tcx.sess, ex.span,
format!("non-exhaustive patterns: type {} \
is non-empty",
pat_ty));
span_help!(&mut err, ex.span,
"Please ensure that all possible cases are being handled; \
possibly adding wildcards or more match arms.");
@ -438,10 +445,11 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
1 => format!("pattern {} not covered", joined_patterns),
_ => format!("patterns {} not covered", joined_patterns)
};
struct_span_err!(cx.tcx.sess, sp, E0004,
"non-exhaustive patterns: {} not covered",
joined_patterns
).span_label(sp, &label_text).emit();
create_e0004(cx.tcx.sess, sp,
format!("non-exhaustive patterns: {} not covered",
joined_patterns))
.span_label(sp, &label_text)
.emit();
},
}
}

@ -15,6 +15,11 @@
use self::SawExprComponent::*;
use self::SawAbiComponent::*;
use self::SawItemComponent::*;
use self::SawPatComponent::*;
use self::SawTyComponent::*;
use self::SawTraitOrImplItemComponent::*;
use syntax::abi::Abi;
use syntax::ast::{self, Name, NodeId};
use syntax::parse::token;
use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
@ -155,11 +160,11 @@ enum SawAbiComponent<'a> {
SawMod,
SawForeignItem,
SawItem,
SawTy,
SawItem(SawItemComponent),
SawTy(SawTyComponent),
SawGenerics,
SawTraitItem,
SawImplItem,
SawTraitItem(SawTraitOrImplItemComponent),
SawImplItem(SawTraitOrImplItemComponent),
SawStructField,
SawVariant,
SawPath(bool),
@ -167,7 +172,7 @@ enum SawAbiComponent<'a> {
SawPathParameters,
SawPathListItem,
SawBlock,
SawPat,
SawPat(SawPatComponent),
SawLocal,
SawArm,
SawExpr(SawExprComponent<'a>),
@ -198,6 +203,9 @@ enum SawAbiComponent<'a> {
/// because the SVH is just a developer convenience; there is no
/// guarantee of collision-freedom, hash collisions are just
/// (hopefully) unlikely.)
///
/// The xxxComponent enums and saw_xxx functions for Item, Pat,
/// Ty, TraitItem and ImplItem follow the same methodology.
#[derive(Hash)]
enum SawExprComponent<'a> {
@ -267,6 +275,134 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
}
}
#[derive(Hash)]
enum SawItemComponent {
SawItemExternCrate,
SawItemUse,
SawItemStatic(Mutability),
SawItemConst,
SawItemFn(Unsafety, Constness, Abi),
SawItemMod,
SawItemForeignMod,
SawItemTy,
SawItemEnum,
SawItemStruct,
SawItemUnion,
SawItemTrait(Unsafety),
SawItemDefaultImpl(Unsafety),
SawItemImpl(Unsafety, ImplPolarity)
}
fn saw_item(node: &Item_) -> SawItemComponent {
match *node {
ItemExternCrate(..) => SawItemExternCrate,
ItemUse(..) => SawItemUse,
ItemStatic(_, mutability, _) => SawItemStatic(mutability),
ItemConst(..) =>SawItemConst,
ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi),
ItemMod(..) => SawItemMod,
ItemForeignMod(..) => SawItemForeignMod,
ItemTy(..) => SawItemTy,
ItemEnum(..) => SawItemEnum,
ItemStruct(..) => SawItemStruct,
ItemUnion(..) => SawItemUnion,
ItemTrait(unsafety, ..) => SawItemTrait(unsafety),
ItemDefaultImpl(unsafety, _) => SawItemDefaultImpl(unsafety),
ItemImpl(unsafety, implpolarity, ..) => SawItemImpl(unsafety, implpolarity)
}
}
#[derive(Hash)]
enum SawPatComponent {
SawPatWild,
SawPatBinding(BindingMode),
SawPatStruct,
SawPatTupleStruct,
SawPatPath,
SawPatTuple,
SawPatBox,
SawPatRef(Mutability),
SawPatLit,
SawPatRange,
SawPatSlice
}
fn saw_pat(node: &PatKind) -> SawPatComponent {
match *node {
PatKind::Wild => SawPatWild,
PatKind::Binding(bindingmode, ..) => SawPatBinding(bindingmode),
PatKind::Struct(..) => SawPatStruct,
PatKind::TupleStruct(..) => SawPatTupleStruct,
PatKind::Path(..) => SawPatPath,
PatKind::Tuple(..) => SawPatTuple,
PatKind::Box(..) => SawPatBox,
PatKind::Ref(_, mutability) => SawPatRef(mutability),
PatKind::Lit(..) => SawPatLit,
PatKind::Range(..) => SawPatRange,
PatKind::Slice(..) => SawPatSlice
}
}
#[derive(Hash)]
enum SawTyComponent {
SawTySlice,
SawTyArray,
SawTyPtr(Mutability),
SawTyRptr(Mutability),
SawTyBareFn(Unsafety, Abi),
SawTyNever,
SawTyTup,
SawTyPath,
SawTyObjectSum,
SawTyPolyTraitRef,
SawTyImplTrait,
SawTyTypeof,
SawTyInfer
}
fn saw_ty(node: &Ty_) -> SawTyComponent {
match *node {
TySlice(..) => SawTySlice,
TyArray(..) => SawTyArray,
TyPtr(ref mty) => SawTyPtr(mty.mutbl),
TyRptr(_, ref mty) => SawTyRptr(mty.mutbl),
TyBareFn(ref barefnty) => SawTyBareFn(barefnty.unsafety, barefnty.abi),
TyNever => SawTyNever,
TyTup(..) => SawTyTup,
TyPath(..) => SawTyPath,
TyObjectSum(..) => SawTyObjectSum,
TyPolyTraitRef(..) => SawTyPolyTraitRef,
TyImplTrait(..) => SawTyImplTrait,
TyTypeof(..) => SawTyTypeof,
TyInfer => SawTyInfer
}
}
#[derive(Hash)]
enum SawTraitOrImplItemComponent {
SawTraitOrImplItemConst,
SawTraitOrImplItemMethod(Unsafety, Constness, Abi),
SawTraitOrImplItemType
}
fn saw_trait_item(ti: &TraitItem_) -> SawTraitOrImplItemComponent {
match *ti {
ConstTraitItem(..) => SawTraitOrImplItemConst,
MethodTraitItem(ref sig, _) =>
SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi),
TypeTraitItem(..) => SawTraitOrImplItemType
}
}
fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent {
match *ii {
ImplItemKind::Const(..) => SawTraitOrImplItemConst,
ImplItemKind::Method(ref sig, _) =>
SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi),
ImplItemKind::Type(..) => SawTraitOrImplItemType
}
}
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
enum SawSpanExpnKind {
NoExpansion,
@ -383,10 +519,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
fn visit_item(&mut self, i: &'tcx Item) {
debug!("visit_item: {:?} st={:?}", i, self.st);
SawItem.hash(self.st);
// Hash the value of the discriminant of the Item variant.
self.hash_discriminant(&i.node);
SawItem(saw_item(&i.node)).hash(self.st);
hash_span!(self, i.span);
hash_attrs!(self, &i.attrs);
visit::walk_item(self, i)
@ -399,7 +532,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
fn visit_ty(&mut self, t: &'tcx Ty) {
debug!("visit_ty: st={:?}", self.st);
SawTy.hash(self.st);
SawTy(saw_ty(&t.node)).hash(self.st);
hash_span!(self, t.span);
visit::walk_ty(self, t)
}
@ -412,8 +545,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
fn visit_trait_item(&mut self, ti: &'tcx TraitItem) {
debug!("visit_trait_item: st={:?}", self.st);
SawTraitItem.hash(self.st);
self.hash_discriminant(&ti.node);
SawTraitItem(saw_trait_item(&ti.node)).hash(self.st);
hash_span!(self, ti.span);
hash_attrs!(self, &ti.attrs);
visit::walk_trait_item(self, ti)
@ -421,8 +553,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
fn visit_impl_item(&mut self, ii: &'tcx ImplItem) {
debug!("visit_impl_item: st={:?}", self.st);
SawImplItem.hash(self.st);
self.hash_discriminant(&ii.node);
SawImplItem(saw_impl_item(&ii.node)).hash(self.st);
hash_span!(self, ii.span);
hash_attrs!(self, &ii.attrs);
visit::walk_impl_item(self, ii)
@ -452,8 +583,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
fn visit_pat(&mut self, p: &'tcx Pat) {
debug!("visit_pat: st={:?}", self.st);
SawPat.hash(self.st);
self.hash_discriminant(&p.node);
SawPat(saw_pat(&p.node)).hash(self.st);
hash_span!(self, p.span);
visit::walk_pat(self, p)
}

@ -50,6 +50,7 @@ impl<'a> SimplifyCfg<'a> {
impl<'l, 'tcx> MirPass<'tcx> for SimplifyCfg<'l> {
fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) {
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, mir);
CfgSimplifier::new(mir).simplify();
remove_dead_blocks(mir);
@ -78,6 +79,8 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
// we can't use mir.predecessors() here because that counts
// dead blocks, which we don't want to.
pred_count[START_BLOCK] = 1;
for (_, data) in traversal::preorder(mir) {
if let Some(ref term) = data.terminator {
for &tgt in term.successors().iter() {
@ -157,8 +160,16 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
debug!("collapsing goto chain from {:?} to {:?}", *start, target);
*changed |= *start != target;
self.pred_count[target] += 1;
self.pred_count[*start] -= 1;
if self.pred_count[*start] == 1 {
// This is the last reference to *start, so the pred-count to
// to target is moved into the current block.
self.pred_count[*start] = 0;
} else {
self.pred_count[target] += 1;
self.pred_count[*start] -= 1;
}
*start = target;
}

@ -183,6 +183,14 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
StructGEP(bcx, fat_ptr, abi::FAT_PTR_ADDR)
}
pub fn get_meta_builder(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
b.struct_gep(fat_ptr, abi::FAT_PTR_EXTRA)
}
pub fn get_dataptr_builder(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
b.struct_gep(fat_ptr, abi::FAT_PTR_ADDR)
}
fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, info_ty: Ty<'tcx>, it: LangItem) -> DefId {
match bcx.tcx().lang_items.require(it) {
Ok(id) => id,
@ -247,124 +255,6 @@ pub fn bin_op_to_fcmp_predicate(op: hir::BinOp_) -> llvm::RealPredicate {
}
}
pub fn compare_fat_ptrs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
lhs_addr: ValueRef,
lhs_extra: ValueRef,
rhs_addr: ValueRef,
rhs_extra: ValueRef,
_t: Ty<'tcx>,
op: hir::BinOp_,
debug_loc: DebugLoc)
-> ValueRef {
match op {
hir::BiEq => {
let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc);
let extra_eq = ICmp(bcx, llvm::IntEQ, lhs_extra, rhs_extra, debug_loc);
And(bcx, addr_eq, extra_eq, debug_loc)
}
hir::BiNe => {
let addr_eq = ICmp(bcx, llvm::IntNE, lhs_addr, rhs_addr, debug_loc);
let extra_eq = ICmp(bcx, llvm::IntNE, lhs_extra, rhs_extra, debug_loc);
Or(bcx, addr_eq, extra_eq, debug_loc)
}
hir::BiLe | hir::BiLt | hir::BiGe | hir::BiGt => {
// a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1)
let (op, strict_op) = match op {
hir::BiLt => (llvm::IntULT, llvm::IntULT),
hir::BiLe => (llvm::IntULE, llvm::IntULT),
hir::BiGt => (llvm::IntUGT, llvm::IntUGT),
hir::BiGe => (llvm::IntUGE, llvm::IntUGT),
_ => bug!(),
};
let addr_eq = ICmp(bcx, llvm::IntEQ, lhs_addr, rhs_addr, debug_loc);
let extra_op = ICmp(bcx, op, lhs_extra, rhs_extra, debug_loc);
let addr_eq_extra_op = And(bcx, addr_eq, extra_op, debug_loc);
let addr_strict = ICmp(bcx, strict_op, lhs_addr, rhs_addr, debug_loc);
Or(bcx, addr_strict, addr_eq_extra_op, debug_loc)
}
_ => {
bug!("unexpected fat ptr binop");
}
}
}
pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
lhs: ValueRef,
rhs: ValueRef,
t: Ty<'tcx>,
op: hir::BinOp_,
debug_loc: DebugLoc)
-> ValueRef {
match t.sty {
ty::TyTuple(ref tys) if tys.is_empty() => {
// We don't need to do actual comparisons for nil.
// () == () holds but () < () does not.
match op {
hir::BiEq | hir::BiLe | hir::BiGe => return C_bool(bcx.ccx(), true),
hir::BiNe | hir::BiLt | hir::BiGt => return C_bool(bcx.ccx(), false),
// refinements would be nice
_ => bug!("compare_scalar_types: must be a comparison operator"),
}
}
ty::TyBool => {
// FIXME(#36856) -- using `from_immediate` forces these booleans into `i8`,
// which works around some LLVM bugs
ICmp(bcx,
bin_op_to_icmp_predicate(op, false),
from_immediate(bcx, lhs),
from_immediate(bcx, rhs),
debug_loc)
}
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyUint(_) | ty::TyChar => {
ICmp(bcx,
bin_op_to_icmp_predicate(op, false),
lhs,
rhs,
debug_loc)
}
ty::TyRawPtr(mt) if common::type_is_sized(bcx.tcx(), mt.ty) => {
ICmp(bcx,
bin_op_to_icmp_predicate(op, false),
lhs,
rhs,
debug_loc)
}
ty::TyRawPtr(_) => {
let lhs_addr = Load(bcx, GEPi(bcx, lhs, &[0, abi::FAT_PTR_ADDR]));
let lhs_extra = Load(bcx, GEPi(bcx, lhs, &[0, abi::FAT_PTR_EXTRA]));
let rhs_addr = Load(bcx, GEPi(bcx, rhs, &[0, abi::FAT_PTR_ADDR]));
let rhs_extra = Load(bcx, GEPi(bcx, rhs, &[0, abi::FAT_PTR_EXTRA]));
compare_fat_ptrs(bcx,
lhs_addr,
lhs_extra,
rhs_addr,
rhs_extra,
t,
op,
debug_loc)
}
ty::TyInt(_) => {
ICmp(bcx,
bin_op_to_icmp_predicate(op, true),
lhs,
rhs,
debug_loc)
}
ty::TyFloat(_) => {
FCmp(bcx,
bin_op_to_fcmp_predicate(op),
lhs,
rhs,
debug_loc)
}
// Should never get here, because t is scalar.
_ => bug!("non-scalar type passed to compare_scalar_types"),
}
}
pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
lhs: ValueRef,
rhs: ValueRef,
@ -632,6 +522,11 @@ pub fn need_invoke(bcx: Block) -> bool {
}
}
pub fn call_assume<'a, 'tcx>(b: &Builder<'a, 'tcx>, val: ValueRef) {
let assume_intrinsic = b.ccx.get_intrinsic("llvm.assume");
b.call(assume_intrinsic, &[val], None);
}
/// Helper for loading values from memory. Does the necessary conversion if the in-memory type
/// differs from the type used for SSA values. Also handles various special cases where the type
/// gives us better information about what we are loading.
@ -685,12 +580,9 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
debug!("store_ty: {:?} : {:?} <- {:?}", Value(dst), t, Value(v));
if common::type_is_fat_ptr(cx.tcx(), t) {
Store(cx,
ExtractValue(cx, v, abi::FAT_PTR_ADDR),
get_dataptr(cx, dst));
Store(cx,
ExtractValue(cx, v, abi::FAT_PTR_EXTRA),
get_meta(cx, dst));
let lladdr = ExtractValue(cx, v, abi::FAT_PTR_ADDR);
let llextra = ExtractValue(cx, v, abi::FAT_PTR_EXTRA);
store_fat_ptr(cx, lladdr, llextra, dst, t);
} else {
Store(cx, from_immediate(cx, v), dst);
}
@ -708,11 +600,36 @@ pub fn store_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
pub fn load_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
src: ValueRef,
_ty: Ty<'tcx>)
-> (ValueRef, ValueRef) {
// FIXME: emit metadata
(Load(cx, get_dataptr(cx, src)),
Load(cx, get_meta(cx, src)))
ty: Ty<'tcx>)
-> (ValueRef, ValueRef)
{
if cx.unreachable.get() {
// FIXME: remove me
return (Load(cx, get_dataptr(cx, src)),
Load(cx, get_meta(cx, src)));
}
load_fat_ptr_builder(&B(cx), src, ty)
}
pub fn load_fat_ptr_builder<'a, 'tcx>(
b: &Builder<'a, 'tcx>,
src: ValueRef,
t: Ty<'tcx>)
-> (ValueRef, ValueRef)
{
let ptr = get_dataptr_builder(b, src);
let ptr = if t.is_region_ptr() || t.is_unique() {
b.load_nonnull(ptr)
} else {
b.load(ptr)
};
// FIXME: emit metadata on `meta`.
let meta = b.load(get_meta_builder(b, src));
(ptr, meta)
}
pub fn from_immediate(bcx: Block, val: ValueRef) -> ValueRef {

@ -217,6 +217,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
llreffn: ValueRef)
-> ValueRef
{
if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) {
return llfn;
}
debug!("trans_fn_once_adapter_shim(closure_def_id={:?}, substs={:?}, llreffn={:?})",
closure_def_id, substs, Value(llreffn));
@ -257,7 +261,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
// Create the by-value helper.
let function_name = method_instance.symbol_name(ccx.shared());
let lloncefn = declare::declare_fn(ccx, &function_name, llonce_fn_ty);
let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
attributes::set_frame_pointer_elimination(ccx, lloncefn);
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
@ -312,5 +316,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
fcx.finish(bcx, DebugLoc::None);
ccx.instances().borrow_mut().insert(method_instance, lloncefn);
lloncefn
}

@ -35,7 +35,7 @@ use syntax::parse::token;
use super::{MirContext, LocalRef};
use super::analyze::CleanupKind;
use super::constant::Const;
use super::lvalue::{LvalueRef, load_fat_ptr};
use super::lvalue::{LvalueRef};
use super::operand::OperandRef;
use super::operand::OperandValue::*;
@ -703,7 +703,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
for (n, &ty) in arg_types.iter().enumerate() {
let ptr = adt::trans_field_ptr_builder(bcx, tuple.ty, base, Disr(0), n);
let val = if common::type_is_fat_ptr(bcx.tcx(), ty) {
let (lldata, llextra) = load_fat_ptr(bcx, ptr);
let (lldata, llextra) = base::load_fat_ptr_builder(bcx, ptr, ty);
Pair(lldata, llextra)
} else {
// trans_argument will load this if it needs to

@ -13,10 +13,8 @@ use rustc::ty::{self, Ty, TypeFoldable};
use rustc::mir::repr as mir;
use rustc::mir::tcx::LvalueTy;
use rustc_data_structures::indexed_vec::Idx;
use abi;
use adt;
use base;
use builder::Builder;
use common::{self, BlockAndBuilder, CrateContext, C_uint, C_undef};
use consts;
use machine;
@ -69,18 +67,6 @@ impl<'tcx> LvalueRef<'tcx> {
}
}
pub fn get_meta(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
b.struct_gep(fat_ptr, abi::FAT_PTR_EXTRA)
}
pub fn get_dataptr(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
b.struct_gep(fat_ptr, abi::FAT_PTR_ADDR)
}
pub fn load_fat_ptr(b: &Builder, fat_ptr: ValueRef) -> (ValueRef, ValueRef) {
(b.load(get_dataptr(b, fat_ptr)), b.load(get_meta(b, fat_ptr)))
}
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn trans_lvalue(&mut self,
bcx: &BlockAndBuilder<'bcx, 'tcx>,

@ -34,7 +34,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx};
pub use self::constant::trans_static_initializer;
use self::lvalue::{LvalueRef, get_dataptr, get_meta};
use self::lvalue::{LvalueRef};
use rustc::mir::traversal;
use self::operand::{OperandRef, OperandValue};
@ -384,8 +384,10 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
// they are the two sub-fields of a single aggregate field.
let meta = &fcx.fn_ty.args[idx];
idx += 1;
arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, dst));
meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, dst));
arg.store_fn_arg(bcx, &mut llarg_idx,
base::get_dataptr_builder(bcx, dst));
meta.store_fn_arg(bcx, &mut llarg_idx,
base::get_meta_builder(bcx, dst));
} else {
arg.store_fn_arg(bcx, &mut llarg_idx, dst);
}
@ -466,8 +468,10 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
// so make an alloca to store them in.
let meta = &fcx.fn_ty.args[idx];
idx += 1;
arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, lltemp));
meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, lltemp));
arg.store_fn_arg(bcx, &mut llarg_idx,
base::get_dataptr_builder(bcx, lltemp));
meta.store_fn_arg(bcx, &mut llarg_idx,
base::get_meta_builder(bcx, lltemp));
} else {
// otherwise, arg is passed by value, so make a
// temporary and store it there

@ -143,20 +143,18 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
{
debug!("trans_load: {:?} @ {:?}", Value(llval), ty);
let val = if common::type_is_imm_pair(bcx.ccx(), ty) {
let val = if common::type_is_fat_ptr(bcx.tcx(), ty) {
let (lldata, llextra) = base::load_fat_ptr_builder(bcx, llval, ty);
OperandValue::Pair(lldata, llextra)
} else if common::type_is_imm_pair(bcx.ccx(), ty) {
let [a_ty, b_ty] = common::type_pair_fields(bcx.ccx(), ty).unwrap();
let a_ptr = bcx.struct_gep(llval, 0);
let b_ptr = bcx.struct_gep(llval, 1);
// This is None only for fat pointers, which don't
// need any special load-time behavior anyway.
let pair_fields = common::type_pair_fields(bcx.ccx(), ty);
let (a, b) = if let Some([a_ty, b_ty]) = pair_fields {
(base::load_ty_builder(bcx, a_ptr, a_ty),
base::load_ty_builder(bcx, b_ptr, b_ty))
} else {
(bcx.load(a_ptr), bcx.load(b_ptr))
};
OperandValue::Pair(a, b)
OperandValue::Pair(
base::load_ty_builder(bcx, a_ptr, a_ty),
base::load_ty_builder(bcx, b_ptr, b_ty)
)
} else if common::type_is_immediate(bcx.ccx(), ty) {
OperandValue::Immediate(base::load_ty_builder(bcx, llval, ty))
} else {

@ -11,15 +11,18 @@
use llvm::{self, ValueRef};
use rustc::ty::{self, Ty};
use rustc::ty::cast::{CastTy, IntTy};
use rustc::ty::layout::Layout;
use rustc::mir::repr as mir;
use asm;
use base;
use callee::Callee;
use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder, Result};
use common::{C_integral};
use debuginfo::DebugLoc;
use adt;
use machine;
use type_::Type;
use type_of;
use tvec;
use value::Value;
@ -28,7 +31,7 @@ use Disr;
use super::MirContext;
use super::constant::const_scalar_checked_binop;
use super::operand::{OperandRef, OperandValue};
use super::lvalue::{LvalueRef, get_dataptr};
use super::lvalue::{LvalueRef};
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn trans_rvalue(&mut self,
@ -98,7 +101,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let tr_elem = self.trans_operand(&bcx, elem);
let size = count.value.as_u64(bcx.tcx().sess.target.uint_type);
let size = C_uint(bcx.ccx(), size);
let base = get_dataptr(&bcx, dest.llval);
let base = base::get_dataptr_builder(&bcx, dest.llval);
let bcx = bcx.map_block(|block| {
tvec::slice_for_each(block, base, tr_elem.ty, size, |block, llslot| {
self.store_operand_direct(block, llslot, tr_elem);
@ -281,7 +284,26 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
OperandValue::Pair(..) => bug!("Unexpected Pair operand")
};
(discr, adt::is_discr_signed(&l))
let (signed, min, max) = match l {
&Layout::CEnum { signed, min, max, .. } => {
(signed, min, max)
}
_ => bug!("CEnum {:?} is not an enum", operand)
};
if max > min {
// We want `table[e as usize]` to not
// have bound checks, and this is the most
// convenient place to put the `assume`.
base::call_assume(&bcx, bcx.icmp(
llvm::IntULE,
discr,
C_integral(common::val_ty(discr), max, false)
))
}
(discr, signed)
} else {
(operand.immediate(), operand.ty.is_signed())
};
@ -382,13 +404,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
match (lhs.val, rhs.val) {
(OperandValue::Pair(lhs_addr, lhs_extra),
OperandValue::Pair(rhs_addr, rhs_extra)) => {
bcx.with_block(|bcx| {
base::compare_fat_ptrs(bcx,
lhs_addr, lhs_extra,
rhs_addr, rhs_extra,
lhs.ty, op.to_hir_binop(),
debug_loc)
})
self.trans_fat_ptr_binop(&bcx, op,
lhs_addr, lhs_extra,
rhs_addr, rhs_extra,
lhs.ty)
}
_ => bug!()
}
@ -485,6 +504,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
input_ty: Ty<'tcx>) -> ValueRef {
let is_float = input_ty.is_fp();
let is_signed = input_ty.is_signed();
let is_nil = input_ty.is_nil();
let is_bool = input_ty.is_bool();
match op {
mir::BinOp::Add => if is_float {
bcx.fadd(lhs, rhs)
@ -535,12 +556,79 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
DebugLoc::None)
})
}
mir::BinOp::Eq | mir::BinOp::Lt | mir::BinOp::Gt |
mir::BinOp::Ne | mir::BinOp::Le | mir::BinOp::Ge => {
bcx.with_block(|bcx| {
base::compare_scalar_types(bcx, lhs, rhs, input_ty,
op.to_hir_binop(), DebugLoc::None)
mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt |
mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_nil {
C_bool(bcx.ccx(), match op {
mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt => false,
mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => true,
_ => unreachable!()
})
} else if is_float {
bcx.fcmp(
base::bin_op_to_fcmp_predicate(op.to_hir_binop()),
lhs, rhs
)
} else {
let (lhs, rhs) = if is_bool {
// FIXME(#36856) -- extend the bools into `i8` because
// LLVM's i1 comparisons are broken.
(bcx.zext(lhs, Type::i8(bcx.ccx())),
bcx.zext(rhs, Type::i8(bcx.ccx())))
} else {
(lhs, rhs)
};
bcx.icmp(
base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed),
lhs, rhs
)
}
}
}
pub fn trans_fat_ptr_binop(&mut self,
bcx: &BlockAndBuilder<'bcx, 'tcx>,
op: mir::BinOp,
lhs_addr: ValueRef,
lhs_extra: ValueRef,
rhs_addr: ValueRef,
rhs_extra: ValueRef,
_input_ty: Ty<'tcx>)
-> ValueRef {
match op {
mir::BinOp::Eq => {
bcx.and(
bcx.icmp(llvm::IntEQ, lhs_addr, rhs_addr),
bcx.icmp(llvm::IntEQ, lhs_extra, rhs_extra)
)
}
mir::BinOp::Ne => {
bcx.or(
bcx.icmp(llvm::IntNE, lhs_addr, rhs_addr),
bcx.icmp(llvm::IntNE, lhs_extra, rhs_extra)
)
}
mir::BinOp::Le | mir::BinOp::Lt |
mir::BinOp::Ge | mir::BinOp::Gt => {
// a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1)
let (op, strict_op) = match op {
mir::BinOp::Lt => (llvm::IntULT, llvm::IntULT),
mir::BinOp::Le => (llvm::IntULE, llvm::IntULT),
mir::BinOp::Gt => (llvm::IntUGT, llvm::IntUGT),
mir::BinOp::Ge => (llvm::IntUGE, llvm::IntUGT),
_ => bug!(),
};
bcx.or(
bcx.icmp(strict_op, lhs_addr, rhs_addr),
bcx.and(
bcx.icmp(llvm::IntEQ, lhs_addr, rhs_addr),
bcx.icmp(op, lhs_extra, rhs_extra)
)
)
}
_ => {
bug!("unexpected fat ptr binop");
}
}
}

@ -267,14 +267,14 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
let mut initial_partitioning = place_root_translation_items(scx,
trans_items);
debug_dump(tcx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter());
debug_dump(scx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter());
// If the partitioning should produce a fixed count of codegen units, merge
// until that count is reached.
if let PartitioningStrategy::FixedUnitCount(count) = strategy {
merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name[..]);
debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
debug_dump(scx, "POST MERGING:", initial_partitioning.codegen_units.iter());
}
// In the next step, we use the inlining map to determine which addtional
@ -284,7 +284,7 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
let post_inlining = place_inlined_translation_items(initial_partitioning,
inlining_map);
debug_dump(tcx, "POST INLINING:", post_inlining.0.iter());
debug_dump(scx, "POST INLINING:", post_inlining.0.iter());
// Finally, sort by codegen unit name, so that we get deterministic results
let mut result = post_inlining.0;
@ -552,7 +552,7 @@ fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString
index)[..])
}
fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
label: &str,
cgus: I)
where I: Iterator<Item=&'b CodegenUnit<'tcx>>,
@ -561,10 +561,21 @@ fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if cfg!(debug_assertions) {
debug!("{}", label);
for cgu in cgus {
let symbol_map = SymbolMap::build(scx, cgu.items
.iter()
.map(|(&trans_item, _)| trans_item));
debug!("CodegenUnit {}:", cgu.name);
for (trans_item, linkage) in &cgu.items {
debug!(" - {} [{:?}]", trans_item.to_string(tcx), linkage);
let symbol_name = symbol_map.get_or_compute(scx, *trans_item);
let symbol_hash_start = symbol_name.rfind('h');
let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..])
.unwrap_or("<no hash>");
debug!(" - {} [{:?}] [{}]",
trans_item.to_string(scx.tcx()),
linkage,
symbol_hash);
}
debug!("");

@ -1,3 +1,5 @@
## Variance of type and lifetime parameters
This file infers the variance of type and lifetime parameters. The
algorithm is taken from Section 4 of the paper "Taming the Wildcards:
Combining Definition- and Use-Site Variance" published in PLDI'11 and
@ -52,11 +54,11 @@ These indicate that (1) the variance of A must be at most covariant;
variance of C must be at most covariant *and* contravariant. All of these
results are based on a variance lattice defined as follows:
* Top (bivariant)
- +
o Bottom (invariant)
* Top (bivariant)
- +
o Bottom (invariant)
Based on this lattice, the solution V(A)=+, V(B)=-, V(C)=o is the
Based on this lattice, the solution `V(A)=+`, `V(B)=-`, `V(C)=o` is the
optimal solution. Note that there is always a naive solution which
just declares all variables to be invariant.
@ -68,11 +70,11 @@ take the form:
V(X) <= Term
Term := + | - | * | o | V(X) | Term x Term
Here the notation V(X) indicates the variance of a type/region
Here the notation `V(X)` indicates the variance of a type/region
parameter `X` with respect to its defining class. `Term x Term`
represents the "variance transform" as defined in the paper:
If the variance of a type variable `X` in type expression `E` is `V2`
> If the variance of a type variable `X` in type expression `E` is `V2`
and the definition-site variance of the [corresponding] type parameter
of a class `C` is `V1`, then the variance of `X` in the type expression
`C<E>` is `V3 = V1.xform(V2)`.
@ -267,7 +269,7 @@ expressions -- must be invariant with respect to all of their
inputs. To see why this makes sense, consider what subtyping for a
trait reference means:
<T as Trait> <: <U as Trait>
<T as Trait> <: <U as Trait>
means that if I know that `T as Trait`, I also know that `U as
Trait`. Moreover, if you think of it as dictionary passing style,
@ -291,9 +293,9 @@ impl<T> Identity for T { type Out = T; ... }
Now if I have `<&'static () as Identity>::Out`, this can be
validly derived as `&'a ()` for any `'a`:
<&'a () as Identity> <: <&'static () as Identity>
if &'static () < : &'a () -- Identity is contravariant in Self
if 'static : 'a -- Subtyping rules for relations
<&'a () as Identity> <: <&'static () as Identity>
if &'static () < : &'a () -- Identity is contravariant in Self
if 'static : 'a -- Subtyping rules for relations
This change otoh means that `<'static () as Identity>::Out` is
always `&'static ()` (which might then be upcast to `'a ()`,

@ -301,8 +301,8 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext,
tcx.lang_items.char_impl(),
tcx.lang_items.str_impl(),
tcx.lang_items.slice_impl(),
tcx.lang_items.slice_impl(),
tcx.lang_items.const_ptr_impl()
tcx.lang_items.const_ptr_impl(),
tcx.lang_items.mut_ptr_impl(),
];
for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {

@ -231,7 +231,7 @@ impl<R: Seek> Seek for BufReader<R> {
if let SeekFrom::Current(n) = pos {
let remainder = (self.cap - self.pos) as i64;
// it should be safe to assume that remainder fits within an i64 as the alternative
// means we managed to allocate 8 ebibytes and that's absurd.
// means we managed to allocate 8 exbibytes and that's absurd.
// But it's not out of the realm of possibility for some weird underlying reader to
// support seeking by i64::min_value() so we need to handle underflow when subtracting
// remainder.

@ -29,7 +29,7 @@ use sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "openbsd", target_os = "netbsd",
target_os = "solaris", taget_os = "haiku")))]
target_os = "solaris", target_os = "haiku")))]
use sys::net::netc::IPV6_ADD_MEMBERSHIP;
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",

@ -0,0 +1,24 @@
// Copyright 2016 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.
// compile-flags: -O
#![crate_type = "lib"]
pub enum Foo {
A, B
}
// CHECK-LABEL: @lookup
#[no_mangle]
pub fn lookup(buf: &[u8; 2], f: Foo) -> u8 {
// CHECK-NOT: panic_bounds_check
buf[f as usize]
}

@ -11,5 +11,5 @@
fn main() {
let x = Some(1);
match x { } //~ ERROR E0002
match x { } //~ ERROR E0004
}

@ -0,0 +1,56 @@
// Copyright 2016 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 changing what a `type` points to does not go unnoticed.
// compile-flags: -Z query-dep-graph
#![feature(rustc_attrs)]
#![allow(dead_code)]
#![allow(unused_variables)]
fn main() { }
#[rustc_if_this_changed]
type TypeAlias = u32;
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
struct Struct {
x: TypeAlias,
y: u32
}
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
enum Enum {
Variant1(TypeAlias),
Variant2(i32)
}
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
trait Trait {
fn method(&self, _: TypeAlias);
}
struct SomeType;
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
impl SomeType {
fn method(&self, _: TypeAlias) {}
}
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
type TypeAlias2 = TypeAlias;
#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
fn function(_: TypeAlias) {
}

@ -0,0 +1,400 @@
// Copyright 2016 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.
// This test case tests the incremental compilation hash (ICH) implementation
// for function interfaces.
// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.
// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph
#![allow(warnings)]
#![feature(conservative_impl_trait)]
#![feature(intrinsics)]
#![feature(linkage)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]
// Add Parameter ---------------------------------------------------------------
#[cfg(cfail1)]
fn add_parameter() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn add_parameter(p: i32) {}
// Add Return Type -------------------------------------------------------------
#[cfg(cfail1)]
fn add_return_type() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn add_return_type() -> () {}
// Change Parameter Type -------------------------------------------------------
#[cfg(cfail1)]
fn type_of_parameter(p: i32) {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn type_of_parameter(p: i64) {}
// Change Parameter Type Reference ---------------------------------------------
#[cfg(cfail1)]
fn type_of_parameter_ref(p: &i32) {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn type_of_parameter_ref(p: &mut i32) {}
// Change Parameter Order ------------------------------------------------------
#[cfg(cfail1)]
fn order_of_parameters(p1: i32, p2: i64) {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn order_of_parameters(p2: i64, p1: i32) {}
// Unsafe ----------------------------------------------------------------------
#[cfg(cfail1)]
fn make_unsafe() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
unsafe fn make_unsafe() {}
// Extern ----------------------------------------------------------------------
#[cfg(cfail1)]
fn make_extern() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
extern fn make_extern() {}
// Extern C Extern Rust-Intrinsic ----------------------------------------------
#[cfg(cfail1)]
extern "C" fn make_intrinsic() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
extern "rust-intrinsic" fn make_intrinsic() {}
// Type Parameter --------------------------------------------------------------
#[cfg(cfail1)]
fn type_parameter() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn type_parameter<T>() {}
// Lifetime Parameter ----------------------------------------------------------
#[cfg(cfail1)]
fn lifetime_parameter() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn lifetime_parameter<'a>() {}
// Trait Bound -----------------------------------------------------------------
#[cfg(cfail1)]
fn trait_bound<T>() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn trait_bound<T: Eq>() {}
// Builtin Bound ---------------------------------------------------------------
#[cfg(cfail1)]
fn builtin_bound<T>() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn builtin_bound<T: Send>() {}
// Lifetime Bound --------------------------------------------------------------
#[cfg(cfail1)]
fn lifetime_bound<'a, T>() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn lifetime_bound<'a, T: 'a>() {}
// Second Trait Bound ----------------------------------------------------------
#[cfg(cfail1)]
fn second_trait_bound<T: Eq>() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn second_trait_bound<T: Eq + Clone>() {}
// Second Builtin Bound --------------------------------------------------------
#[cfg(cfail1)]
fn second_builtin_bound<T: Send>() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn second_builtin_bound<T: Send + Sized>() {}
// Second Lifetime Bound -------------------------------------------------------
#[cfg(cfail1)]
fn second_lifetime_bound<'a, 'b, T: 'a>() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn second_lifetime_bound<'a, 'b, T: 'a + 'b>() {}
// Inline ----------------------------------------------------------------------
#[cfg(cfail1)]
fn inline() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
#[inline]
fn inline() {}
// Inline Never ----------------------------------------------------------------
#[cfg(cfail1)]
#[inline(always)]
fn inline_never() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
#[inline(never)]
fn inline_never() {}
// No Mangle -------------------------------------------------------------------
#[cfg(cfail1)]
fn no_mangle() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
#[no_mangle]
fn no_mangle() {}
// Linkage ---------------------------------------------------------------------
#[cfg(cfail1)]
fn linkage() {}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
#[linkage="weak_odr"]
fn linkage() {}
// Return Impl Trait -----------------------------------------------------------
#[cfg(cfail1)]
fn return_impl_trait() -> i32 {
0
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn return_impl_trait() -> impl Clone {
0
}
// Change Return Impl Trait ----------------------------------------------------
#[cfg(cfail1)]
fn change_return_impl_trait() -> impl Clone {
0
}
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn change_return_impl_trait() -> impl Copy {
0
}
// Change Return Type Indirectly -----------------------------------------------
struct ReferencedType1;
struct ReferencedType2;
mod change_return_type_indirectly {
#[cfg(cfail1)]
use super::ReferencedType1 as ReturnType;
#[cfg(not(cfail1))]
use super::ReferencedType2 as ReturnType;
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn indirect_return_type() -> ReturnType {
ReturnType {}
}
}
// Change Parameter Type Indirectly --------------------------------------------
mod change_parameter_type_indirectly {
#[cfg(cfail1)]
use super::ReferencedType1 as ParameterType;
#[cfg(not(cfail1))]
use super::ReferencedType2 as ParameterType;
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn indirect_parameter_type(p: ParameterType) {}
}
// Change Trait Bound Indirectly -----------------------------------------------
trait ReferencedTrait1 {}
trait ReferencedTrait2 {}
mod change_trait_bound_indirectly {
#[cfg(cfail1)]
use super::ReferencedTrait1 as Trait;
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn indirect_trait_bound<T: Trait>(p: T) {}
}
// Change Trait Bound Indirectly In Where Clause -------------------------------
mod change_trait_bound_indirectly_in_where_clause {
#[cfg(cfail1)]
use super::ReferencedTrait1 as Trait;
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn indirect_trait_bound_where<T>(p: T) where T: Trait {}
}

@ -26,7 +26,7 @@ fn main() {}
// _2 = _1;
// _3 = _2;
// _0 = Baz { x: _3, y: const F32(0), z: const false };
// goto -> bb1;
// return;
// }
// END rustc.node13.Deaggregator.before.mir
// START rustc.node13.Deaggregator.after.mir
@ -36,6 +36,6 @@ fn main() {}
// (_0.0: usize) = _3;
// (_0.1: f32) = const F32(0);
// (_0.2: bool) = const false;
// goto -> bb1;
// return;
// }
// END rustc.node13.Deaggregator.after.mir

@ -31,7 +31,7 @@ fn main() {
// _2 = _1;
// _3 = _2;
// _0 = Baz::Foo { x: _3 };
// goto -> bb1;
// return;
// }
// END rustc.node10.Deaggregator.before.mir
// START rustc.node10.Deaggregator.after.mir
@ -40,6 +40,6 @@ fn main() {
// _3 = _2;
// ((_0 as Foo).0: usize) = _3;
// discriminant(_0) = 1;
// goto -> bb1;
// return;
// }
// END rustc.node10.Deaggregator.after.mir

@ -38,10 +38,6 @@ fn main() {
// _0 = ();
// StorageDead(_6);
// StorageDead(_1);
// goto -> bb1;
// }
//
// bb1: {
// return;
// }
// END rustc.node4.TypeckMir.before.mir

@ -1,12 +1,16 @@
-include ../tools.mk
# This test case makes sure that monomorphizations of the same function with the
# same set of generic arguments will have the same symbol names when
# instantiated in different crates.
# The following command will:
# 1. dump the symbols of a library using `nm`
# 2. extract only those lines that we are interested in via `grep`
# 3. from those lines, extract just the symbol name via `sed`
# (symbol names always start with "_ZN" and end with "E")
# 4. sort those symbol names for deterministic comparison
# 5. write the result into a file
dump-symbols = nm "$(TMPDIR)/lib$(1).rlib" \
| grep "some_test_function" \
| sed "s/^[0-9a-f]\{8,16\}/00000000/" \
| grep -E "some_test_function|Bar|bar" \
| sed "s/.*\(_ZN.*E\).*/\1/" \
| sort \
> "$(TMPDIR)/$(1).nm"

@ -10,6 +10,20 @@
#![crate_type="rlib"]
pub trait Foo {
fn foo<T>();
}
pub struct Bar;
impl Foo for Bar {
fn foo<T>() {}
}
pub fn bar() {
Bar::foo::<Bar>();
}
pub fn some_test_function<T>(t: T) -> T {
t
}

@ -18,3 +18,9 @@ pub fn user() {
let x = 2u64;
stable_symbol_names1::some_test_function(&x);
}
pub fn trait_impl_test_function() {
use stable_symbol_names1::*;
Bar::foo::<Bar>();
bar();
}