Auto merge of #37002 - jonathandturner:rollup, r=jonathandturner
Rollup of 15 pull requests - Successful merges: #36726, #36832, #36909, #36930, #36932, #36957, #36959, #36960, #36962, #36965, #36966, #36967, #36972, #36974, #36977 - Failed merges:
This commit is contained in:
commit
ad19c32a58
31 changed files with 925 additions and 267 deletions
|
@ -90,16 +90,16 @@ pub fn std_link(build: &Build,
|
||||||
add_to_sysroot(&out_dir, &libdir);
|
add_to_sysroot(&out_dir, &libdir);
|
||||||
|
|
||||||
if target.contains("musl") && !target.contains("mips") {
|
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
|
/// Copies the crt(1,i,n).o startup objects
|
||||||
///
|
///
|
||||||
/// Only required for musl targets that statically link to libc
|
/// 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"] {
|
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>,
|
cc: Option<String>,
|
||||||
cxx: Option<String>,
|
cxx: Option<String>,
|
||||||
android_ndk: Option<String>,
|
android_ndk: Option<String>,
|
||||||
|
musl_root: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
@ -268,6 +269,7 @@ impl Config {
|
||||||
}
|
}
|
||||||
target.cxx = cfg.cxx.clone().map(PathBuf::from);
|
target.cxx = cfg.cxx.clone().map(PathBuf::from);
|
||||||
target.cc = cfg.cc.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);
|
config.target_config.insert(triple.clone(), target);
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,8 +146,8 @@ pub fn check(build: &mut Build) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
panic!("when targeting MUSL either the build.musl-root \
|
panic!("when targeting MUSL either the rust.musl-root \
|
||||||
option or the target.$TARGET.musl-root one must \
|
option or the target.$TARGET.musl-root option must \
|
||||||
be specified in config.toml")
|
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
|
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.
|
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
|
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
|
system is up to the task, and gives you powerful ways to reason about
|
||||||
concurrent code at compile time.
|
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
|
`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
|
between threads, but shared mutable data is unsafe—and when threads are
|
||||||
involved can cause data races!
|
involved—can cause data races!
|
||||||
|
|
||||||
|
|
||||||
Usually when we wish to make something in an immutable position mutable, we use
|
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
|
/// 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
|
/// If `n` substrings are returned, the last substring (the `n`th substring)
|
||||||
/// string slice.
|
/// will contain the remainder of the string.
|
||||||
///
|
///
|
||||||
/// The pattern can be a `&str`, [`char`], or a closure that determines the
|
/// The pattern can be a `&str`, [`char`], or a closure that determines the
|
||||||
/// split.
|
/// split.
|
||||||
|
@ -1098,16 +1098,16 @@ impl str {
|
||||||
/// assert_eq!(v, ["abc", "defXghi"]);
|
/// assert_eq!(v, ["abc", "defXghi"]);
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
|
pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
|
||||||
core_str::StrExt::splitn(self, count, pat)
|
core_str::StrExt::splitn(self, n, pat)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator over substrings of this string slice, separated by a
|
/// An iterator over substrings of this string slice, separated by a
|
||||||
/// pattern, starting from the end of the string, restricted to returning
|
/// 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
|
/// If `n` substrings are returned, the last substring (the `n`th substring)
|
||||||
/// string slice.
|
/// will contain the remainder of the string.
|
||||||
///
|
///
|
||||||
/// The pattern can be a `&str`, [`char`], or a closure that
|
/// The pattern can be a `&str`, [`char`], or a closure that
|
||||||
/// determines the split.
|
/// determines the split.
|
||||||
|
@ -1145,10 +1145,10 @@ impl str {
|
||||||
/// assert_eq!(v, ["ghi", "abc1def"]);
|
/// assert_eq!(v, ["ghi", "abc1def"]);
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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>
|
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
|
/// An iterator over the matches of a pattern within the given string
|
||||||
|
|
|
@ -17,6 +17,9 @@ use ptr;
|
||||||
|
|
||||||
/// An implementation of SipHash 1-3.
|
/// 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/
|
/// See: https://131002.net/siphash/
|
||||||
#[unstable(feature = "sip_hash_13", issue = "34767")]
|
#[unstable(feature = "sip_hash_13", issue = "34767")]
|
||||||
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
|
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
|
||||||
|
@ -39,9 +42,6 @@ pub struct SipHasher24 {
|
||||||
///
|
///
|
||||||
/// See: https://131002.net/siphash/
|
/// 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
|
/// SipHash is a general-purpose hashing function: it runs at a good
|
||||||
/// speed (competitive with Spooky and City) and permits strong _keyed_
|
/// speed (competitive with Spooky and City) and permits strong _keyed_
|
||||||
/// hashing. This lets you key your hashtables from a strong RNG, such as
|
/// 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()
|
data.to_le()
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! rotl {
|
|
||||||
($x:expr, $b:expr) =>
|
|
||||||
(($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! compress {
|
macro_rules! compress {
|
||||||
($state:expr) => ({
|
($state:expr) => ({
|
||||||
compress!($state.v0, $state.v1, $state.v2, $state.v3)
|
compress!($state.v0, $state.v1, $state.v2, $state.v3)
|
||||||
});
|
});
|
||||||
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
|
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
|
||||||
({
|
({
|
||||||
$v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
|
$v0 = $v0.wrapping_add($v1); $v1 = $v1.rotate_left(13); $v1 ^= $v0;
|
||||||
$v0 = rotl!($v0, 32);
|
$v0 = $v0.rotate_left(32);
|
||||||
$v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
|
$v2 = $v2.wrapping_add($v3); $v3 = $v3.rotate_left(16); $v3 ^= $v2;
|
||||||
$v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
|
$v0 = $v0.wrapping_add($v3); $v3 = $v3.rotate_left(21); $v3 ^= $v0;
|
||||||
$v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
|
$v2 = $v2.wrapping_add($v1); $v1 = $v1.rotate_left(17); $v1 ^= $v2;
|
||||||
$v2 = rotl!($v2, 32);
|
$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::expr_use_visitor as euv;
|
||||||
use rustc::middle::mem_categorization::{cmt};
|
use rustc::middle::mem_categorization::{cmt};
|
||||||
use rustc::hir::pat_util::*;
|
use rustc::hir::pat_util::*;
|
||||||
|
use rustc::session::Session;
|
||||||
use rustc::traits::Reveal;
|
use rustc::traits::Reveal;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
|
use rustc_errors::DiagnosticBuilder;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::{FromIterator, IntoIterator, repeat};
|
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();
|
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) {
|
fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
|
||||||
intravisit::walk_expr(cx, ex);
|
intravisit::walk_expr(cx, ex);
|
||||||
match ex.node {
|
match ex.node {
|
||||||
|
@ -215,9 +221,10 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
|
||||||
if inlined_arms.is_empty() {
|
if inlined_arms.is_empty() {
|
||||||
if !pat_ty.is_uninhabited(cx.tcx) {
|
if !pat_ty.is_uninhabited(cx.tcx) {
|
||||||
// We know the type is inhabited, so this must be wrong
|
// We know the type is inhabited, so this must be wrong
|
||||||
let mut err = struct_span_err!(cx.tcx.sess, ex.span, E0002,
|
let mut err = create_e0004(cx.tcx.sess, ex.span,
|
||||||
"non-exhaustive patterns: type {} is non-empty",
|
format!("non-exhaustive patterns: type {} \
|
||||||
pat_ty);
|
is non-empty",
|
||||||
|
pat_ty));
|
||||||
span_help!(&mut err, ex.span,
|
span_help!(&mut err, ex.span,
|
||||||
"Please ensure that all possible cases are being handled; \
|
"Please ensure that all possible cases are being handled; \
|
||||||
possibly adding wildcards or more match arms.");
|
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),
|
1 => format!("pattern {} not covered", joined_patterns),
|
||||||
_ => format!("patterns {} not covered", joined_patterns)
|
_ => format!("patterns {} not covered", joined_patterns)
|
||||||
};
|
};
|
||||||
struct_span_err!(cx.tcx.sess, sp, E0004,
|
create_e0004(cx.tcx.sess, sp,
|
||||||
"non-exhaustive patterns: {} not covered",
|
format!("non-exhaustive patterns: {} not covered",
|
||||||
joined_patterns
|
joined_patterns))
|
||||||
).span_label(sp, &label_text).emit();
|
.span_label(sp, &label_text)
|
||||||
|
.emit();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
|
|
||||||
use self::SawExprComponent::*;
|
use self::SawExprComponent::*;
|
||||||
use self::SawAbiComponent::*;
|
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::ast::{self, Name, NodeId};
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
|
use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
|
||||||
|
@ -155,11 +160,11 @@ enum SawAbiComponent<'a> {
|
||||||
|
|
||||||
SawMod,
|
SawMod,
|
||||||
SawForeignItem,
|
SawForeignItem,
|
||||||
SawItem,
|
SawItem(SawItemComponent),
|
||||||
SawTy,
|
SawTy(SawTyComponent),
|
||||||
SawGenerics,
|
SawGenerics,
|
||||||
SawTraitItem,
|
SawTraitItem(SawTraitOrImplItemComponent),
|
||||||
SawImplItem,
|
SawImplItem(SawTraitOrImplItemComponent),
|
||||||
SawStructField,
|
SawStructField,
|
||||||
SawVariant,
|
SawVariant,
|
||||||
SawPath(bool),
|
SawPath(bool),
|
||||||
|
@ -167,7 +172,7 @@ enum SawAbiComponent<'a> {
|
||||||
SawPathParameters,
|
SawPathParameters,
|
||||||
SawPathListItem,
|
SawPathListItem,
|
||||||
SawBlock,
|
SawBlock,
|
||||||
SawPat,
|
SawPat(SawPatComponent),
|
||||||
SawLocal,
|
SawLocal,
|
||||||
SawArm,
|
SawArm,
|
||||||
SawExpr(SawExprComponent<'a>),
|
SawExpr(SawExprComponent<'a>),
|
||||||
|
@ -198,6 +203,9 @@ enum SawAbiComponent<'a> {
|
||||||
/// because the SVH is just a developer convenience; there is no
|
/// because the SVH is just a developer convenience; there is no
|
||||||
/// guarantee of collision-freedom, hash collisions are just
|
/// guarantee of collision-freedom, hash collisions are just
|
||||||
/// (hopefully) unlikely.)
|
/// (hopefully) unlikely.)
|
||||||
|
///
|
||||||
|
/// The xxxComponent enums and saw_xxx functions for Item, Pat,
|
||||||
|
/// Ty, TraitItem and ImplItem follow the same methodology.
|
||||||
#[derive(Hash)]
|
#[derive(Hash)]
|
||||||
enum SawExprComponent<'a> {
|
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)]
|
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
enum SawSpanExpnKind {
|
enum SawSpanExpnKind {
|
||||||
NoExpansion,
|
NoExpansion,
|
||||||
|
@ -383,10 +519,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
|
||||||
|
|
||||||
fn visit_item(&mut self, i: &'tcx Item) {
|
fn visit_item(&mut self, i: &'tcx Item) {
|
||||||
debug!("visit_item: {:?} st={:?}", i, self.st);
|
debug!("visit_item: {:?} st={:?}", i, self.st);
|
||||||
|
SawItem(saw_item(&i.node)).hash(self.st);
|
||||||
SawItem.hash(self.st);
|
|
||||||
// Hash the value of the discriminant of the Item variant.
|
|
||||||
self.hash_discriminant(&i.node);
|
|
||||||
hash_span!(self, i.span);
|
hash_span!(self, i.span);
|
||||||
hash_attrs!(self, &i.attrs);
|
hash_attrs!(self, &i.attrs);
|
||||||
visit::walk_item(self, i)
|
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) {
|
fn visit_ty(&mut self, t: &'tcx Ty) {
|
||||||
debug!("visit_ty: st={:?}", self.st);
|
debug!("visit_ty: st={:?}", self.st);
|
||||||
SawTy.hash(self.st);
|
SawTy(saw_ty(&t.node)).hash(self.st);
|
||||||
hash_span!(self, t.span);
|
hash_span!(self, t.span);
|
||||||
visit::walk_ty(self, t)
|
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) {
|
fn visit_trait_item(&mut self, ti: &'tcx TraitItem) {
|
||||||
debug!("visit_trait_item: st={:?}", self.st);
|
debug!("visit_trait_item: st={:?}", self.st);
|
||||||
SawTraitItem.hash(self.st);
|
SawTraitItem(saw_trait_item(&ti.node)).hash(self.st);
|
||||||
self.hash_discriminant(&ti.node);
|
|
||||||
hash_span!(self, ti.span);
|
hash_span!(self, ti.span);
|
||||||
hash_attrs!(self, &ti.attrs);
|
hash_attrs!(self, &ti.attrs);
|
||||||
visit::walk_trait_item(self, ti)
|
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) {
|
fn visit_impl_item(&mut self, ii: &'tcx ImplItem) {
|
||||||
debug!("visit_impl_item: st={:?}", self.st);
|
debug!("visit_impl_item: st={:?}", self.st);
|
||||||
SawImplItem.hash(self.st);
|
SawImplItem(saw_impl_item(&ii.node)).hash(self.st);
|
||||||
self.hash_discriminant(&ii.node);
|
|
||||||
hash_span!(self, ii.span);
|
hash_span!(self, ii.span);
|
||||||
hash_attrs!(self, &ii.attrs);
|
hash_attrs!(self, &ii.attrs);
|
||||||
visit::walk_impl_item(self, ii)
|
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) {
|
fn visit_pat(&mut self, p: &'tcx Pat) {
|
||||||
debug!("visit_pat: st={:?}", self.st);
|
debug!("visit_pat: st={:?}", self.st);
|
||||||
SawPat.hash(self.st);
|
SawPat(saw_pat(&p.node)).hash(self.st);
|
||||||
self.hash_discriminant(&p.node);
|
|
||||||
hash_span!(self, p.span);
|
hash_span!(self, p.span);
|
||||||
visit::walk_pat(self, p)
|
visit::walk_pat(self, p)
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ impl<'a> SimplifyCfg<'a> {
|
||||||
|
|
||||||
impl<'l, 'tcx> MirPass<'tcx> for SimplifyCfg<'l> {
|
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>) {
|
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();
|
CfgSimplifier::new(mir).simplify();
|
||||||
remove_dead_blocks(mir);
|
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
|
// we can't use mir.predecessors() here because that counts
|
||||||
// dead blocks, which we don't want to.
|
// dead blocks, which we don't want to.
|
||||||
|
pred_count[START_BLOCK] = 1;
|
||||||
|
|
||||||
for (_, data) in traversal::preorder(mir) {
|
for (_, data) in traversal::preorder(mir) {
|
||||||
if let Some(ref term) = data.terminator {
|
if let Some(ref term) = data.terminator {
|
||||||
for &tgt in term.successors().iter() {
|
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);
|
debug!("collapsing goto chain from {:?} to {:?}", *start, target);
|
||||||
|
|
||||||
*changed |= *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;
|
*start = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,14 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
|
||||||
StructGEP(bcx, fat_ptr, abi::FAT_PTR_ADDR)
|
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 {
|
fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, info_ty: Ty<'tcx>, it: LangItem) -> DefId {
|
||||||
match bcx.tcx().lang_items.require(it) {
|
match bcx.tcx().lang_items.require(it) {
|
||||||
Ok(id) => id,
|
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>,
|
pub fn compare_simd_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
lhs: ValueRef,
|
lhs: ValueRef,
|
||||||
rhs: 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
|
/// 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
|
/// 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.
|
/// 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));
|
debug!("store_ty: {:?} : {:?} <- {:?}", Value(dst), t, Value(v));
|
||||||
|
|
||||||
if common::type_is_fat_ptr(cx.tcx(), t) {
|
if common::type_is_fat_ptr(cx.tcx(), t) {
|
||||||
Store(cx,
|
let lladdr = ExtractValue(cx, v, abi::FAT_PTR_ADDR);
|
||||||
ExtractValue(cx, v, abi::FAT_PTR_ADDR),
|
let llextra = ExtractValue(cx, v, abi::FAT_PTR_EXTRA);
|
||||||
get_dataptr(cx, dst));
|
store_fat_ptr(cx, lladdr, llextra, dst, t);
|
||||||
Store(cx,
|
|
||||||
ExtractValue(cx, v, abi::FAT_PTR_EXTRA),
|
|
||||||
get_meta(cx, dst));
|
|
||||||
} else {
|
} else {
|
||||||
Store(cx, from_immediate(cx, v), dst);
|
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>,
|
pub fn load_fat_ptr<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
|
||||||
src: ValueRef,
|
src: ValueRef,
|
||||||
_ty: Ty<'tcx>)
|
ty: Ty<'tcx>)
|
||||||
-> (ValueRef, ValueRef) {
|
-> (ValueRef, ValueRef)
|
||||||
// FIXME: emit metadata
|
{
|
||||||
(Load(cx, get_dataptr(cx, src)),
|
if cx.unreachable.get() {
|
||||||
Load(cx, get_meta(cx, src)))
|
// 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 {
|
pub fn from_immediate(bcx: Block, val: ValueRef) -> ValueRef {
|
||||||
|
|
|
@ -217,6 +217,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
||||||
llreffn: ValueRef)
|
llreffn: ValueRef)
|
||||||
-> 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={:?})",
|
debug!("trans_fn_once_adapter_shim(closure_def_id={:?}, substs={:?}, llreffn={:?})",
|
||||||
closure_def_id, substs, Value(llreffn));
|
closure_def_id, substs, Value(llreffn));
|
||||||
|
|
||||||
|
@ -257,7 +261,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
||||||
|
|
||||||
// Create the by-value helper.
|
// Create the by-value helper.
|
||||||
let function_name = method_instance.symbol_name(ccx.shared());
|
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);
|
attributes::set_frame_pointer_elimination(ccx, lloncefn);
|
||||||
|
|
||||||
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
||||||
|
@ -312,5 +316,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
||||||
|
|
||||||
fcx.finish(bcx, DebugLoc::None);
|
fcx.finish(bcx, DebugLoc::None);
|
||||||
|
|
||||||
|
ccx.instances().borrow_mut().insert(method_instance, lloncefn);
|
||||||
|
|
||||||
lloncefn
|
lloncefn
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ use syntax::parse::token;
|
||||||
use super::{MirContext, LocalRef};
|
use super::{MirContext, LocalRef};
|
||||||
use super::analyze::CleanupKind;
|
use super::analyze::CleanupKind;
|
||||||
use super::constant::Const;
|
use super::constant::Const;
|
||||||
use super::lvalue::{LvalueRef, load_fat_ptr};
|
use super::lvalue::{LvalueRef};
|
||||||
use super::operand::OperandRef;
|
use super::operand::OperandRef;
|
||||||
use super::operand::OperandValue::*;
|
use super::operand::OperandValue::*;
|
||||||
|
|
||||||
|
@ -703,7 +703,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||||
for (n, &ty) in arg_types.iter().enumerate() {
|
for (n, &ty) in arg_types.iter().enumerate() {
|
||||||
let ptr = adt::trans_field_ptr_builder(bcx, tuple.ty, base, Disr(0), n);
|
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 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)
|
Pair(lldata, llextra)
|
||||||
} else {
|
} else {
|
||||||
// trans_argument will load this if it needs to
|
// 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::repr as mir;
|
||||||
use rustc::mir::tcx::LvalueTy;
|
use rustc::mir::tcx::LvalueTy;
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
use abi;
|
|
||||||
use adt;
|
use adt;
|
||||||
use base;
|
use base;
|
||||||
use builder::Builder;
|
|
||||||
use common::{self, BlockAndBuilder, CrateContext, C_uint, C_undef};
|
use common::{self, BlockAndBuilder, CrateContext, C_uint, C_undef};
|
||||||
use consts;
|
use consts;
|
||||||
use machine;
|
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> {
|
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||||
pub fn trans_lvalue(&mut self,
|
pub fn trans_lvalue(&mut self,
|
||||||
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||||
|
|
|
@ -34,7 +34,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||||
|
|
||||||
pub use self::constant::trans_static_initializer;
|
pub use self::constant::trans_static_initializer;
|
||||||
|
|
||||||
use self::lvalue::{LvalueRef, get_dataptr, get_meta};
|
use self::lvalue::{LvalueRef};
|
||||||
use rustc::mir::traversal;
|
use rustc::mir::traversal;
|
||||||
|
|
||||||
use self::operand::{OperandRef, OperandValue};
|
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.
|
// they are the two sub-fields of a single aggregate field.
|
||||||
let meta = &fcx.fn_ty.args[idx];
|
let meta = &fcx.fn_ty.args[idx];
|
||||||
idx += 1;
|
idx += 1;
|
||||||
arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, dst));
|
arg.store_fn_arg(bcx, &mut llarg_idx,
|
||||||
meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, dst));
|
base::get_dataptr_builder(bcx, dst));
|
||||||
|
meta.store_fn_arg(bcx, &mut llarg_idx,
|
||||||
|
base::get_meta_builder(bcx, dst));
|
||||||
} else {
|
} else {
|
||||||
arg.store_fn_arg(bcx, &mut llarg_idx, dst);
|
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.
|
// so make an alloca to store them in.
|
||||||
let meta = &fcx.fn_ty.args[idx];
|
let meta = &fcx.fn_ty.args[idx];
|
||||||
idx += 1;
|
idx += 1;
|
||||||
arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, lltemp));
|
arg.store_fn_arg(bcx, &mut llarg_idx,
|
||||||
meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, lltemp));
|
base::get_dataptr_builder(bcx, lltemp));
|
||||||
|
meta.store_fn_arg(bcx, &mut llarg_idx,
|
||||||
|
base::get_meta_builder(bcx, lltemp));
|
||||||
} else {
|
} else {
|
||||||
// otherwise, arg is passed by value, so make a
|
// otherwise, arg is passed by value, so make a
|
||||||
// temporary and store it there
|
// temporary and store it there
|
||||||
|
|
|
@ -143,20 +143,18 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||||
{
|
{
|
||||||
debug!("trans_load: {:?} @ {:?}", Value(llval), ty);
|
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 a_ptr = bcx.struct_gep(llval, 0);
|
||||||
let b_ptr = bcx.struct_gep(llval, 1);
|
let b_ptr = bcx.struct_gep(llval, 1);
|
||||||
|
|
||||||
// This is None only for fat pointers, which don't
|
OperandValue::Pair(
|
||||||
// need any special load-time behavior anyway.
|
base::load_ty_builder(bcx, a_ptr, a_ty),
|
||||||
let pair_fields = common::type_pair_fields(bcx.ccx(), ty);
|
base::load_ty_builder(bcx, b_ptr, b_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)
|
|
||||||
} else if common::type_is_immediate(bcx.ccx(), ty) {
|
} else if common::type_is_immediate(bcx.ccx(), ty) {
|
||||||
OperandValue::Immediate(base::load_ty_builder(bcx, llval, ty))
|
OperandValue::Immediate(base::load_ty_builder(bcx, llval, ty))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,15 +11,18 @@
|
||||||
use llvm::{self, ValueRef};
|
use llvm::{self, ValueRef};
|
||||||
use rustc::ty::{self, Ty};
|
use rustc::ty::{self, Ty};
|
||||||
use rustc::ty::cast::{CastTy, IntTy};
|
use rustc::ty::cast::{CastTy, IntTy};
|
||||||
|
use rustc::ty::layout::Layout;
|
||||||
use rustc::mir::repr as mir;
|
use rustc::mir::repr as mir;
|
||||||
|
|
||||||
use asm;
|
use asm;
|
||||||
use base;
|
use base;
|
||||||
use callee::Callee;
|
use callee::Callee;
|
||||||
use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder, Result};
|
use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder, Result};
|
||||||
|
use common::{C_integral};
|
||||||
use debuginfo::DebugLoc;
|
use debuginfo::DebugLoc;
|
||||||
use adt;
|
use adt;
|
||||||
use machine;
|
use machine;
|
||||||
|
use type_::Type;
|
||||||
use type_of;
|
use type_of;
|
||||||
use tvec;
|
use tvec;
|
||||||
use value::Value;
|
use value::Value;
|
||||||
|
@ -28,7 +31,7 @@ use Disr;
|
||||||
use super::MirContext;
|
use super::MirContext;
|
||||||
use super::constant::const_scalar_checked_binop;
|
use super::constant::const_scalar_checked_binop;
|
||||||
use super::operand::{OperandRef, OperandValue};
|
use super::operand::{OperandRef, OperandValue};
|
||||||
use super::lvalue::{LvalueRef, get_dataptr};
|
use super::lvalue::{LvalueRef};
|
||||||
|
|
||||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||||
pub fn trans_rvalue(&mut self,
|
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 tr_elem = self.trans_operand(&bcx, elem);
|
||||||
let size = count.value.as_u64(bcx.tcx().sess.target.uint_type);
|
let size = count.value.as_u64(bcx.tcx().sess.target.uint_type);
|
||||||
let size = C_uint(bcx.ccx(), size);
|
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| {
|
let bcx = bcx.map_block(|block| {
|
||||||
tvec::slice_for_each(block, base, tr_elem.ty, size, |block, llslot| {
|
tvec::slice_for_each(block, base, tr_elem.ty, size, |block, llslot| {
|
||||||
self.store_operand_direct(block, llslot, tr_elem);
|
self.store_operand_direct(block, llslot, tr_elem);
|
||||||
|
@ -281,7 +284,26 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||||
}
|
}
|
||||||
OperandValue::Pair(..) => bug!("Unexpected Pair operand")
|
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 {
|
} else {
|
||||||
(operand.immediate(), operand.ty.is_signed())
|
(operand.immediate(), operand.ty.is_signed())
|
||||||
};
|
};
|
||||||
|
@ -382,13 +404,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||||
match (lhs.val, rhs.val) {
|
match (lhs.val, rhs.val) {
|
||||||
(OperandValue::Pair(lhs_addr, lhs_extra),
|
(OperandValue::Pair(lhs_addr, lhs_extra),
|
||||||
OperandValue::Pair(rhs_addr, rhs_extra)) => {
|
OperandValue::Pair(rhs_addr, rhs_extra)) => {
|
||||||
bcx.with_block(|bcx| {
|
self.trans_fat_ptr_binop(&bcx, op,
|
||||||
base::compare_fat_ptrs(bcx,
|
lhs_addr, lhs_extra,
|
||||||
lhs_addr, lhs_extra,
|
rhs_addr, rhs_extra,
|
||||||
rhs_addr, rhs_extra,
|
lhs.ty)
|
||||||
lhs.ty, op.to_hir_binop(),
|
|
||||||
debug_loc)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
_ => bug!()
|
_ => bug!()
|
||||||
}
|
}
|
||||||
|
@ -485,6 +504,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||||
input_ty: Ty<'tcx>) -> ValueRef {
|
input_ty: Ty<'tcx>) -> ValueRef {
|
||||||
let is_float = input_ty.is_fp();
|
let is_float = input_ty.is_fp();
|
||||||
let is_signed = input_ty.is_signed();
|
let is_signed = input_ty.is_signed();
|
||||||
|
let is_nil = input_ty.is_nil();
|
||||||
|
let is_bool = input_ty.is_bool();
|
||||||
match op {
|
match op {
|
||||||
mir::BinOp::Add => if is_float {
|
mir::BinOp::Add => if is_float {
|
||||||
bcx.fadd(lhs, rhs)
|
bcx.fadd(lhs, rhs)
|
||||||
|
@ -535,12 +556,79 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||||
DebugLoc::None)
|
DebugLoc::None)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
mir::BinOp::Eq | mir::BinOp::Lt | mir::BinOp::Gt |
|
mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt |
|
||||||
mir::BinOp::Ne | mir::BinOp::Le | mir::BinOp::Ge => {
|
mir::BinOp::Eq | mir::BinOp::Le | mir::BinOp::Ge => if is_nil {
|
||||||
bcx.with_block(|bcx| {
|
C_bool(bcx.ccx(), match op {
|
||||||
base::compare_scalar_types(bcx, lhs, rhs, input_ty,
|
mir::BinOp::Ne | mir::BinOp::Lt | mir::BinOp::Gt => false,
|
||||||
op.to_hir_binop(), DebugLoc::None)
|
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,
|
let mut initial_partitioning = place_root_translation_items(scx,
|
||||||
trans_items);
|
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
|
// If the partitioning should produce a fixed count of codegen units, merge
|
||||||
// until that count is reached.
|
// until that count is reached.
|
||||||
if let PartitioningStrategy::FixedUnitCount(count) = strategy {
|
if let PartitioningStrategy::FixedUnitCount(count) = strategy {
|
||||||
merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name[..]);
|
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
|
// 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,
|
let post_inlining = place_inlined_translation_items(initial_partitioning,
|
||||||
inlining_map);
|
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
|
// Finally, sort by codegen unit name, so that we get deterministic results
|
||||||
let mut result = post_inlining.0;
|
let mut result = post_inlining.0;
|
||||||
|
@ -552,7 +552,7 @@ fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString
|
||||||
index)[..])
|
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,
|
label: &str,
|
||||||
cgus: I)
|
cgus: I)
|
||||||
where I: Iterator<Item=&'b CodegenUnit<'tcx>>,
|
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) {
|
if cfg!(debug_assertions) {
|
||||||
debug!("{}", label);
|
debug!("{}", label);
|
||||||
for cgu in cgus {
|
for cgu in cgus {
|
||||||
|
let symbol_map = SymbolMap::build(scx, cgu.items
|
||||||
|
.iter()
|
||||||
|
.map(|(&trans_item, _)| trans_item));
|
||||||
debug!("CodegenUnit {}:", cgu.name);
|
debug!("CodegenUnit {}:", cgu.name);
|
||||||
|
|
||||||
for (trans_item, linkage) in &cgu.items {
|
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!("");
|
debug!("");
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
## Variance of type and lifetime parameters
|
||||||
|
|
||||||
This file infers the variance of type and lifetime parameters. The
|
This file infers the variance of type and lifetime parameters. The
|
||||||
algorithm is taken from Section 4 of the paper "Taming the Wildcards:
|
algorithm is taken from Section 4 of the paper "Taming the Wildcards:
|
||||||
Combining Definition- and Use-Site Variance" published in PLDI'11 and
|
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
|
variance of C must be at most covariant *and* contravariant. All of these
|
||||||
results are based on a variance lattice defined as follows:
|
results are based on a variance lattice defined as follows:
|
||||||
|
|
||||||
* Top (bivariant)
|
* Top (bivariant)
|
||||||
- +
|
- +
|
||||||
o Bottom (invariant)
|
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
|
optimal solution. Note that there is always a naive solution which
|
||||||
just declares all variables to be invariant.
|
just declares all variables to be invariant.
|
||||||
|
|
||||||
|
@ -68,11 +70,11 @@ take the form:
|
||||||
V(X) <= Term
|
V(X) <= Term
|
||||||
Term := + | - | * | o | V(X) | Term 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`
|
parameter `X` with respect to its defining class. `Term x Term`
|
||||||
represents the "variance transform" as defined in the paper:
|
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
|
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
|
of a class `C` is `V1`, then the variance of `X` in the type expression
|
||||||
`C<E>` is `V3 = V1.xform(V2)`.
|
`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
|
inputs. To see why this makes sense, consider what subtyping for a
|
||||||
trait reference means:
|
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
|
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,
|
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
|
Now if I have `<&'static () as Identity>::Out`, this can be
|
||||||
validly derived as `&'a ()` for any `'a`:
|
validly derived as `&'a ()` for any `'a`:
|
||||||
|
|
||||||
<&'a () as Identity> <: <&'static () as Identity>
|
<&'a () as Identity> <: <&'static () as Identity>
|
||||||
if &'static () < : &'a () -- Identity is contravariant in Self
|
if &'static () < : &'a () -- Identity is contravariant in Self
|
||||||
if 'static : 'a -- Subtyping rules for relations
|
if 'static : 'a -- Subtyping rules for relations
|
||||||
|
|
||||||
This change otoh means that `<'static () as Identity>::Out` is
|
This change otoh means that `<'static () as Identity>::Out` is
|
||||||
always `&'static ()` (which might then be upcast to `'a ()`,
|
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.char_impl(),
|
||||||
tcx.lang_items.str_impl(),
|
tcx.lang_items.str_impl(),
|
||||||
tcx.lang_items.slice_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) {
|
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 {
|
if let SeekFrom::Current(n) = pos {
|
||||||
let remainder = (self.cap - self.pos) as i64;
|
let remainder = (self.cap - self.pos) as i64;
|
||||||
// it should be safe to assume that remainder fits within an i64 as the alternative
|
// 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
|
// 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
|
// support seeking by i64::min_value() so we need to handle underflow when subtracting
|
||||||
// remainder.
|
// 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",
|
#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
|
||||||
target_os = "ios", target_os = "macos",
|
target_os = "ios", target_os = "macos",
|
||||||
target_os = "openbsd", target_os = "netbsd",
|
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;
|
use sys::net::netc::IPV6_ADD_MEMBERSHIP;
|
||||||
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
|
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
|
||||||
target_os = "ios", target_os = "macos",
|
target_os = "ios", target_os = "macos",
|
||||||
|
|
24
src/test/codegen/enum-bounds-check.rs
Normal file
24
src/test/codegen/enum-bounds-check.rs
Normal file
|
@ -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() {
|
fn main() {
|
||||||
let x = Some(1);
|
let x = Some(1);
|
||||||
|
|
||||||
match x { } //~ ERROR E0002
|
match x { } //~ ERROR E0004
|
||||||
}
|
}
|
56
src/test/compile-fail/dep-graph-type-alias.rs
Normal file
56
src/test/compile-fail/dep-graph-type-alias.rs
Normal file
|
@ -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) {
|
||||||
|
|
||||||
|
}
|
400
src/test/incremental/hashes/function_interfaces.rs
Normal file
400
src/test/incremental/hashes/function_interfaces.rs
Normal file
|
@ -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;
|
// _2 = _1;
|
||||||
// _3 = _2;
|
// _3 = _2;
|
||||||
// _0 = Baz { x: _3, y: const F32(0), z: const false };
|
// _0 = Baz { x: _3, y: const F32(0), z: const false };
|
||||||
// goto -> bb1;
|
// return;
|
||||||
// }
|
// }
|
||||||
// END rustc.node13.Deaggregator.before.mir
|
// END rustc.node13.Deaggregator.before.mir
|
||||||
// START rustc.node13.Deaggregator.after.mir
|
// START rustc.node13.Deaggregator.after.mir
|
||||||
|
@ -36,6 +36,6 @@ fn main() {}
|
||||||
// (_0.0: usize) = _3;
|
// (_0.0: usize) = _3;
|
||||||
// (_0.1: f32) = const F32(0);
|
// (_0.1: f32) = const F32(0);
|
||||||
// (_0.2: bool) = const false;
|
// (_0.2: bool) = const false;
|
||||||
// goto -> bb1;
|
// return;
|
||||||
// }
|
// }
|
||||||
// END rustc.node13.Deaggregator.after.mir
|
// END rustc.node13.Deaggregator.after.mir
|
||||||
|
|
|
@ -31,7 +31,7 @@ fn main() {
|
||||||
// _2 = _1;
|
// _2 = _1;
|
||||||
// _3 = _2;
|
// _3 = _2;
|
||||||
// _0 = Baz::Foo { x: _3 };
|
// _0 = Baz::Foo { x: _3 };
|
||||||
// goto -> bb1;
|
// return;
|
||||||
// }
|
// }
|
||||||
// END rustc.node10.Deaggregator.before.mir
|
// END rustc.node10.Deaggregator.before.mir
|
||||||
// START rustc.node10.Deaggregator.after.mir
|
// START rustc.node10.Deaggregator.after.mir
|
||||||
|
@ -40,6 +40,6 @@ fn main() {
|
||||||
// _3 = _2;
|
// _3 = _2;
|
||||||
// ((_0 as Foo).0: usize) = _3;
|
// ((_0 as Foo).0: usize) = _3;
|
||||||
// discriminant(_0) = 1;
|
// discriminant(_0) = 1;
|
||||||
// goto -> bb1;
|
// return;
|
||||||
// }
|
// }
|
||||||
// END rustc.node10.Deaggregator.after.mir
|
// END rustc.node10.Deaggregator.after.mir
|
||||||
|
|
|
@ -38,10 +38,6 @@ fn main() {
|
||||||
// _0 = ();
|
// _0 = ();
|
||||||
// StorageDead(_6);
|
// StorageDead(_6);
|
||||||
// StorageDead(_1);
|
// StorageDead(_1);
|
||||||
// goto -> bb1;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// bb1: {
|
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// END rustc.node4.TypeckMir.before.mir
|
// END rustc.node4.TypeckMir.before.mir
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
-include ../tools.mk
|
-include ../tools.mk
|
||||||
|
|
||||||
# This test case makes sure that monomorphizations of the same function with the
|
# The following command will:
|
||||||
# same set of generic arguments will have the same symbol names when
|
# 1. dump the symbols of a library using `nm`
|
||||||
# instantiated in different crates.
|
# 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" \
|
dump-symbols = nm "$(TMPDIR)/lib$(1).rlib" \
|
||||||
| grep "some_test_function" \
|
| grep -E "some_test_function|Bar|bar" \
|
||||||
| sed "s/^[0-9a-f]\{8,16\}/00000000/" \
|
| sed "s/.*\(_ZN.*E\).*/\1/" \
|
||||||
| sort \
|
| sort \
|
||||||
> "$(TMPDIR)/$(1).nm"
|
> "$(TMPDIR)/$(1).nm"
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,20 @@
|
||||||
|
|
||||||
#![crate_type="rlib"]
|
#![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 {
|
pub fn some_test_function<T>(t: T) -> T {
|
||||||
t
|
t
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,3 +18,9 @@ pub fn user() {
|
||||||
let x = 2u64;
|
let x = 2u64;
|
||||||
stable_symbol_names1::some_test_function(&x);
|
stable_symbol_names1::some_test_function(&x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn trait_impl_test_function() {
|
||||||
|
use stable_symbol_names1::*;
|
||||||
|
Bar::foo::<Bar>();
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue