Brandon Sanderson <singingboyo@gmail.com> Brandon Sanderson <singingboyo@hotmail.com>
Brett Cannon <brett@python.org> Brett Cannon <brettcannon@users.noreply.github.com>
Brian Anderson <banderson@mozilla.com> <andersrb@gmail.com>
+Brian Anderson <banderson@mozilla.com> <banderson@mozilla.org>
Brian Dawn <brian.t.dawn@gmail.com>
Brian Leibig <brian@brianleibig.com> Brian Leibig <brian.leibig@gmail.com>
Carl-Anton Ingmarsson <mail@carlanton.se> <ca.ingmarsson@gmail.com>
-Carol (Nichols || Goulding) <carol.nichols@gmail.com>
-Carol (Nichols || Goulding) <cnichols@thinkthroughmath.com>
+Carol (Nichols || Goulding) <carol.nichols@gmail.com> <cnichols@thinkthroughmath.com>
+Carol (Nichols || Goulding) <carol.nichols@gmail.com> Carol Nichols <carol.nichols@gmail.com>
Carol Willing <carolcode@willingconsulting.com>
Chris C Cerami <chrisccerami@users.noreply.github.com> Chris C Cerami <chrisccerami@gmail.com>
Chris Pressey <cpressey@gmail.com>
[pull-requests]: #pull-requests
Pull requests are the primary mechanism we use to change Rust. GitHub itself
-has some [great documentation][pull-requests] on using the Pull Request feature.
+has some [great documentation][about-pull-requests] on using the Pull Request feature.
We use the "fork and pull" model [described here][development-models], where
contributors push changes to their personal fork and create pull requests to
bring those changes into the source repository.
-[pull-requests]: https://help.github.com/articles/about-pull-requests/
+[about-pull-requests]: https://help.github.com/articles/about-pull-requests/
[development-models]: https://help.github.com/articles/about-collaborative-development-models/
Please make pull requests against the `master` branch.
[[package]]
name = "mdbook"
-version = "0.0.26"
+version = "0.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfmt-nightly 0.3.4",
+ "rustfmt-nightly 0.3.6",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.0"
dependencies = [
"clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "mdbook 0.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mdbook 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"syntax_pos 0.0.0",
]
+[[package]]
+name = "rustc-ap-rustc_cratesio_shim"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-ap-rustc_data_structures"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-ap-rustc_errors"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-ap-serialize"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rustc-ap-syntax"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-ap-syntax_pos"
+version = "12.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-demangle"
version = "0.1.5"
"rustc_const_math 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
- "rustc_trans_utils 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
"rustc 0.0.0",
"rustc_back 0.0.0",
"rustc_data_structures 0.0.0",
+ "rustc_incremental 0.0.0",
+ "rustc_mir 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustfmt-nightly"
-version = "0.3.4"
+version = "0.3.6"
dependencies = [
"cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
"checksum markup5ever 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "047150a0e03b57e638fc45af33a0b63a0362305d5b9f92ecef81df472a4cceb0"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
-"checksum mdbook 0.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "8a1ac668292d1e5c7b1c6fd64f70d3a85105b8069a89558a0d67bdb2ff298ca1"
+"checksum mdbook 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "1ee8ba20c002000546681dc78d7f7e91fd35832058b1e2fdd492ca842bb6e9be"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
"checksum rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b21ea952e9bf1569929abf1bb920262cde04b7b1b26d8e0260286302807299d2"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff"
+"checksum rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a51c10af5abd5d698b7e3487e869e6d15f6feb04cbedb5c792e2824f9d845e"
+"checksum rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1aa227490501072780d57f74b1164d361833ff8e172f817da0da2cdf2e4280cc"
+"checksum rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21ff6c6e13ac4fc04b7d4d398828b024c4b6577045cb3175b33d35fea35ff6d0"
+"checksum rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b4e7f51e298675c2bf830f7265621a8936fb09e63b825b58144cbaac969e604"
+"checksum rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8bf5639869ba2f7fa581939cd217cb71a85506b82ad0ea520614fb0dceb2386c"
+"checksum rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c020cdb7379e1c733ae0a311ae47c748337ba584d2dd7b7f53baaae78de6f8b"
"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
// The version number
pub const CFG_RELEASE_NUM: &str = "1.25.0";
-// An optional number to put after the label, e.g. '.2' -> '-beta.2'
-// Be sure to make this starts with a dot to conform to semver pre-release
-// versions (section 9)
-pub const CFG_PRERELEASE_VERSION: &str = ".1";
-
pub struct GitInfo {
inner: Option<Info>,
}
mode: "compile-fail",
suite: "compile-fail-fulldeps",
},
+ Test {
+ path: "src/test/incremental-fulldeps",
+ mode: "incremental",
+ suite: "incremental-fulldeps",
+ },
Test { path: "src/test/run-make", mode: "run-make", suite: "run-make" },
Test { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" },
cmd.env("CFG_RELEASE_INFO", build.rust_version())
.env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
.env("CFG_RELEASE", build.rust_release())
- .env("CFG_PRERELEASE_VERSION", channel::CFG_PRERELEASE_VERSION)
.env("CFG_VER_MAJOR", parts.next().unwrap())
.env("CFG_VER_MINOR", parts.next().unwrap())
.env("CFG_VER_PATCH", parts.next().unwrap())
#[cfg(unix)]
extern crate libc;
-use std::cell::RefCell;
+use std::cell::{RefCell, Cell};
use std::collections::{HashSet, HashMap};
use std::env;
use std::fs::{self, File};
is_sudo: bool,
ci_env: CiEnv,
delayed_failures: RefCell<Vec<String>>,
+ prerelease_version: Cell<Option<u32>>,
}
#[derive(Debug)]
is_sudo,
ci_env: CiEnv::current(),
delayed_failures: RefCell::new(Vec::new()),
+ prerelease_version: Cell::new(None),
}
}
fn release(&self, num: &str) -> String {
match &self.config.channel[..] {
"stable" => num.to_string(),
- "beta" => format!("{}-beta{}", num, channel::CFG_PRERELEASE_VERSION),
+ "beta" => format!("{}-beta.{}", num, self.beta_prerelease_version()),
"nightly" => format!("{}-nightly", num),
_ => format!("{}-dev", num),
}
}
+ fn beta_prerelease_version(&self) -> u32 {
+ if let Some(s) = self.prerelease_version.get() {
+ return s
+ }
+
+ let beta = output(
+ Command::new("git")
+ .arg("ls-remote")
+ .arg("origin")
+ .arg("beta")
+ .current_dir(&self.src)
+ );
+ let beta = beta.trim().split_whitespace().next().unwrap();
+ let master = output(
+ Command::new("git")
+ .arg("ls-remote")
+ .arg("origin")
+ .arg("master")
+ .current_dir(&self.src)
+ );
+ let master = master.trim().split_whitespace().next().unwrap();
+
+ // Figure out where the current beta branch started.
+ let base = output(
+ Command::new("git")
+ .arg("merge-base")
+ .arg(beta)
+ .arg(master)
+ .current_dir(&self.src),
+ );
+ let base = base.trim();
+
+ // Next figure out how many merge commits happened since we branched off
+ // beta. That's our beta number!
+ let count = output(
+ Command::new("git")
+ .arg("rev-list")
+ .arg("--count")
+ .arg("--merges")
+ .arg(format!("{}...HEAD", base))
+ .current_dir(&self.src),
+ );
+ let n = count.trim().parse().unwrap();
+ self.prerelease_version.set(Some(n));
+ n
+ }
+
/// Returns the value of `release` above for Rust itself.
fn rust_release(&self) -> String {
self.release(channel::CFG_RELEASE_NUM)
rm -rf "$CACHE_DIR"
mkdir "$CACHE_DIR"
+# On the beta channel we'll be automatically calculating the prerelease version
+# via the git history, so unshallow our shallow clone from CI.
+if grep -q RUST_RELEASE_CHANNEL=beta src/ci/run.sh; then
+ git fetch origin --unshallow beta master
+fi
+
travis_fold start update_cache
travis_time_start
nicknamed 'The Rust Bookshelf.'
* [The Rust Programming Language][book] teaches you how to program in Rust.
+* [Rust By Example][rbe] teaches you how to program in Rust using editable examples.
* [The Cargo Book][cargo-book] is a guide to Cargo, Rust's build tool and dependency manager.
* [The Unstable Book][unstable-book] has documentation for unstable features.
* [The Rustonomicon][nomicon] is your guidebook to the dark arts of unsafe Rust.
[refchecklist]: https://github.com/rust-lang-nursery/reference/issues/9
[err]: error-index.html
[book]: book/index.html
+[rbe]: rust-by-example/index.html
[nomicon]: nomicon/index.html
[unstable-book]: unstable-book/index.html
[rustdoc-book]: rustdoc/index.html
-Subproject commit 2f7b05fd5939aa49d52c4ab309b9a47776ba7bd8
+Subproject commit fec3182d0b0a3cf8122e192b3270064a5b19be5b
--- /dev/null
+# `repr_transparent`
+
+The tracking issue for this feature is: [#43036]
+
+[#43036]: https://github.com/rust-lang/rust/issues/43036
+
+------------------------
+
+This feature enables the `repr(transparent)` attribute on structs, which enables
+the use of newtypes without the usual ABI implications of wrapping the value in
+a struct.
+
+## Background
+
+It's sometimes useful to add additional type safety by introducing *newtypes*.
+For example, code that handles numeric quantities in different units such as
+millimeters, centimeters, grams, kilograms, etc. may want to use the type system
+to rule out mistakes such as adding millimeters to grams:
+
+```rust
+use std::ops::Add;
+
+struct Millimeters(f64);
+struct Grams(f64);
+
+impl Add<Millimeters> for Millimeters {
+ type Output = Millimeters;
+
+ fn add(self, other: Millimeters) -> Millimeters {
+ Millimeters(self.0 + other.0)
+ }
+}
+
+// Likewise: impl Add<Grams> for Grams {}
+```
+
+Other uses of newtypes include using `PhantomData` to add lifetimes to raw
+pointers or to implement the "phantom types" pattern. See the [PhantomData]
+documentation and [the Nomicon][nomicon-phantom] for more details.
+
+The added type safety is especially useful when interacting with C or other
+languages. However, in those cases we need to ensure the newtypes we add do not
+introduce incompatibilities with the C ABI.
+
+## Newtypes in FFI
+
+Luckily, `repr(C)` newtypes are laid out just like the type they wrap on all
+platforms which Rust currently supports, and likely on many more. For example,
+consider this C declaration:
+
+```C
+struct Object {
+ double weight; //< in grams
+ double height; //< in millimeters
+ // ...
+}
+
+void frobnicate(struct Object *);
+```
+
+While using this C code from Rust, we could add `repr(C)` to the `Grams` and
+`Millimeters` newtypes introduced above and use them to add some type safety
+while staying compatible with the memory layout of `Object`:
+
+```rust,no_run
+#[repr(C)]
+struct Grams(f64);
+
+#[repr(C)]
+struct Millimeters(f64);
+
+#[repr(C)]
+struct Object {
+ weight: Grams,
+ height: Millimeters,
+ // ...
+}
+
+extern {
+ fn frobnicate(_: *mut Object);
+}
+```
+
+This works even when adding some `PhantomData` fields, because they are
+zero-sized and therefore don't have to affect the memory layout.
+
+However, there's more to the ABI than just memory layout: there's also the
+question of how function call arguments and return values are passed. Many
+common ABI treat a struct containing a single field differently from that field
+itself, at least when the field is a scalar (e.g., integer or float or pointer).
+
+To continue the above example, suppose the C library also exposes a function
+like this:
+
+```C
+double calculate_weight(double height);
+```
+
+Using our newtypes on the Rust side like this will cause an ABI mismatch on many
+platforms:
+
+```rust,ignore
+extern {
+ fn calculate_weight(height: Millimeters) -> Grams;
+}
+```
+
+For example, on x86_64 Linux, Rust will pass the argument in an integer
+register, while the C function expects the argument to be in a floating-point
+register. Likewise, the C function will return the result in a floating-point
+register while Rust will expect it in an integer register.
+
+Note that this problem is not specific to floats: To give another example,
+32-bit x86 linux will pass and return `struct Foo(i32);` on the stack while
+`i32` is placed in registers.
+
+## Enter `repr(transparent)`
+
+So while `repr(C)` happens to do the right thing with respect to memory layout,
+it's not quite the right tool for newtypes in FFI. Instead of declaring a C
+struct, we need to communicate to the Rust compiler that our newtype is just for
+type safety on the Rust side. This is what `repr(transparent)` does.
+
+The attribute can be applied to a newtype-like structs that contains a single
+field. It indicates that the newtype should be represented exactly like that
+field's type, i.e., the newtype should be ignored for ABI purpopses: not only is
+it laid out the same in memory, it is also passed identically in function calls.
+
+In the above example, the ABI mismatches can be prevented by making the newtypes
+`Grams` and `Millimeters` transparent like this:
+
+```rust
+#![feature(repr_transparent)]
+
+#[repr(transparent)]
+struct Grams(f64);
+
+#[repr(transparent)]
+struct Millimeters(f64);
+```
+
+In addition to that single field, any number of zero-sized fields are permitted,
+including but not limited to `PhantomData`:
+
+```rust
+#![feature(repr_transparent)]
+
+use std::marker::PhantomData;
+
+struct Foo { /* ... */ }
+
+#[repr(transparent)]
+struct FooPtrWithLifetime<'a>(*const Foo, PhantomData<&'a Foo>);
+
+#[repr(transparent)]
+struct NumberWithUnit<T, U>(T, PhantomData<U>);
+
+struct CustomZst;
+
+#[repr(transparent)]
+struct PtrWithCustomZst<'a> {
+ ptr: FooPtrWithLifetime<'a>,
+ some_marker: CustomZst,
+}
+```
+
+Transparent structs can be nested: `PtrWithCustomZst` is also represented
+exactly like `*const Foo`.
+
+Because `repr(transparent)` delegates all representation concerns to another
+type, it is incompatible with all other `repr(..)` attributes. It also cannot be
+applied to enums, unions, empty structs, structs whose fields are all
+zero-sized, or structs with *multiple* non-zero-sized fields.
+
+[PhantomData]: https://doc.rust-lang.org/std/marker/struct.PhantomData.html
+[nomicon-phantom]: https://doc.rust-lang.org/nomicon/phantom-data.html
use core::fmt;
use core::mem;
use core::usize;
-use core::ptr::{self, Unique};
+use core::ptr::{self, NonNull};
/// Represents the combination of a starting address and
/// a total capacity of the returned block.
/// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom`
/// method, rather than directly invoking `panic!` or similar.
- fn alloc_one<T>(&mut self) -> Result<Unique<T>, AllocErr>
+ fn alloc_one<T>(&mut self) -> Result<NonNull<T>, AllocErr>
where Self: Sized
{
let k = Layout::new::<T>();
if k.size() > 0 {
- unsafe { self.alloc(k).map(|p| Unique::new_unchecked(p as *mut T)) }
+ unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) }
} else {
Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one"))
}
/// * `ptr` must denote a block of memory currently allocated via this allocator
///
/// * the layout of `T` must *fit* that block of memory.
- unsafe fn dealloc_one<T>(&mut self, ptr: Unique<T>)
+ unsafe fn dealloc_one<T>(&mut self, ptr: NonNull<T>)
where Self: Sized
{
let raw_ptr = ptr.as_ptr() as *mut u8;
/// Clients wishing to abort computation in response to an
/// allocation error are encouraged to call the allocator's `oom`
/// method, rather than directly invoking `panic!` or similar.
- fn alloc_array<T>(&mut self, n: usize) -> Result<Unique<T>, AllocErr>
+ fn alloc_array<T>(&mut self, n: usize) -> Result<NonNull<T>, AllocErr>
where Self: Sized
{
match Layout::array::<T>(n) {
unsafe {
self.alloc(layout.clone())
.map(|p| {
- Unique::new_unchecked(p as *mut T)
+ NonNull::new_unchecked(p as *mut T)
})
}
}
/// reallocation error are encouraged to call the allocator's `oom`
/// method, rather than directly invoking `panic!` or similar.
unsafe fn realloc_array<T>(&mut self,
- ptr: Unique<T>,
+ ptr: NonNull<T>,
n_old: usize,
- n_new: usize) -> Result<Unique<T>, AllocErr>
+ n_new: usize) -> Result<NonNull<T>, AllocErr>
where Self: Sized
{
match (Layout::array::<T>(n_old), Layout::array::<T>(n_new), ptr.as_ptr()) {
(Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => {
self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone())
- .map(|p|Unique::new_unchecked(p as *mut T))
+ .map(|p| NonNull::new_unchecked(p as *mut T))
}
_ => {
Err(AllocErr::invalid_input("invalid layout for realloc_array"))
/// constraints.
///
/// Always returns `Err` on arithmetic overflow.
- unsafe fn dealloc_array<T>(&mut self, ptr: Unique<T>, n: usize) -> Result<(), AllocErr>
+ unsafe fn dealloc_array<T>(&mut self, ptr: NonNull<T>, n: usize) -> Result<(), AllocErr>
where Self: Sized
{
let raw_ptr = ptr.as_ptr() as *mut u8;
use core::mem::{self, align_of_val, size_of_val, uninitialized};
use core::ops::Deref;
use core::ops::CoerceUnsized;
-use core::ptr::{self, Shared};
+use core::ptr::{self, NonNull};
use core::marker::{Unsize, PhantomData};
use core::hash::{Hash, Hasher};
use core::{isize, usize};
/// [rc_examples]: ../../std/rc/index.html#examples
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Arc<T: ?Sized> {
- ptr: Shared<ArcInner<T>>,
+ ptr: NonNull<ArcInner<T>>,
phantom: PhantomData<T>,
}
/// [`None`]: ../../std/option/enum.Option.html#variant.None
#[stable(feature = "arc_weak", since = "1.4.0")]
pub struct Weak<T: ?Sized> {
- ptr: Shared<ArcInner<T>>,
+ ptr: NonNull<ArcInner<T>>,
}
#[stable(feature = "arc_weak", since = "1.4.0")]
weak: atomic::AtomicUsize::new(1),
data,
};
- Arc { ptr: Shared::from(Box::into_unique(x)), phantom: PhantomData }
+ Arc { ptr: Box::into_raw_non_null(x), phantom: PhantomData }
}
/// Returns the contained value, if the `Arc` has exactly one strong reference.
let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
Arc {
- ptr: Shared::new_unchecked(arc_ptr),
+ ptr: NonNull::new_unchecked(arc_ptr),
phantom: PhantomData,
}
}
// Free the allocation without dropping its contents
box_free(bptr);
- Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData }
+ Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData }
}
}
}
&mut (*ptr).data as *mut [T] as *mut T,
v.len());
- Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData }
+ Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData }
}
}
// All clear. Forget the guard so it doesn't free the new ArcInner.
mem::forget(guard);
- Arc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData }
+ Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData }
}
}
}
pub fn new() -> Weak<T> {
unsafe {
Weak {
- ptr: Shared::from(Box::into_unique(box ArcInner {
+ ptr: Box::into_raw_non_null(box ArcInner {
strong: atomic::AtomicUsize::new(0),
weak: atomic::AtomicUsize::new(1),
data: uninitialized(),
- })),
+ }),
}
}
}
use core::mem;
use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer};
-use core::ptr::{self, Unique};
+use core::ptr::{self, NonNull, Unique};
use core::convert::From;
use str::from_boxed_utf8_unchecked;
#[stable(feature = "box_raw", since = "1.4.0")]
#[inline]
pub unsafe fn from_raw(raw: *mut T) -> Self {
- Box::from_unique(Unique::new_unchecked(raw))
- }
-
- /// Constructs a `Box` from a `Unique<T>` pointer.
- ///
- /// After calling this function, the memory is owned by a `Box` and `T` can
- /// then be destroyed and released upon drop.
- ///
- /// # Safety
- ///
- /// A `Unique<T>` can be safely created via [`Unique::new`] and thus doesn't
- /// necessarily own the data pointed to nor is the data guaranteed to live
- /// as long as the pointer.
- ///
- /// [`Unique::new`]: ../../core/ptr/struct.Unique.html#method.new
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(unique)]
- ///
- /// fn main() {
- /// let x = Box::new(5);
- /// let ptr = Box::into_unique(x);
- /// let x = unsafe { Box::from_unique(ptr) };
- /// }
- /// ```
- #[unstable(feature = "unique", reason = "needs an RFC to flesh out design",
- issue = "27730")]
- #[inline]
- pub unsafe fn from_unique(u: Unique<T>) -> Self {
- Box(u)
+ Box(Unique::new_unchecked(raw))
}
/// Consumes the `Box`, returning the wrapped raw pointer.
#[stable(feature = "box_raw", since = "1.4.0")]
#[inline]
pub fn into_raw(b: Box<T>) -> *mut T {
- Box::into_unique(b).as_ptr()
+ Box::into_raw_non_null(b).as_ptr()
}
- /// Consumes the `Box`, returning the wrapped pointer as `Unique<T>`.
+ /// Consumes the `Box`, returning the wrapped pointer as `NonNull<T>`.
///
/// After calling this function, the caller is responsible for the
/// memory previously managed by the `Box`. In particular, the
/// caller should properly destroy `T` and release the memory. The
- /// proper way to do so is to either convert the `Unique<T>` pointer:
- ///
- /// - Into a `Box` with the [`Box::from_unique`] function.
- ///
- /// - Into a raw pointer and back into a `Box` with the [`Box::from_raw`]
- /// function.
+ /// proper way to do so is to convert the `NonNull<T>` pointer
+ /// into a raw pointer and back into a `Box` with the [`Box::from_raw`]
+ /// function.
///
/// Note: this is an associated function, which means that you have
- /// to call it as `Box::into_unique(b)` instead of `b.into_unique()`. This
+ /// to call it as `Box::into_raw_non_null(b)`
+ /// instead of `b.into_raw_non_null()`. This
/// is so that there is no conflict with a method on the inner type.
///
- /// [`Box::from_unique`]: struct.Box.html#method.from_unique
/// [`Box::from_raw`]: struct.Box.html#method.from_raw
///
/// # Examples
///
/// ```
- /// #![feature(unique)]
+ /// #![feature(box_into_raw_non_null)]
///
/// fn main() {
/// let x = Box::new(5);
- /// let ptr = Box::into_unique(x);
+ /// let ptr = Box::into_raw_non_null(x);
/// }
/// ```
- #[unstable(feature = "unique", reason = "needs an RFC to flesh out design",
- issue = "27730")]
+ #[unstable(feature = "box_into_raw_non_null", issue = "47336")]
+ #[inline]
+ pub fn into_raw_non_null(b: Box<T>) -> NonNull<T> {
+ Box::into_unique(b).into()
+ }
+
+ #[unstable(feature = "ptr_internals", issue = "0", reason = "use into_raw_non_null instead")]
#[inline]
pub fn into_unique(b: Box<T>) -> Unique<T> {
let unique = b.0;
/// Basic usage:
///
/// ```
- /// use std::collections::BTreeMap;
+ /// use std::collections::BTreeSet;
///
- /// let mut a = BTreeMap::new();
- /// a.insert(1, "a");
- /// a.insert(2, "b");
- /// a.insert(3, "c");
- /// a.insert(17, "d");
- /// a.insert(41, "e");
+ /// let mut a = BTreeSet::new();
+ /// a.insert(1);
+ /// a.insert(2);
+ /// a.insert(3);
+ /// a.insert(17);
+ /// a.insert(41);
///
/// let b = a.split_off(&3);
///
/// assert_eq!(a.len(), 2);
/// assert_eq!(b.len(), 3);
///
- /// assert_eq!(a[&1], "a");
- /// assert_eq!(a[&2], "b");
+ /// assert!(a.contains(&1));
+ /// assert!(a.contains(&2));
///
- /// assert_eq!(b[&3], "c");
- /// assert_eq!(b[&17], "d");
- /// assert_eq!(b[&41], "e");
+ /// assert!(b.contains(&3));
+ /// assert!(b.contains(&17));
+ /// assert!(b.contains(&41));
/// ```
#[stable(feature = "btree_split_off", since = "1.11.0")]
pub fn split_off<Q: ?Sized + Ord>(&mut self, key: &Q) -> Self where T: Borrow<Q> {
///
/// This preserves the non-null invariant for types like `Box<T>`. The address
/// may overlap with non-zero-size memory allocations.
-#[rustc_deprecated(since = "1.19", reason = "Use Unique/Shared::empty() instead")]
+#[rustc_deprecated(since = "1.19", reason = "Use Unique/NonNull::empty() instead")]
#[unstable(feature = "heap_api", issue = "27700")]
pub const EMPTY: *mut () = 1 as *mut ();
#![cfg_attr(test, feature(rand, test))]
#![feature(allow_internal_unstable)]
#![feature(ascii_ctype)]
+#![feature(box_into_raw_non_null)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(cfg_target_has_atomic)]
#![feature(pattern)]
#![feature(placement_in_syntax)]
#![feature(placement_new_protocol)]
+#![feature(ptr_internals)]
#![feature(rustc_attrs)]
-#![feature(shared)]
#![feature(slice_get_slice)]
#![feature(slice_patterns)]
#![feature(slice_rsplit)]
#![feature(trusted_len)]
#![feature(unboxed_closures)]
#![feature(unicode)]
-#![feature(unique)]
#![feature(unsize)]
#![feature(allocator_internals)]
#![feature(on_unimplemented)]
use core::marker::PhantomData;
use core::mem;
use core::ops::{BoxPlace, InPlace, Place, Placer};
-use core::ptr::{self, Shared};
+use core::ptr::{self, NonNull};
use boxed::{Box, IntermediateBox};
use super::SpecExtend;
/// more memory efficient and make better use of CPU cache.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LinkedList<T> {
- head: Option<Shared<Node<T>>>,
- tail: Option<Shared<Node<T>>>,
+ head: Option<NonNull<Node<T>>>,
+ tail: Option<NonNull<Node<T>>>,
len: usize,
marker: PhantomData<Box<Node<T>>>,
}
struct Node<T> {
- next: Option<Shared<Node<T>>>,
- prev: Option<Shared<Node<T>>>,
+ next: Option<NonNull<Node<T>>>,
+ prev: Option<NonNull<Node<T>>>,
element: T,
}
/// [`LinkedList`]: struct.LinkedList.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
- head: Option<Shared<Node<T>>>,
- tail: Option<Shared<Node<T>>>,
+ head: Option<NonNull<Node<T>>>,
+ tail: Option<NonNull<Node<T>>>,
len: usize,
marker: PhantomData<&'a Node<T>>,
}
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T: 'a> {
list: &'a mut LinkedList<T>,
- head: Option<Shared<Node<T>>>,
- tail: Option<Shared<Node<T>>>,
+ head: Option<NonNull<Node<T>>>,
+ tail: Option<NonNull<Node<T>>>,
len: usize,
}
unsafe {
node.next = self.head;
node.prev = None;
- let node = Some(Shared::from(Box::into_unique(node)));
+ let node = Some(Box::into_raw_non_null(node));
match self.head {
None => self.tail = node,
unsafe {
node.next = None;
node.prev = self.tail;
- let node = Some(Shared::from(Box::into_unique(node)));
+ let node = Some(Box::into_raw_non_null(node));
match self.tail {
None => self.head = node,
///
/// Warning: this will not check that the provided node belongs to the current list.
#[inline]
- unsafe fn unlink_node(&mut self, mut node: Shared<Node<T>>) {
+ unsafe fn unlink_node(&mut self, mut node: NonNull<Node<T>>) {
let node = node.as_mut();
match node.prev {
Some(prev) => prev,
};
- let node = Some(Shared::from(Box::into_unique(box Node {
+ let node = Some(Box::into_raw_non_null(box Node {
next: Some(head),
prev: Some(prev),
element,
- })));
+ }));
prev.as_mut().next = node;
head.as_mut().prev = node;
where F: FnMut(&mut T) -> bool,
{
list: &'a mut LinkedList<T>,
- it: Option<Shared<Node<T>>>,
+ it: Option<NonNull<Node<T>>>,
pred: F,
idx: usize,
old_len: usize,
// would cause overflow
let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
match self.a.alloc_array::<T>(new_cap) {
- Ok(ptr) => (new_cap, ptr),
+ Ok(ptr) => (new_cap, ptr.into()),
Err(e) => self.a.oom(e),
}
}
use core::mem::{self, align_of_val, forget, size_of_val, uninitialized};
use core::ops::Deref;
use core::ops::CoerceUnsized;
-use core::ptr::{self, Shared};
+use core::ptr::{self, NonNull};
use core::convert::From;
use heap::{Heap, Alloc, Layout, box_free};
/// [get_mut]: #method.get_mut
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Rc<T: ?Sized> {
- ptr: Shared<RcBox<T>>,
+ ptr: NonNull<RcBox<T>>,
phantom: PhantomData<T>,
}
// pointers, which ensures that the weak destructor never frees
// the allocation while the strong destructor is running, even
// if the weak pointer is stored inside the strong one.
- ptr: Shared::from(Box::into_unique(box RcBox {
+ ptr: Box::into_raw_non_null(box RcBox {
strong: Cell::new(1),
weak: Cell::new(1),
value,
- })),
+ }),
phantom: PhantomData,
}
}
let rc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
Rc {
- ptr: Shared::new_unchecked(rc_ptr),
+ ptr: NonNull::new_unchecked(rc_ptr),
phantom: PhantomData,
}
}
let raw: *const RcBox<Any> = self.ptr.as_ptr();
forget(self);
Ok(Rc {
- ptr: Shared::new_unchecked(raw as *const RcBox<T> as *mut _),
+ ptr: NonNull::new_unchecked(raw as *const RcBox<T> as *mut _),
phantom: PhantomData,
})
}
// Free the allocation without dropping its contents
box_free(bptr);
- Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData }
+ Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData }
}
}
}
&mut (*ptr).value as *mut [T] as *mut T,
v.len());
- Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData }
+ Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData }
}
}
// All clear. Forget the guard so it doesn't free the new RcBox.
forget(guard);
- Rc { ptr: Shared::new_unchecked(ptr), phantom: PhantomData }
+ Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData }
}
}
}
/// [`None`]: ../../std/option/enum.Option.html#variant.None
#[stable(feature = "rc_weak", since = "1.4.0")]
pub struct Weak<T: ?Sized> {
- ptr: Shared<RcBox<T>>,
+ ptr: NonNull<RcBox<T>>,
}
#[stable(feature = "rc_weak", since = "1.4.0")]
pub fn new() -> Weak<T> {
unsafe {
Weak {
- ptr: Shared::from(Box::into_unique(box RcBox {
+ ptr: Box::into_raw_non_null(box RcBox {
strong: Cell::new(0),
weak: Cell::new(1),
value: uninitialized(),
- })),
+ }),
}
}
}
/// assert_eq!(iter.next().unwrap(), &['m']);
/// assert!(iter.next().is_none());
/// ```
+ ///
+ /// [`exact_chunks`]: #method.exact_chunks
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn chunks(&self, chunk_size: usize) -> Chunks<T> {
/// assert_eq!(iter.next().unwrap(), &['r', 'e']);
/// assert!(iter.next().is_none());
/// ```
+ ///
+ /// [`chunks`]: #method.chunks
#[unstable(feature = "exact_chunks", issue = "47115")]
#[inline]
pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
/// }
/// assert_eq!(v, &[1, 1, 2, 2, 3]);
/// ```
+ ///
+ /// [`exact_chunks_mut`]: #method.exact_chunks_mut
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
/// }
/// assert_eq!(v, &[1, 1, 2, 2, 0]);
/// ```
+ ///
+ /// [`chunks_mut`]: #method.chunks_mut
#[unstable(feature = "exact_chunks", issue = "47115")]
#[inline]
pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
use core::ops::{InPlace, Index, IndexMut, Place, Placer};
use core::ops;
use core::ptr;
-use core::ptr::Shared;
+use core::ptr::NonNull;
use core::slice;
use borrow::ToOwned;
tail_start: end,
tail_len: len - end,
iter: range_slice.iter(),
- vec: Shared::from(self),
+ vec: NonNull::from(self),
}
}
}
let cap = self.buf.cap();
mem::forget(self);
IntoIter {
- buf: Shared::new_unchecked(begin),
+ buf: NonNull::new_unchecked(begin),
phantom: PhantomData,
cap,
ptr: begin,
/// [`IntoIterator`]: ../../std/iter/trait.IntoIterator.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<T> {
- buf: Shared<T>,
+ buf: NonNull<T>,
phantom: PhantomData<T>,
cap: usize,
ptr: *const T,
tail_len: usize,
/// Current remaining range to remove
iter: slice::Iter<'a, T>,
- vec: Shared<Vec<T>>,
+ vec: NonNull<Vec<T>>,
}
#[stable(feature = "collection_debug", since = "1.17.0")]
use core::mem;
use core::ops::{Index, IndexMut, Place, Placer, InPlace};
use core::ptr;
-use core::ptr::Shared;
+use core::ptr::NonNull;
use core::slice;
use core::hash::{Hash, Hasher};
self.head = drain_tail;
Drain {
- deque: Shared::from(&mut *self),
+ deque: NonNull::from(&mut *self),
after_tail: drain_head,
after_head: head,
iter: Iter {
}
}
- /// Clears the buffer, removing all values.
+ /// Clears the `VecDeque`, removing all values.
///
/// # Examples
///
return elem;
}
- /// Splits the collection into two at the given index.
+ /// Splits the `VecDeque` into two at the given index.
///
- /// Returns a newly allocated `Self`. `self` contains elements `[0, at)`,
- /// and the returned `Self` contains elements `[at, len)`.
+ /// Returns a newly allocated `VecDeque`. `self` contains elements `[0, at)`,
+ /// and the returned `VecDeque` contains elements `[at, len)`.
///
/// Note that the capacity of `self` does not change.
///
///
/// # Panics
///
- /// Panics if `at > len`
+ /// Panics if `at > len`.
///
/// # Examples
///
impl<T: Clone> VecDeque<T> {
/// Modifies the `VecDeque` in-place so that `len()` is equal to new_len,
- /// either by removing excess elements or by appending clones of `value` to the back.
+ /// either by removing excess elements from the back or by appending clones of `value`
+ /// to the back.
///
/// # Examples
///
after_tail: usize,
after_head: usize,
iter: Iter<'a, T>,
- deque: Shared<VecDeque<T>>,
+ deque: NonNull<VecDeque<T>>,
}
#[stable(feature = "collection_debug", since = "1.17.0")]
type Item = T;
type IntoIter = IntoIter<T>;
- /// Consumes the list into a front-to-back iterator yielding elements by
+ /// Consumes the `VecDeque` into a front-to-back iterator yielding elements by
/// value.
fn into_iter(self) -> IntoIter<T> {
IntoIter { inner: self }
if other.is_contiguous() {
ptr::copy(buf.offset(tail as isize), buf, len);
} else {
- if (tail - head) >= cmp::min((cap - tail), head) {
+ if (tail - head) >= cmp::min(cap - tail, head) {
// There is enough free space in the centre for the shortest block so we can
// do this in at most three copy moves.
if (cap - tail) > head {
}
}
+impl<T, E> Option<Result<T, E>> {
+ /// Transposes an `Option` of a `Result` into a `Result` of an `Option`.
+ ///
+ /// `None` will be mapped to `Ok(None)`.
+ /// `Some(Ok(_))` and `Some(Err(_))` will be mapped to `Ok(Some(_))` and `Err(_)`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(transpose_result)]
+ ///
+ /// #[derive(Debug, Eq, PartialEq)]
+ /// struct SomeErr;
+ ///
+ /// let x: Result<Option<i32>, SomeErr> = Ok(Some(5));
+ /// let y: Option<Result<i32, SomeErr>> = Some(Ok(5));
+ /// assert_eq!(x, y.transpose());
+ /// ```
+ #[inline]
+ #[unstable(feature = "transpose_result", issue = "47338")]
+ pub fn transpose(self) -> Result<Option<T>, E> {
+ match self {
+ Some(Ok(x)) => Ok(Some(x)),
+ Some(Err(e)) => Err(e),
+ None => Ok(None),
+ }
+ }
+}
+
// This is a separate function to reduce the code size of .expect() itself.
#[inline(never)]
#[cold]
/// its owning Unique.
///
/// If you're uncertain of whether it's correct to use `Unique` for your purposes,
-/// consider using `Shared`, which has weaker semantics.
+/// consider using `NonNull`, which has weaker semantics.
///
/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
/// is never dereferenced. This is so that enums may use this forbidden value
///
/// Unlike `*mut T`, `Unique<T>` is covariant over `T`. This should always be correct
/// for any type which upholds Unique's aliasing requirements.
-#[allow(missing_debug_implementations)]
-#[unstable(feature = "unique", reason = "needs an RFC to flesh out design",
- issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0",
+ reason = "use NonNull instead and consider PhantomData<T> \
+ (if you also use #[may_dangle]), Send, and/or Sync")]
pub struct Unique<T: ?Sized> {
pointer: NonZero<*const T>,
// NOTE: this marker has no consequences for variance, but is necessary
_marker: PhantomData<T>,
}
+#[unstable(feature = "ptr_internals", issue = "0")]
+impl<T: ?Sized> fmt::Debug for Unique<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Pointer::fmt(&self.as_ptr(), f)
+ }
+}
+
/// `Unique` pointers are `Send` if `T` is `Send` because the data they
/// reference is unaliased. Note that this aliasing invariant is
/// unenforced by the type system; the abstraction using the
/// `Unique` must enforce it.
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
unsafe impl<T: Send + ?Sized> Send for Unique<T> { }
/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
/// reference is unaliased. Note that this aliasing invariant is
/// unenforced by the type system; the abstraction using the
/// `Unique` must enforce it.
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
unsafe impl<T: Sync + ?Sized> Sync for Unique<T> { }
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: Sized> Unique<T> {
/// Creates a new `Unique` that is dangling, but well-aligned.
///
/// This is useful for initializing types which lazily allocate, like
/// `Vec::new` does.
+ // FIXME: rename to dangling() to match NonNull?
pub fn empty() -> Self {
unsafe {
let ptr = mem::align_of::<T>() as *mut T;
}
}
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: ?Sized> Unique<T> {
/// Creates a new `Unique`.
///
/// # Safety
///
/// `ptr` must be non-null.
- #[unstable(feature = "unique", issue = "27730")]
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
Unique { pointer: NonZero::new_unchecked(ptr), _marker: PhantomData }
}
///
/// The resulting lifetime is bound to self so this behaves "as if"
/// it were actually an instance of T that is getting borrowed. If a longer
- /// (unbound) lifetime is needed, use `&*my_ptr.ptr()`.
+ /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
pub unsafe fn as_ref(&self) -> &T {
&*self.as_ptr()
}
///
/// The resulting lifetime is bound to self so this behaves "as if"
/// it were actually an instance of T that is getting borrowed. If a longer
- /// (unbound) lifetime is needed, use `&mut *my_ptr.ptr()`.
+ /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
pub unsafe fn as_mut(&mut self) -> &mut T {
&mut *self.as_ptr()
}
}
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: ?Sized> Clone for Unique<T> {
fn clone(&self) -> Self {
*self
}
}
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: ?Sized> Copy for Unique<T> { }
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> { }
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: ?Sized> fmt::Pointer for Unique<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&self.as_ptr(), f)
}
}
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
impl<'a, T: ?Sized> From<&'a mut T> for Unique<T> {
fn from(reference: &'a mut T) -> Self {
Unique { pointer: NonZero::from(reference), _marker: PhantomData }
}
}
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
impl<'a, T: ?Sized> From<&'a T> for Unique<T> {
fn from(reference: &'a T) -> Self {
Unique { pointer: NonZero::from(reference), _marker: PhantomData }
}
}
+#[unstable(feature = "ptr_internals", issue = "0")]
+impl<'a, T: ?Sized> From<NonNull<T>> for Unique<T> {
+ fn from(p: NonNull<T>) -> Self {
+ Unique { pointer: p.pointer, _marker: PhantomData }
+ }
+}
+
+/// Previous name of `NonNull`.
+#[rustc_deprecated(since = "1.24", reason = "renamed to `NonNull`")]
+#[unstable(feature = "shared", issue = "27730")]
+pub type Shared<T> = NonNull<T>;
+
/// `*mut T` but non-zero and covariant.
///
/// This is often the correct thing to use when building data structures using
/// raw pointers, but is ultimately more dangerous to use because of its additional
-/// properties. If you're not sure if you should use `Shared<T>`, just use `*mut T`!
+/// properties. If you're not sure if you should use `NonNull<T>`, just use `*mut T`!
///
/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
/// is never dereferenced. This is so that enums may use this forbidden value
-/// as a discriminant -- `Option<Shared<T>>` has the same size as `Shared<T>`.
+/// as a discriminant -- `Option<NonNull<T>>` has the same size as `NonNull<T>`.
/// However the pointer may still dangle if it isn't dereferenced.
///
-/// Unlike `*mut T`, `Shared<T>` is covariant over `T`. If this is incorrect
+/// Unlike `*mut T`, `NonNull<T>` is covariant over `T`. If this is incorrect
/// for your use case, you should include some PhantomData in your type to
/// provide invariance, such as `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`.
/// Usually this won't be necessary; covariance is correct for most safe abstractions,
/// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they
/// provide a public API that follows the normal shared XOR mutable rules of Rust.
-#[allow(missing_debug_implementations)]
-#[unstable(feature = "shared", reason = "needs an RFC to flesh out design",
- issue = "27730")]
-pub struct Shared<T: ?Sized> {
+#[stable(feature = "nonnull", since = "1.24.0")]
+pub struct NonNull<T: ?Sized> {
pointer: NonZero<*const T>,
}
-/// `Shared` pointers are not `Send` because the data they reference may be aliased.
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<T: ?Sized> fmt::Debug for NonNull<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Pointer::fmt(&self.as_ptr(), f)
+ }
+}
+
+/// `NonNull` pointers are not `Send` because the data they reference may be aliased.
// NB: This impl is unnecessary, but should provide better error messages.
-#[unstable(feature = "shared", issue = "27730")]
-impl<T: ?Sized> !Send for Shared<T> { }
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<T: ?Sized> !Send for NonNull<T> { }
-/// `Shared` pointers are not `Sync` because the data they reference may be aliased.
+/// `NonNull` pointers are not `Sync` because the data they reference may be aliased.
// NB: This impl is unnecessary, but should provide better error messages.
-#[unstable(feature = "shared", issue = "27730")]
-impl<T: ?Sized> !Sync for Shared<T> { }
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<T: ?Sized> !Sync for NonNull<T> { }
-#[unstable(feature = "shared", issue = "27730")]
-impl<T: Sized> Shared<T> {
- /// Creates a new `Shared` that is dangling, but well-aligned.
+impl<T: Sized> NonNull<T> {
+ /// Creates a new `NonNull` that is dangling, but well-aligned.
///
/// This is useful for initializing types which lazily allocate, like
/// `Vec::new` does.
- pub fn empty() -> Self {
+ #[stable(feature = "nonnull", since = "1.24.0")]
+ pub fn dangling() -> Self {
unsafe {
let ptr = mem::align_of::<T>() as *mut T;
- Shared::new_unchecked(ptr)
+ NonNull::new_unchecked(ptr)
}
}
}
-#[unstable(feature = "shared", issue = "27730")]
-impl<T: ?Sized> Shared<T> {
- /// Creates a new `Shared`.
+impl<T: ?Sized> NonNull<T> {
+ /// Creates a new `NonNull`.
///
/// # Safety
///
/// `ptr` must be non-null.
- #[unstable(feature = "shared", issue = "27730")]
+ #[stable(feature = "nonnull", since = "1.24.0")]
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
- Shared { pointer: NonZero::new_unchecked(ptr) }
+ NonNull { pointer: NonZero::new_unchecked(ptr) }
}
- /// Creates a new `Shared` if `ptr` is non-null.
+ /// Creates a new `NonNull` if `ptr` is non-null.
+ #[stable(feature = "nonnull", since = "1.24.0")]
pub fn new(ptr: *mut T) -> Option<Self> {
- NonZero::new(ptr as *const T).map(|nz| Shared { pointer: nz })
+ NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz })
}
/// Acquires the underlying `*mut` pointer.
+ #[stable(feature = "nonnull", since = "1.24.0")]
pub fn as_ptr(self) -> *mut T {
self.pointer.get() as *mut T
}
///
/// The resulting lifetime is bound to self so this behaves "as if"
/// it were actually an instance of T that is getting borrowed. If a longer
- /// (unbound) lifetime is needed, use `&*my_ptr.ptr()`.
+ /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
+ #[stable(feature = "nonnull", since = "1.24.0")]
pub unsafe fn as_ref(&self) -> &T {
&*self.as_ptr()
}
///
/// The resulting lifetime is bound to self so this behaves "as if"
/// it were actually an instance of T that is getting borrowed. If a longer
- /// (unbound) lifetime is needed, use `&mut *my_ptr.ptr_mut()`.
+ /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
+ #[stable(feature = "nonnull", since = "1.24.0")]
pub unsafe fn as_mut(&mut self) -> &mut T {
&mut *self.as_ptr()
}
-
- /// Acquires the underlying pointer as a `*mut` pointer.
- #[rustc_deprecated(since = "1.19", reason = "renamed to `as_ptr` for ergonomics/consistency")]
- #[unstable(feature = "shared", issue = "27730")]
- pub unsafe fn as_mut_ptr(&self) -> *mut T {
- self.as_ptr()
- }
}
-#[unstable(feature = "shared", issue = "27730")]
-impl<T: ?Sized> Clone for Shared<T> {
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<T: ?Sized> Clone for NonNull<T> {
fn clone(&self) -> Self {
*self
}
}
-#[unstable(feature = "shared", issue = "27730")]
-impl<T: ?Sized> Copy for Shared<T> { }
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<T: ?Sized> Copy for NonNull<T> { }
-#[unstable(feature = "shared", issue = "27730")]
-impl<T: ?Sized, U: ?Sized> CoerceUnsized<Shared<U>> for Shared<T> where T: Unsize<U> { }
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> { }
-#[unstable(feature = "shared", issue = "27730")]
-impl<T: ?Sized> fmt::Pointer for Shared<T> {
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<T: ?Sized> fmt::Pointer for NonNull<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&self.as_ptr(), f)
}
}
-#[unstable(feature = "shared", issue = "27730")]
-impl<T: ?Sized> From<Unique<T>> for Shared<T> {
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
fn from(unique: Unique<T>) -> Self {
- Shared { pointer: unique.pointer }
+ NonNull { pointer: unique.pointer }
}
}
-#[unstable(feature = "shared", issue = "27730")]
-impl<'a, T: ?Sized> From<&'a mut T> for Shared<T> {
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
fn from(reference: &'a mut T) -> Self {
- Shared { pointer: NonZero::from(reference) }
+ NonNull { pointer: NonZero::from(reference) }
}
}
-#[unstable(feature = "shared", issue = "27730")]
-impl<'a, T: ?Sized> From<&'a T> for Shared<T> {
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<'a, T: ?Sized> From<&'a T> for NonNull<T> {
fn from(reference: &'a T) -> Self {
- Shared { pointer: NonZero::from(reference) }
+ NonNull { pointer: NonZero::from(reference) }
}
}
}
}
+impl<T, E> Result<Option<T>, E> {
+ /// Transposes a `Result` of an `Option` into an `Option` of a `Result`.
+ ///
+ /// `Ok(None)` will be mapped to `None`.
+ /// `Ok(Some(_))` and `Err(_)` will be mapped to `Some(Ok(_))` and `Some(Err(_))`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(transpose_result)]
+ ///
+ /// #[derive(Debug, Eq, PartialEq)]
+ /// struct SomeErr;
+ ///
+ /// let x: Result<Option<i32>, SomeErr> = Ok(Some(5));
+ /// let y: Option<Result<i32, SomeErr>> = Some(Ok(5));
+ /// assert_eq!(x.transpose(), y);
+ /// ```
+ #[inline]
+ #[unstable(feature = "transpose_result", issue = "47338")]
+ pub fn transpose(self) -> Option<Result<T, E>> {
+ match self {
+ Ok(Some(x)) => Some(Ok(x)),
+ Ok(None) => None,
+ Err(e) => Some(Err(e)),
+ }
+ }
+}
+
// This is a separate function to reduce the code size of the methods
#[inline(never)]
#[cold]
#![feature(trusted_len)]
#![feature(try_from)]
#![feature(try_trait)]
-#![feature(unique)]
#![feature(exact_chunks)]
extern crate core;
}
#[test]
-fn test_unsized_unique() {
+fn test_unsized_nonnull() {
let xs: &[i32] = &[1, 2, 3];
- let ptr = unsafe { Unique::new_unchecked(xs as *const [i32] as *mut [i32]) };
+ let ptr = unsafe { NonNull::new_unchecked(xs as *const [i32] as *mut [i32]) };
let ys = unsafe { ptr.as_ref() };
let zs: &[i32] = &[1, 2, 3];
assert!(ys == zs);
invoking itself via a virtual call, and hence does not directly
reference its own *type*.
-"##, }
+"##,
+
+E0692: r##"
+A `repr(transparent)` type was also annotated with other, incompatible
+representation hints.
+
+Erroneous code example:
+
+```compile_fail,E0692
+#![feature(repr_transparent)]
+
+#[repr(transparent, C)] // error: incompatible representation hints
+struct Grams(f32);
+```
+
+A type annotated as `repr(transparent)` delegates all representation concerns to
+another type, so adding more representation hints is contradictory. Remove
+either the `transparent` hint or the other hints, like this:
+
+```
+#![feature(repr_transparent)]
+
+#[repr(transparent)]
+struct Grams(f32);
+```
+
+Alternatively, move the other attributes to the contained type:
+
+```
+#![feature(repr_transparent)]
+
+#[repr(C)]
+struct Foo {
+ x: i32,
+ // ...
+}
+
+#[repr(transparent)]
+struct FooWrapper(Foo);
+```
+
+Note that introducing another `struct` just to have a place for the other
+attributes may have unintended side effects on the representation:
+
+```
+#![feature(repr_transparent)]
+
+#[repr(transparent)]
+struct Grams(f32);
+
+#[repr(C)]
+struct Float(f32);
+
+#[repr(transparent)]
+struct Grams2(Float); // this is not equivalent to `Grams` above
+```
+
+Here, `Grams2` is a not equivalent to `Grams` -- the former transparently wraps
+a (non-transparent) struct containing a single float, while `Grams` is a
+transparent wrapper around a float. This can make a difference for the ABI.
+"##,
+
+}
register_diagnostics! {
let mut int_reprs = 0;
let mut is_c = false;
let mut is_simd = false;
+ let mut is_transparent = false;
for hint in &hints {
let name = if let Some(name) = hint.name() {
continue
}
}
+ "transparent" => {
+ is_transparent = true;
+ if target != Target::Struct {
+ ("a", "struct")
+ } else {
+ continue
+ }
+ }
"i8" | "u8" | "i16" | "u16" |
"i32" | "u32" | "i64" | "u64" |
"isize" | "usize" => {
.emit();
}
+ // Just point at all repr hints if there are any incompatibilities.
+ // This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
+ let hint_spans = hints.iter().map(|hint| hint.span);
+
+ // Error on repr(transparent, <anything else>).
+ if is_transparent && hints.len() > 1 {
+ let hint_spans: Vec<_> = hint_spans.clone().collect();
+ span_err!(self.tcx.sess, hint_spans, E0692,
+ "transparent struct cannot have other repr hints");
+ }
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
if (int_reprs > 1)
|| (is_simd && is_c)
|| (int_reprs == 1 && is_c && is_c_like_enum(item)) {
- // Just point at all repr hints. This is not ideal, but tracking
- // precisely which ones are at fault is a huge hassle.
- let spans: Vec<_> = hints.iter().map(|hint| hint.span).collect();
- span_warn!(self.tcx.sess, spans, E0566,
+ let hint_spans: Vec<_> = hint_spans.collect();
+ span_warn!(self.tcx.sess, hint_spans, E0566,
"conflicting representation hints");
}
}
};
// Correctly resolve `self` imports
- if path.segments.last().unwrap().identifier.name == keywords::SelfValue.name() {
+ if path.segments.len() > 1 &&
+ path.segments.last().unwrap().identifier.name == keywords::SelfValue.name() {
let _ = path.segments.pop();
if ident.name == keywords::SelfValue.name() {
*name = path.segments.last().unwrap().identifier.name;
use syntax_pos::{Span, DUMMY_SP};
use syntax::codemap::{self, Spanned};
use syntax::abi::Abi;
-use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
+use syntax::ast::{self, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
use syntax::ext::hygiene::SyntaxContext;
use syntax::ptr::P;
use syntax::symbol::{Symbol, keywords};
use syntax::tokenstream::TokenStream;
use syntax::util::ThinVec;
+use syntax::util::parser::ExprPrecedence;
use ty::AdtKind;
use rustc_data_structures::indexed_vec;
}
}
+impl Into<ast::BinOpKind> for BinOp_ {
+ fn into(self) -> ast::BinOpKind {
+ match self {
+ BiAdd => ast::BinOpKind::Add,
+ BiSub => ast::BinOpKind::Sub,
+ BiMul => ast::BinOpKind::Mul,
+ BiDiv => ast::BinOpKind::Div,
+ BiRem => ast::BinOpKind::Rem,
+ BiAnd => ast::BinOpKind::And,
+ BiOr => ast::BinOpKind::Or,
+ BiBitXor => ast::BinOpKind::BitXor,
+ BiBitAnd => ast::BinOpKind::BitAnd,
+ BiBitOr => ast::BinOpKind::BitOr,
+ BiShl => ast::BinOpKind::Shl,
+ BiShr => ast::BinOpKind::Shr,
+ BiEq => ast::BinOpKind::Eq,
+ BiLt => ast::BinOpKind::Lt,
+ BiLe => ast::BinOpKind::Le,
+ BiNe => ast::BinOpKind::Ne,
+ BiGe => ast::BinOpKind::Ge,
+ BiGt => ast::BinOpKind::Gt,
+ }
+ }
+}
+
pub type BinOp = Spanned<BinOp_>;
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub hir_id: HirId,
}
+impl Expr {
+ pub fn precedence(&self) -> ExprPrecedence {
+ match self.node {
+ ExprBox(_) => ExprPrecedence::Box,
+ ExprArray(_) => ExprPrecedence::Array,
+ ExprCall(..) => ExprPrecedence::Call,
+ ExprMethodCall(..) => ExprPrecedence::MethodCall,
+ ExprTup(_) => ExprPrecedence::Tup,
+ ExprBinary(op, ..) => ExprPrecedence::Binary(op.node.into()),
+ ExprUnary(..) => ExprPrecedence::Unary,
+ ExprLit(_) => ExprPrecedence::Lit,
+ ExprType(..) | ExprCast(..) => ExprPrecedence::Cast,
+ ExprIf(..) => ExprPrecedence::If,
+ ExprWhile(..) => ExprPrecedence::While,
+ ExprLoop(..) => ExprPrecedence::Loop,
+ ExprMatch(..) => ExprPrecedence::Match,
+ ExprClosure(..) => ExprPrecedence::Closure,
+ ExprBlock(..) => ExprPrecedence::Block,
+ ExprAssign(..) => ExprPrecedence::Assign,
+ ExprAssignOp(..) => ExprPrecedence::AssignOp,
+ ExprField(..) => ExprPrecedence::Field,
+ ExprTupField(..) => ExprPrecedence::TupField,
+ ExprIndex(..) => ExprPrecedence::Index,
+ ExprPath(..) => ExprPrecedence::Path,
+ ExprAddrOf(..) => ExprPrecedence::AddrOf,
+ ExprBreak(..) => ExprPrecedence::Break,
+ ExprAgain(..) => ExprPrecedence::Continue,
+ ExprRet(..) => ExprPrecedence::Ret,
+ ExprInlineAsm(..) => ExprPrecedence::InlineAsm,
+ ExprStruct(..) => ExprPrecedence::Struct,
+ ExprRepeat(..) => ExprPrecedence::Repeat,
+ ExprYield(..) => ExprPrecedence::Yield,
+ }
+ }
+}
+
impl fmt::Debug for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "expr({}: {})", self.id,
}
pub fn print_expr_maybe_paren(&mut self, expr: &hir::Expr, prec: i8) -> io::Result<()> {
- let needs_par = expr_precedence(expr) < prec;
+ let needs_par = expr.precedence().order() < prec;
if needs_par {
self.popen()?;
}
}
}
-
-fn expr_precedence(expr: &hir::Expr) -> i8 {
- use syntax::util::parser::*;
-
- match expr.node {
- hir::ExprClosure(..) => PREC_CLOSURE,
-
- hir::ExprBreak(..) |
- hir::ExprAgain(..) |
- hir::ExprRet(..) |
- hir::ExprYield(..) => PREC_JUMP,
-
- // Binop-like expr kinds, handled by `AssocOp`.
- hir::ExprBinary(op, _, _) => bin_op_to_assoc_op(op.node).precedence() as i8,
-
- hir::ExprCast(..) => AssocOp::As.precedence() as i8,
- hir::ExprType(..) => AssocOp::Colon.precedence() as i8,
-
- hir::ExprAssign(..) |
- hir::ExprAssignOp(..) => AssocOp::Assign.precedence() as i8,
-
- // Unary, prefix
- hir::ExprBox(..) |
- hir::ExprAddrOf(..) |
- hir::ExprUnary(..) => PREC_PREFIX,
-
- // Unary, postfix
- hir::ExprCall(..) |
- hir::ExprMethodCall(..) |
- hir::ExprField(..) |
- hir::ExprTupField(..) |
- hir::ExprIndex(..) |
- hir::ExprInlineAsm(..) => PREC_POSTFIX,
-
- // Never need parens
- hir::ExprArray(..) |
- hir::ExprRepeat(..) |
- hir::ExprTup(..) |
- hir::ExprLit(..) |
- hir::ExprPath(..) |
- hir::ExprIf(..) |
- hir::ExprWhile(..) |
- hir::ExprLoop(..) |
- hir::ExprMatch(..) |
- hir::ExprBlock(..) |
- hir::ExprStruct(..) => PREC_PAREN,
- }
-}
-
fn bin_op_to_assoc_op(op: hir::BinOp_) -> AssocOp {
use hir::BinOp_::*;
match op {
//! This module contains `HashStable` implementations for various data types
//! from rustc::ty in no particular order.
-use ich::{StableHashingContext, NodeIdHashingMode};
+use ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey,
StableHasher, StableHasherResult};
+use std::cell::RefCell;
use std::hash as std_hash;
use std::mem;
use middle::region;
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
- (&self[..]).hash_stable(hcx, hasher);
+ thread_local! {
+ static CACHE: RefCell<FxHashMap<(usize, usize), Fingerprint>> =
+ RefCell::new(FxHashMap());
+ }
+
+ let hash = CACHE.with(|cache| {
+ let key = (self.as_ptr() as usize, self.len());
+ if let Some(&hash) = cache.borrow().get(&key) {
+ return hash;
+ }
+
+ let mut hasher = StableHasher::new();
+ (&self[..]).hash_stable(hcx, &mut hasher);
+
+ let hash: Fingerprint = hasher.finish();
+ cache.borrow_mut().insert(key, hash);
+ hash
+ });
+
+ hash.hash_stable(hcx, hasher);
}
}
sub_region: Region<'tcx>,
sup_origin: SubregionOrigin<'tcx>,
sup_region: Region<'tcx>) {
+
let mut err = self.report_inference_failure(var_origin);
self.tcx.note_and_explain_region(region_scope_tree, &mut err,
///
/// It will later be extended to trait objects.
pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
- let NiceRegionError { span, sub, sup, .. } = *self;
+ let (span, sub, sup) = self.get_regions();
// Determine whether the sub and sup consist of both anonymous (elided) regions.
let anon_reg_sup = self.is_suitable_region(sup)?;
mod different_lifetimes;
mod find_anon_type;
mod named_anon_conflict;
+mod outlives_closure;
mod util;
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
- let (span, sub, sup) = match *error {
- ConcreteFailure(ref origin, sub, sup) => (origin.span(), sub, sup),
- SubSupConflict(_, ref origin, sub, _, sup) => (origin.span(), sub, sup),
- _ => return false, // inapplicable
- };
+ match *error {
+ ConcreteFailure(..) | SubSupConflict(..) => {}
+ _ => return false, // inapplicable
+ }
if let Some(tables) = self.in_progress_tables {
let tables = tables.borrow();
- NiceRegionError::new(self.tcx, span, sub, sup, Some(&tables)).try_report().is_some()
+ NiceRegionError::new(self.tcx, error.clone(), Some(&tables)).try_report().is_some()
} else {
- NiceRegionError::new(self.tcx, span, sub, sup, None).try_report().is_some()
+ NiceRegionError::new(self.tcx, error.clone(), None).try_report().is_some()
}
}
}
pub struct NiceRegionError<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
- span: Span,
- sub: ty::Region<'tcx>,
- sup: ty::Region<'tcx>,
+ error: Option<RegionResolutionError<'tcx>>,
+ regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
tables: Option<&'cx ty::TypeckTables<'tcx>>,
}
impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
pub fn new(
+ tcx: TyCtxt<'cx, 'gcx, 'tcx>,
+ error: RegionResolutionError<'tcx>,
+ tables: Option<&'cx ty::TypeckTables<'tcx>>,
+ ) -> Self {
+ Self { tcx, error: Some(error), regions: None, tables }
+ }
+
+ pub fn new_from_span(
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
span: Span,
sub: ty::Region<'tcx>,
sup: ty::Region<'tcx>,
tables: Option<&'cx ty::TypeckTables<'tcx>>,
) -> Self {
- Self { tcx, span, sub, sup, tables }
+ Self { tcx, error: None, regions: Some((span, sub, sup)), tables }
}
pub fn try_report(&self) -> Option<ErrorReported> {
self.try_report_named_anon_conflict()
.or_else(|| self.try_report_anon_anon_conflict())
+ .or_else(|| self.try_report_outlives_closure())
+ }
+
+ pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
+ match (&self.error, self.regions) {
+ (&Some(ConcreteFailure(ref origin, sub, sup)), None) => (origin.span(), sub, sup),
+ (&Some(SubSupConflict(_, ref origin, sub, _, sup)), None) => (origin.span(), sub, sup),
+ (None, Some((span, sub, sup))) => (span, sub, sup),
+ (Some(_), Some(_)) => panic!("incorrectly built NiceRegionError"),
+ _ => panic!("trying to report on an incorrect lifetime failure"),
+ }
}
}
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
/// an anonymous region, emit an descriptive diagnostic error.
pub(super) fn try_report_named_anon_conflict(&self) -> Option<ErrorReported> {
- let NiceRegionError { span, sub, sup, .. } = *self;
+ let (span, sub, sup) = self.get_regions();
debug!(
"try_report_named_anon_conflict(sub={:?}, sup={:?})",
--- /dev/null
+// Copyright 2018 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.
+
+//! Error Reporting for Anonymous Region Lifetime Errors
+//! where both the regions are anonymous.
+
+use infer::error_reporting::nice_region_error::NiceRegionError;
+use infer::SubregionOrigin;
+use ty::RegionKind;
+use hir::{Expr, ExprClosure};
+use hir::map::NodeExpr;
+use util::common::ErrorReported;
+use infer::lexical_region_resolve::RegionResolutionError::SubSupConflict;
+
+impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
+ /// Print the error message for lifetime errors when binding excapes a closure.
+ ///
+ /// Consider a case where we have
+ ///
+ /// ```no_run
+ /// fn with_int<F>(f: F) where F: FnOnce(&isize) {
+ /// let x = 3;
+ /// f(&x);
+ /// }
+ /// fn main() {
+ /// let mut x = None;
+ /// with_int(|y| x = Some(y));
+ /// }
+ /// ```
+ ///
+ /// the output will be
+ ///
+ /// ```text
+ /// let mut x = None;
+ /// ----- borrowed data cannot be stored into here...
+ /// with_int(|y| x = Some(y));
+ /// --- ^ cannot be stored outside of its closure
+ /// |
+ /// ...because it cannot outlive this closure
+ /// ```
+ pub(super) fn try_report_outlives_closure(&self) -> Option<ErrorReported> {
+ if let Some(SubSupConflict(origin,
+ ref sub_origin,
+ _,
+ ref sup_origin,
+ sup_region)) = self.error {
+
+ // #45983: when trying to assign the contents of an argument to a binding outside of a
+ // closure, provide a specific message pointing this out.
+ if let (&SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span),
+ &RegionKind::ReFree(ref free_region)) = (&sub_origin, sup_region) {
+ let hir = &self.tcx.hir;
+ if let Some(node_id) = hir.as_local_node_id(free_region.scope) {
+ match hir.get(node_id) {
+ NodeExpr(Expr {
+ node: ExprClosure(_, _, _, closure_span, false),
+ ..
+ }) => {
+ let sup_sp = sup_origin.span();
+ let origin_sp = origin.span();
+ let mut err = self.tcx.sess.struct_span_err(
+ sup_sp,
+ "borrowed data cannot be stored outside of its closure");
+ err.span_label(sup_sp, "cannot be stored outside of its closure");
+ if origin_sp == sup_sp || origin_sp.contains(sup_sp) {
+// // sup_sp == origin.span():
+//
+// let mut x = None;
+// ----- borrowed data cannot be stored into here...
+// with_int(|y| x = Some(y));
+// --- ^ cannot be stored outside of its closure
+// |
+// ...because it cannot outlive this closure
+//
+// // origin.contains(&sup_sp):
+//
+// let mut f: Option<&u32> = None;
+// ----- borrowed data cannot be stored into here...
+// closure_expecting_bound(|x: &'x u32| {
+// ------------ ... because it cannot outlive this closure
+// f = Some(x);
+// ^ cannot be stored outside of its closure
+ err.span_label(*external_span,
+ "borrowed data cannot be stored into here...");
+ err.span_label(*closure_span,
+ "...because it cannot outlive this closure");
+ } else {
+// FIXME: the wording for this case could be much improved
+//
+// let mut lines_to_use: Vec<&CrateId> = Vec::new();
+// - cannot infer an appropriate lifetime...
+// let push_id = |installed_id: &CrateId| {
+// ------- ------------------------ borrowed data cannot outlive this closure
+// |
+// ...so that variable is valid at time of its declaration
+// lines_to_use.push(installed_id);
+// ^^^^^^^^^^^^ cannot be stored outside of its closure
+ err.span_label(origin_sp,
+ "cannot infer an appropriate lifetime...");
+ err.span_label(*external_span,
+ "...so that variable is valid at time of its \
+ declaration");
+ err.span_label(*closure_span,
+ "borrowed data cannot outlive this closure");
+ }
+ err.emit();
+ return Some(ErrorReported);
+ }
+ _ => {}
+ }
+ }
+ }
+ }
+ None
+ }
+}
+
#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
#![feature(const_fn)]
+#![feature(copy_closures, clone_closures)]
#![feature(core_intrinsics)]
#![feature(drain_filter)]
#![feature(dyn_trait)]
fn super_mir(&mut self,
mir: & $($mutability)* Mir<'tcx>) {
+ if let Some(yield_ty) = &$($mutability)* mir.yield_ty {
+ self.visit_ty(yield_ty, TyContext::YieldTy(SourceInfo {
+ span: mir.span,
+ scope: ARGUMENT_VISIBILITY_SCOPE,
+ }));
+ }
+
// for best performance, we want to use an iterator rather
// than a for-loop, to avoid calling Mir::invalidate for
// each basic block.
/// The return type of the function.
ReturnTy(SourceInfo),
+ YieldTy(SourceInfo),
+
/// A type found at some location.
Location(Location),
}
options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
build_debugging_options, "Z", "debugging",
DB_OPTIONS, db_type_desc, dbsetters,
+ codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
+ "the backend to use"),
verbose: bool = (false, parse_bool, [UNTRACKED],
"in general, enable more debug printouts"),
span_free_formats: bool = (false, parse_bool, [UNTRACKED],
pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo};
pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo};
-use hir::def_id::{CrateNum, DefIndex};
+use hir::def_id::CrateNum;
use ich::Fingerprint;
use lint;
/// Returns the symbol name for the registrar function,
/// given the crate Svh and the function DefIndex.
- pub fn generate_plugin_registrar_symbol(&self, disambiguator: CrateDisambiguator,
- index: DefIndex)
+ pub fn generate_plugin_registrar_symbol(&self,
+ disambiguator: CrateDisambiguator)
-> String {
- format!("__rustc_plugin_registrar__{}_{}", disambiguator.to_fingerprint().to_hex(),
- index.to_proc_macro_index())
+ format!("__rustc_plugin_registrar_{}__", disambiguator.to_fingerprint().to_hex())
}
- pub fn generate_derive_registrar_symbol(&self, disambiguator: CrateDisambiguator,
- index: DefIndex)
+ pub fn generate_derive_registrar_symbol(&self,
+ disambiguator: CrateDisambiguator)
-> String {
- format!("__rustc_derive_registrar__{}_{}", disambiguator.to_fingerprint().to_hex(),
- index.to_proc_macro_index())
+ format!("__rustc_derive_registrar_{}__", disambiguator.to_fingerprint().to_hex())
}
pub fn sysroot<'a>(&'a self) -> &'a Path {
self.tcx.hir.span_if_local(did)
}).map(|sp| self.tcx.sess.codemap().def_span(sp)); // the sp could be an fn def
- let found_ty_count =
- match found_trait_ref.skip_binder().substs.type_at(1).sty {
- ty::TyTuple(ref tys, _) => tys.len(),
- _ => 1,
- };
- let (expected_tys, expected_ty_count) =
- match expected_trait_ref.skip_binder().substs.type_at(1).sty {
- ty::TyTuple(ref tys, _) =>
- (tys.iter().map(|t| &t.sty).collect(), tys.len()),
- ref sty => (vec![sty], 1),
- };
- if found_ty_count == expected_ty_count {
+ let found = match found_trait_ref.skip_binder().substs.type_at(1).sty {
+ ty::TyTuple(ref tys, _) => tys.iter()
+ .map(|_| ArgKind::empty()).collect::<Vec<_>>(),
+ _ => vec![ArgKind::empty()],
+ };
+ let expected = match expected_trait_ref.skip_binder().substs.type_at(1).sty {
+ ty::TyTuple(ref tys, _) => tys.iter()
+ .map(|t| match t.sty {
+ ty::TypeVariants::TyTuple(ref tys, _) => ArgKind::Tuple(
+ span,
+ tys.iter()
+ .map(|ty| ("_".to_owned(), format!("{}", ty.sty)))
+ .collect::<Vec<_>>()
+ ),
+ _ => ArgKind::Arg("_".to_owned(), format!("{}", t.sty)),
+ }).collect(),
+ ref sty => vec![ArgKind::Arg("_".to_owned(), format!("{}", sty))],
+ };
+ if found.len()== expected.len() {
self.report_closure_arg_mismatch(span,
found_span,
found_trait_ref,
expected_trait_ref)
} else {
- let expected_tuple = if expected_ty_count == 1 {
- expected_tys.first().and_then(|t| {
- if let &&ty::TyTuple(ref tuptys, _) = t {
- Some(tuptys.len())
- } else {
- None
- }
- })
- } else {
- None
- };
-
- // FIXME(#44150): Expand this to "N args expected but a N-tuple found."
- // Type of the 1st expected argument is somehow provided as type of a
- // found one in that case.
- //
- // ```
- // [1i32, 2, 3].sort_by(|(a, b)| ..)
- // // ^^^^^^^ --------
- // // expected_trait_ref: std::ops::FnMut<(&i32, &i32)>
- // // found_trait_ref: std::ops::FnMut<(&i32,)>
- // ```
-
- let (closure_span, closure_args) = found_did
+ let (closure_span, found) = found_did
.and_then(|did| self.tcx.hir.get_if_local(did))
- .and_then(|node| {
- if let hir::map::NodeExpr(
- &hir::Expr {
- node: hir::ExprClosure(_, ref decl, id, span, _),
- ..
- }) = node
- {
- let ty_snips = decl.inputs.iter()
- .map(|ty| {
- self.tcx.sess.codemap().span_to_snippet(ty.span).ok()
- .and_then(|snip| {
- // filter out dummy spans
- if snip == "," || snip == "|" {
- None
- } else {
- Some(snip)
- }
- })
- })
- .collect::<Vec<Option<String>>>();
-
- let body = self.tcx.hir.body(id);
- let pat_snips = body.arguments.iter()
- .map(|arg|
- self.tcx.sess.codemap().span_to_snippet(arg.pat.span).ok())
- .collect::<Option<Vec<String>>>();
-
- Some((span, pat_snips, ty_snips))
- } else {
- None
- }
- })
- .map(|(span, pat, ty)| (Some(span), Some((pat, ty))))
- .unwrap_or((None, None));
- let closure_args = closure_args.and_then(|(pat, ty)| Some((pat?, ty)));
-
- self.report_arg_count_mismatch(
- span,
- closure_span.or(found_span),
- expected_ty_count,
- expected_tuple,
- found_ty_count,
- closure_args,
- found_trait_ty.is_closure()
- )
+ .map(|node| self.get_fn_like_arguments(node))
+ .unwrap_or((found_span.unwrap(), found));
+
+ self.report_arg_count_mismatch(span,
+ closure_span,
+ expected,
+ found,
+ found_trait_ty.is_closure())
}
}
}
}
+ fn get_fn_like_arguments(&self, node: hir::map::Node) -> (Span, Vec<ArgKind>) {
+ if let hir::map::NodeExpr(&hir::Expr {
+ node: hir::ExprClosure(_, ref _decl, id, span, _),
+ ..
+ }) = node {
+ (self.tcx.sess.codemap().def_span(span), self.tcx.hir.body(id).arguments.iter()
+ .map(|arg| {
+ if let hir::Pat {
+ node: hir::PatKind::Tuple(args, _),
+ span,
+ ..
+ } = arg.pat.clone().into_inner() {
+ ArgKind::Tuple(
+ span,
+ args.iter().map(|pat| {
+ let snippet = self.tcx.sess.codemap()
+ .span_to_snippet(pat.span).unwrap();
+ (snippet, "_".to_owned())
+ }).collect::<Vec<_>>(),
+ )
+ } else {
+ let name = self.tcx.sess.codemap().span_to_snippet(arg.pat.span).unwrap();
+ ArgKind::Arg(name, "_".to_owned())
+ }
+ })
+ .collect::<Vec<ArgKind>>())
+ } else if let hir::map::NodeItem(&hir::Item {
+ span,
+ node: hir::ItemFn(ref decl, ..),
+ ..
+ }) = node {
+ (self.tcx.sess.codemap().def_span(span), decl.inputs.iter()
+ .map(|arg| match arg.clone().into_inner().node {
+ hir::TyTup(ref tys) => ArgKind::Tuple(
+ arg.span,
+ tys.iter()
+ .map(|_| ("_".to_owned(), "_".to_owned()))
+ .collect::<Vec<_>>(),
+ ),
+ _ => ArgKind::Arg("_".to_owned(), "_".to_owned())
+ }).collect::<Vec<ArgKind>>())
+ } else {
+ panic!("non-FnLike node found: {:?}", node);
+ }
+ }
+
fn report_arg_count_mismatch(
&self,
span: Span,
- found_span: Option<Span>,
- expected: usize,
- expected_tuple: Option<usize>,
- found: usize,
- closure_args: Option<(Vec<String>, Vec<Option<String>>)>,
- is_closure: bool
+ found_span: Span,
+ expected_args: Vec<ArgKind>,
+ found_args: Vec<ArgKind>,
+ is_closure: bool,
) -> DiagnosticBuilder<'tcx> {
- use std::borrow::Cow;
-
let kind = if is_closure { "closure" } else { "function" };
- let args_str = |n, distinct| format!(
- "{} {}argument{}",
- n,
- if distinct && n >= 2 { "distinct " } else { "" },
- if n == 1 { "" } else { "s" },
- );
-
- let expected_str = if let Some(n) = expected_tuple {
- assert!(expected == 1);
- if closure_args.as_ref().map(|&(ref pats, _)| pats.len()) == Some(n) {
- Cow::from("a single tuple as argument")
- } else {
- // be verbose when numbers differ
- Cow::from(format!("a single {}-tuple as argument", n))
+ let args_str = |arguments: &Vec<ArgKind>, other: &Vec<ArgKind>| {
+ let arg_length = arguments.len();
+ let distinct = match &other[..] {
+ &[ArgKind::Tuple(..)] => true,
+ _ => false,
+ };
+ match (arg_length, arguments.get(0)) {
+ (1, Some(&ArgKind::Tuple(_, ref fields))) => {
+ format!("a single {}-tuple as argument", fields.len())
+ }
+ _ => format!("{} {}argument{}",
+ arg_length,
+ if distinct && arg_length > 1 { "distinct " } else { "" },
+ if arg_length == 1 { "" } else { "s" }),
}
- } else {
- Cow::from(args_str(expected, false))
- };
-
- let found_str = if expected_tuple.is_some() {
- args_str(found, true)
- } else {
- args_str(found, false)
};
+ let expected_str = args_str(&expected_args, &found_args);
+ let found_str = args_str(&found_args, &expected_args);
- let mut err = struct_span_err!(self.tcx.sess, span, E0593,
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0593,
"{} is expected to take {}, but it takes {}",
kind,
expected_str,
found_str,
);
- err.span_label(
- span,
- format!(
- "expected {} that takes {}",
- kind,
- expected_str,
- )
- );
-
- if let Some(span) = found_span {
- if let (Some(expected_tuple), Some((pats, tys))) = (expected_tuple, closure_args) {
- if expected_tuple != found || pats.len() != found {
- err.span_label(span, format!("takes {}", found_str));
- } else {
- let sugg = format!(
- "|({}){}|",
- pats.join(", "),
-
- // add type annotations if available
- if tys.iter().any(|ty| ty.is_some()) {
- Cow::from(format!(
- ": ({})",
- tys.into_iter().map(|ty| if let Some(ty) = ty {
- ty
- } else {
- "_".to_string()
- }).collect::<Vec<String>>().join(", ")
- ))
- } else {
- Cow::from("")
- },
- );
-
- err.span_suggestion(
- span,
- "consider changing the closure to accept a tuple",
- sugg
- );
- }
- } else {
- err.span_label(span, format!("takes {}", found_str));
+ err.span_label(span, format!( "expected {} that takes {}", kind, expected_str));
+ err.span_label(found_span, format!("takes {}", found_str));
+
+ if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
+ if fields.len() == expected_args.len() {
+ let sugg = fields.iter()
+ .map(|(name, _)| name.to_owned())
+ .collect::<Vec<String>>().join(", ");
+ err.span_suggestion(found_span,
+ "change the closure to take multiple arguments instead of \
+ a single tuple",
+ format!("|{}|", sugg));
+ }
+ }
+ if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] {
+ if fields.len() == found_args.len() && is_closure {
+ let sugg = format!(
+ "|({}){}|",
+ found_args.iter()
+ .map(|arg| match arg {
+ ArgKind::Arg(name, _) => name.to_owned(),
+ _ => "_".to_owned(),
+ })
+ .collect::<Vec<String>>()
+ .join(", "),
+ // add type annotations if available
+ if found_args.iter().any(|arg| match arg {
+ ArgKind::Arg(_, ty) => ty != "_",
+ _ => false,
+ }) {
+ format!(": ({})",
+ fields.iter()
+ .map(|(_, ty)| ty.to_owned())
+ .collect::<Vec<String>>()
+ .join(", "))
+ } else {
+ "".to_owned()
+ },
+ );
+ err.span_suggestion(found_span,
+ "change the closure to accept a tuple instead of individual \
+ arguments",
+ sugg);
}
}
suggested_limit));
}
}
+
+enum ArgKind {
+ Arg(String, String),
+ Tuple(Span, Vec<(String, String)>),
+}
+
+impl ArgKind {
+ fn empty() -> ArgKind {
+ ArgKind::Arg("_".to_owned(), "_".to_owned())
+ }
+}
use hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use hir::map::DefPathData;
use hir::svh::Svh;
+use ich::Fingerprint;
use ich::StableHashingContext;
use middle::const_val::ConstVal;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
use serialize::{self, Encodable, Encoder};
+use std::cell::RefCell;
use std::collections::BTreeMap;
use std::cmp;
use std::fmt;
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
- let ty::AdtDef {
- did,
- ref variants,
- ref flags,
- ref repr,
- } = *self;
+ thread_local! {
+ static CACHE: RefCell<FxHashMap<usize, Fingerprint>> =
+ RefCell::new(FxHashMap());
+ }
+
+ let hash: Fingerprint = CACHE.with(|cache| {
+ let addr = self as *const AdtDef as usize;
+ *cache.borrow_mut().entry(addr).or_insert_with(|| {
+ let ty::AdtDef {
+ did,
+ ref variants,
+ ref flags,
+ ref repr,
+ } = *self;
- did.hash_stable(hcx, hasher);
- variants.hash_stable(hcx, hasher);
- flags.hash_stable(hcx, hasher);
- repr.hash_stable(hcx, hasher);
+ let mut hasher = StableHasher::new();
+ did.hash_stable(hcx, &mut hasher);
+ variants.hash_stable(hcx, &mut hasher);
+ flags.hash_stable(hcx, &mut hasher);
+ repr.hash_stable(hcx, &mut hasher);
+
+ hasher.finish()
+ })
+ });
+
+ hash.hash_stable(hcx, hasher);
}
}
const IS_C = 1 << 0;
const IS_PACKED = 1 << 1;
const IS_SIMD = 1 << 2;
+ const IS_TRANSPARENT = 1 << 3;
// Internal only for now. If true, don't reorder fields.
- const IS_LINEAR = 1 << 3;
+ const IS_LINEAR = 1 << 4;
// Any of these flags being set prevent field reordering optimisation.
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits |
flags.insert(match r {
attr::ReprC => ReprFlags::IS_C,
attr::ReprPacked => ReprFlags::IS_PACKED,
+ attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
attr::ReprSimd => ReprFlags::IS_SIMD,
attr::ReprInt(i) => {
size = Some(i);
#[inline]
pub fn packed(&self) -> bool { self.flags.contains(ReprFlags::IS_PACKED) }
#[inline]
+ pub fn transparent(&self) -> bool { self.flags.contains(ReprFlags::IS_TRANSPARENT) }
+ #[inline]
pub fn linear(&self) -> bool { self.flags.contains(ReprFlags::IS_LINEAR) }
pub fn discr_type(&self) -> attr::IntType {
let max_change = S::MAX_EXP as i32 - (S::MIN_EXP as i32 - sig_bits) + 1;
// Clamp to one past the range ends to let normalize handle overflow.
- let exp_change = cmp::min(cmp::max(exp as i32, (-max_change - 1)), max_change);
+ let exp_change = cmp::min(cmp::max(exp as i32, -max_change - 1), max_change);
self.exp = self.exp.saturating_add(exp_change as ExpInt);
self = self.normalize(round, Loss::ExactlyZero).value;
if self.is_nan() {
let mut base = super::cloudabi_base::opts();
base.max_atomic_width = Some(128);
base.abi_blacklist = super::arm_base::abi_blacklist();
+ base.linker = "aarch64-unknown-cloudabi-cc".to_string();
Ok(Target {
llvm_target: "aarch64-unknown-cloudabi".to_string(),
base.max_atomic_width = Some(64);
base.features = "+v7,+vfp3,+neon".to_string();
base.abi_blacklist = super::arm_base::abi_blacklist();
+ base.linker = "armv7-unknown-cloudabi-eabihf-cc".to_string();
Ok(Target {
llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(),
let mut base = super::cloudabi_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
+ base.linker = "i686-unknown-cloudabi-cc".to_string();
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
base.stack_probes = true;
let mut base = super::cloudabi_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
+ base.linker = "x86_64-unknown-cloudabi-cc".to_string();
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.stack_probes = true;
/// (1) all_constructors will only return constructors that are statically
/// possible. eg. it will only return Ok for Result<T, !>
///
-/// Whether a vector `v` of patterns is 'useful' in relation to a set of such
-/// vectors `m` is defined as there being a set of inputs that will match `v`
-/// but not any of the sets in `m`.
+/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
+/// to a set of such vectors `m` - this is defined as there being a set of
+/// inputs that will match `v` but not any of the sets in `m`.
+///
+/// All the patterns at each column of the `matrix ++ v` matrix must
+/// have the same type, except that wildcard (PatternKind::Wild) patterns
+/// with type TyErr are also allowed, even if the "type of the column"
+/// is not TyErr. That is used to represent private fields, as using their
+/// real type would assert that they are inhabited.
///
/// This is used both for reachability checking (if a pattern isn't useful in
/// relation to preceding patterns, it is not reachable) and exhaustiveness
/// checking (if a wildcard pattern is useful in relation to a matrix, the
/// matrix isn't exhaustive).
pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
- matrix: &Matrix<'p, 'tcx>,
- v: &[&'p Pattern<'tcx>],
- witness: WitnessPreference)
- -> Usefulness<'tcx> {
+ matrix: &Matrix<'p, 'tcx>,
+ v: &[&'p Pattern<'tcx>],
+ witness: WitnessPreference)
+ -> Usefulness<'tcx> {
let &Matrix(ref rows) = matrix;
debug!("is_useful({:?}, {:?})", matrix, v);
assert!(rows.iter().all(|r| r.len() == v.len()));
let pcx = PatternContext {
+ // TyErr is used to represent the type of wildcard patterns matching
+ // against inaccessible (private) fields of structs, so that we won't
+ // be able to observe whether the types of the struct's fields are
+ // inhabited.
+ //
+ // If the field is truely inaccessible, then all the patterns
+ // matching against it must be wildcard patterns, so its type
+ // does not matter.
+ //
+ // However, if we are matching against non-wildcard patterns, we
+ // need to know the real type of the field so we can specialize
+ // against it. This primarily occurs through constants - they
+ // can include contents for fields that are inaccessible at the
+ // location of the match. In that case, the field's type is
+ // inhabited - by the constant - so we can just use it.
+ //
+ // FIXME: this might lead to "unstable" behavior with macro hygiene
+ // introducing uninhabited patterns for inaccessible fields. We
+ // need to figure out how to model that.
ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
.unwrap_or(v[0].ty),
max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0])))
if is_visible {
field.ty(cx.tcx, substs)
} else {
- // Treat all non-visible fields as nil. They
+ // Treat all non-visible fields as TyErr. They
// can't appear in any other pattern from
// this match (because they are private),
// so their type does not matter - but
// we don't want to know they are
// uninhabited.
- cx.tcx.mk_nil()
+ cx.tcx.types.err
}
}).collect()
}
use std::marker::Unsize;
use std::iter::Extend;
-use std::ptr::{self, drop_in_place, Shared};
+use std::ptr::{self, drop_in_place, NonNull};
use std::ops::{Deref, DerefMut, Range};
use std::hash::{Hash, Hasher};
use std::slice;
tail_start: end,
tail_len: len - end,
iter: range_slice.iter(),
- array_vec: Shared::from(self),
+ array_vec: NonNull::from(self),
}
}
}
tail_start: usize,
tail_len: usize,
iter: slice::Iter<'a, ManuallyDrop<A::Element>>,
- array_vec: Shared<ArrayVec<A>>,
+ array_vec: NonNull<ArrayVec<A>>,
}
impl<'a, A: Array> Iterator for Drain<'a, A> {
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]
-#![feature(shared)]
#![feature(collections_range)]
#![feature(nonzero)]
#![feature(unboxed_closures)]
use rustc_resolve::{MakeGlobMap, Resolver};
use rustc_metadata::creader::CrateLoader;
use rustc_metadata::cstore::{self, CStore};
-use rustc_trans as trans;
use rustc_trans_utils::trans_crate::TransCrate;
use rustc_typeck as typeck;
use rustc_privacy;
use rustc_passes::{self, ast_validation, loops, consts, static_recursion, hir_stats};
use rustc_const_eval::{self, check_match};
use super::Compilation;
-use ::DefaultTransCrate;
use serialize::json;
use profile;
-pub fn compile_input(sess: &Session,
+pub fn compile_input(trans: Box<TransCrate>,
+ sess: &Session,
cstore: &CStore,
input_path: &Option<PathBuf>,
input: &Input,
output: &Option<PathBuf>,
addl_plugins: Option<Vec<String>>,
control: &CompileController) -> CompileResult {
- use rustc::session::config::CrateType;
-
macro_rules! controller_entry_point {
($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{
let state = &mut $make_state;
}}
}
- if cfg!(not(feature="llvm")) {
- for cty in sess.opts.crate_types.iter() {
- match *cty {
- CrateType::CrateTypeRlib | CrateType::CrateTypeDylib |
- CrateType::CrateTypeExecutable => {},
- _ => {
- sess.parse_sess.span_diagnostic.warn(
- &format!("LLVM unsupported, so output type {} is not supported", cty)
- );
- },
- }
- }
-
- sess.abort_if_errors();
- }
-
if sess.profile_queries() {
profile::begin();
}
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
- let (outputs, trans, dep_graph) = {
+ let (outputs, ongoing_trans, dep_graph) = {
let krate = match phase_1_parse_input(control, sess, input) {
Ok(krate) => krate,
Err(mut parse_error) => {
None
};
- phase_3_run_analysis_passes(control,
+ phase_3_run_analysis_passes(&*trans,
+ control,
sess,
cstore,
hir_map,
tcx.print_debug_stats();
}
- let trans = phase_4_translate_to_llvm::<DefaultTransCrate>(tcx, rx);
+ let ongoing_trans = phase_4_translate_to_llvm(&*trans, tcx, rx);
if log_enabled!(::log::Level::Info) {
println!("Post-trans");
}
}
- Ok((outputs.clone(), trans, tcx.dep_graph.clone()))
+ Ok((outputs.clone(), ongoing_trans, tcx.dep_graph.clone()))
})??
};
sess.code_stats.borrow().print_type_sizes();
}
- let (phase5_result, trans) =
- phase_5_run_llvm_passes::<DefaultTransCrate>(sess, &dep_graph, trans);
-
- controller_entry_point!(after_llvm,
- sess,
- CompileState::state_after_llvm(input, sess, outdir, output, &trans),
- phase5_result);
- phase5_result?;
-
- // Run the linker on any artifacts that resulted from the LLVM run.
- // This should produce either a finished executable or library.
- time(sess.time_passes(), "linking", || {
- DefaultTransCrate::link_binary(sess, &trans, &outputs)
- });
-
- // Now that we won't touch anything in the incremental compilation directory
- // any more, we can finalize it (which involves renaming it)
- #[cfg(feature="llvm")]
- rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
+ trans.join_trans_and_link(ongoing_trans, sess, &dep_graph, &outputs)?;
if sess.opts.debugging_opts.perf_stats {
sess.print_perf_stats();
pub after_expand: PhaseController<'a>,
pub after_hir_lowering: PhaseController<'a>,
pub after_analysis: PhaseController<'a>,
- pub after_llvm: PhaseController<'a>,
pub compilation_done: PhaseController<'a>,
// FIXME we probably want to group the below options together and offer a
after_expand: PhaseController::basic(),
after_hir_lowering: PhaseController::basic(),
after_analysis: PhaseController::basic(),
- after_llvm: PhaseController::basic(),
compilation_done: PhaseController::basic(),
make_glob_map: MakeGlobMap::No,
keep_ast: false,
pub resolutions: Option<&'a Resolutions>,
pub analysis: Option<&'a ty::CrateAnalysis>,
pub tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
- pub trans: Option<&'a trans::CrateTranslation>,
}
impl<'a, 'tcx> CompileState<'a, 'tcx> {
resolutions: None,
analysis: None,
tcx: None,
- trans: None,
}
}
}
}
- fn state_after_llvm(input: &'a Input,
- session: &'tcx Session,
- out_dir: &'a Option<PathBuf>,
- out_file: &'a Option<PathBuf>,
- trans: &'a trans::CrateTranslation)
- -> Self {
- CompileState {
- trans: Some(trans),
- out_file: out_file.as_ref().map(|s| &**s),
- ..CompileState::empty(input, session, out_dir)
- }
- }
-
fn state_when_compilation_done(input: &'a Input,
session: &'tcx Session,
out_dir: &'a Option<PathBuf>,
reachable::provide(providers);
resolve_lifetime::provide(providers);
rustc_privacy::provide(providers);
- DefaultTransCrate::provide(providers);
typeck::provide(providers);
ty::provide(providers);
traits::provide(providers);
pub fn default_provide_extern(providers: &mut ty::maps::Providers) {
cstore::provide_extern(providers);
- DefaultTransCrate::provide_extern(providers);
}
/// Run the resolution, typechecking, region checking and other
/// miscellaneous analysis passes on the crate. Return various
/// structures carrying the results of the analysis.
-pub fn phase_3_run_analysis_passes<'tcx, F, R>(control: &CompileController,
+pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate,
+ control: &CompileController,
sess: &'tcx Session,
cstore: &'tcx CrateStore,
hir_map: hir_map::Map<'tcx>,
let mut local_providers = ty::maps::Providers::default();
default_provide(&mut local_providers);
+ trans.provide(&mut local_providers);
(control.provide)(&mut local_providers);
let mut extern_providers = local_providers;
default_provide_extern(&mut extern_providers);
+ trans.provide_extern(&mut extern_providers);
(control.provide_extern)(&mut extern_providers);
let (tx, rx) = mpsc::channel();
/// Run the translation phase to LLVM, after which the AST and analysis can
/// be discarded.
-pub fn phase_4_translate_to_llvm<'a, 'tcx, Trans: TransCrate>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+pub fn phase_4_translate_to_llvm<'a, 'tcx>(trans: &TransCrate,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
rx: mpsc::Receiver<Box<Any + Send>>)
- -> <Trans as TransCrate>::OngoingCrateTranslation {
+ -> Box<Any> {
let time_passes = tcx.sess.time_passes();
time(time_passes,
let translation =
time(time_passes, "translation", move || {
- Trans::trans_crate(tcx, rx)
+ trans.trans_crate(tcx, rx)
});
if tcx.sess.profile_queries() {
profile::dump("profile_queries".to_string())
translation
}
-/// Run LLVM itself, producing a bitcode file, assembly file or object file
-/// as a side effect.
-pub fn phase_5_run_llvm_passes<Trans: TransCrate>(sess: &Session,
- dep_graph: &DepGraph,
- trans: <Trans as TransCrate>::OngoingCrateTranslation)
- -> (CompileResult, <Trans as TransCrate>::TranslatedCrate) {
- let trans = Trans::join_trans(trans, sess, dep_graph);
-
- if sess.opts.debugging_opts.incremental_info {
- Trans::dump_incremental_data(&trans);
- }
-
- time(sess.time_passes(),
- "serialize work products",
- move || rustc_incremental::save_work_products(sess, dep_graph));
-
- (sess.compile_status(), trans)
-}
-
fn escape_dep_filename(filename: &FileName) -> String {
// Apparently clang and gcc *only* escape spaces:
// http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
extern crate rustc_resolve;
extern crate rustc_save_analysis;
#[cfg(feature="llvm")]
-extern crate rustc_trans;
+pub extern crate rustc_trans;
extern crate rustc_trans_utils;
extern crate rustc_typeck;
extern crate serialize;
use rustc_save_analysis::DumpHandler;
use rustc::session::{self, config, Session, build_session, CompileResult};
use rustc::session::CompileIncomplete;
-use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
+use rustc::session::config::{Input, PrintRequest, ErrorOutputType};
use rustc::session::config::nightly_options;
use rustc::session::{early_error, early_warn};
use rustc::lint::Lint;
pub mod profile;
pub mod driver;
pub mod pretty;
-pub mod target_features;
mod derive_registrar;
+pub mod target_features {
+ use syntax::ast;
+ use syntax::symbol::Symbol;
+ use rustc::session::Session;
+ use rustc_trans_utils::trans_crate::TransCrate;
+
+ /// Add `target_feature = "..."` cfgs for a variety of platform
+ /// specific features (SSE, NEON etc.).
+ ///
+ /// This is performed by checking whether a whitelisted set of
+ /// features is available on the target machine, by querying LLVM.
+ pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session, trans: &TransCrate) {
+ let tf = Symbol::intern("target_feature");
+
+ for feat in trans.target_features(sess) {
+ cfg.insert((tf, Some(feat)));
+ }
+
+ if sess.crt_static_feature() {
+ cfg.insert((tf, Some(Symbol::intern("crt-static"))));
+ }
+ }
+}
+
const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
md#bug-reports";
pub use rustc_trans::LlvmTransCrate as DefaultTransCrate;
#[cfg(not(feature="llvm"))]
-mod rustc_trans {
- use syntax_pos::symbol::Symbol;
- use rustc::session::Session;
- use rustc::session::config::PrintRequest;
+pub mod rustc_trans {
pub use rustc_trans_utils::trans_crate::MetadataOnlyTransCrate as LlvmTransCrate;
- pub use rustc_trans_utils::trans_crate::TranslatedCrate as CrateTranslation;
- pub fn init(_sess: &Session) {}
pub fn print_version() {}
pub fn print_passes() {}
- pub fn print(_req: PrintRequest, _sess: &Session) {}
- pub fn target_features(_sess: &Session) -> Vec<Symbol> { vec![] }
-
- pub mod back {
- pub mod write {
- pub const RELOC_MODEL_ARGS: [(&'static str, ()); 0] = [];
- pub const CODE_GEN_MODEL_ARGS: [(&'static str, ()); 0] = [];
- pub const TLS_MODEL_ARGS: [(&'static str, ()); 0] = [];
+}
+
+fn load_backend_from_dylib(sess: &Session, backend_name: &str) -> Box<TransCrate> {
+ use std::path::Path;
+ use rustc_metadata::dynamic_lib::DynamicLibrary;
+
+ match DynamicLibrary::open(Some(Path::new(backend_name))) {
+ Ok(lib) => {
+ unsafe {
+ let trans = {
+ let __rustc_codegen_backend: unsafe fn(&Session) -> Box<TransCrate>;
+ __rustc_codegen_backend = match lib.symbol("__rustc_codegen_backend") {
+ Ok(f) => ::std::mem::transmute::<*mut u8, _>(f),
+ Err(e) => sess.fatal(&format!("Couldnt load codegen backend as it\
+ doesn't export the __rustc_backend_new symbol: {:?}", e)),
+ };
+ __rustc_codegen_backend(sess)
+ };
+ ::std::mem::forget(lib);
+ trans
+ }
+ }
+ Err(err) => {
+ sess.fatal(&format!("Couldnt load codegen backend {:?}: {:?}", backend_name, err));
+ }
+ }
+}
+
+pub fn get_trans(sess: &Session) -> Box<TransCrate> {
+ let trans_name = sess.opts.debugging_opts.codegen_backend.clone();
+ match trans_name.as_ref().map(|s|&**s) {
+ None => DefaultTransCrate::new(&sess),
+ Some("llvm") => rustc_trans::LlvmTransCrate::new(&sess),
+ Some("metadata_only") => {
+ rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new(&sess)
+ }
+ Some(filename) if filename.contains(".") => {
+ load_backend_from_dylib(&sess, &filename)
}
+ Some(trans_name) => sess.fatal(&format!("Unknown codegen backend {}", trans_name)),
}
}
},
};
- let cstore = CStore::new(DefaultTransCrate::metadata_loader());
-
let loader = file_loader.unwrap_or(box RealFileLoader);
let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
let mut sess = session::build_session_with_codemap(
sopts, input_file_path.clone(), descriptions, codemap, emitter_dest,
);
- rustc_trans::init(&sess);
+
+ let trans = get_trans(&sess);
+
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let mut cfg = config::build_configuration(&sess, cfg);
- target_features::add_configuration(&mut cfg, &sess);
+ target_features::add_configuration(&mut cfg, &sess, &*trans);
sess.parse_sess.config = cfg;
- do_or_return!(callbacks.late_callback(&matches,
+ let plugins = sess.opts.debugging_opts.extra_plugins.clone();
+
+ let cstore = CStore::new(trans.metadata_loader());
+
+ do_or_return!(callbacks.late_callback(&*trans,
+ &matches,
&sess,
&cstore,
&input,
&odir,
&ofile), Some(sess));
- let plugins = sess.opts.debugging_opts.extra_plugins.clone();
let control = callbacks.build_controller(&sess, &matches);
- (driver::compile_input(&sess,
+
+ (driver::compile_input(trans,
+ &sess,
&cstore,
&input_file_path,
&input,
// be called just before actual compilation starts (and before build_controller
// is called), after all arguments etc. have been completely handled.
fn late_callback(&mut self,
+ _: &TransCrate,
_: &getopts::Matches,
_: &Session,
_: &CrateStore,
let mut sess = build_session(sopts.clone(),
None,
descriptions.clone());
- rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let mut cfg = config::build_configuration(&sess, cfg.clone());
- target_features::add_configuration(&mut cfg, &sess);
+ let trans = get_trans(&sess);
+ target_features::add_configuration(&mut cfg, &sess, &*trans);
sess.parse_sess.config = cfg;
- let should_stop =
- RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile);
+ let should_stop = RustcDefaultCalls::print_crate_info(
+ &*trans,
+ &sess,
+ None,
+ odir,
+ ofile
+ );
if should_stop == Compilation::Stop {
return None;
}
fn late_callback(&mut self,
+ trans: &TransCrate,
matches: &getopts::Matches,
sess: &Session,
cstore: &CrateStore,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>)
-> Compilation {
- RustcDefaultCalls::print_crate_info(sess, Some(input), odir, ofile)
+ RustcDefaultCalls::print_crate_info(trans, sess, Some(input), odir, ofile)
.and_then(|| RustcDefaultCalls::list_metadata(sess, cstore, matches, input))
}
control.after_hir_lowering.stop = Compilation::Stop;
}
- if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
- i == OutputType::Metadata) {
- control.after_llvm.stop = Compilation::Stop;
- }
-
if save_analysis(sess) {
enable_save_analysis(&mut control);
}
}
- fn print_crate_info(sess: &Session,
+ fn print_crate_info(trans: &TransCrate,
+ sess: &Session,
input: Option<&Input>,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>)
-> Compilation {
+ use rustc::session::config::PrintRequest::*;
// PrintRequest::NativeStaticLibs is special - printed during linking
// (empty iterator returns true)
if sess.opts.prints.iter().all(|&p| p==PrintRequest::NativeStaticLibs) {
};
for req in &sess.opts.prints {
match *req {
- PrintRequest::TargetList => {
+ TargetList => {
let mut targets = rustc_back::target::get_targets().collect::<Vec<String>>();
targets.sort();
println!("{}", targets.join("\n"));
},
- PrintRequest::Sysroot => println!("{}", sess.sysroot().display()),
- PrintRequest::TargetSpec => println!("{}", sess.target.target.to_json().pretty()),
- PrintRequest::FileNames |
- PrintRequest::CrateName => {
+ Sysroot => println!("{}", sess.sysroot().display()),
+ TargetSpec => println!("{}", sess.target.target.to_json().pretty()),
+ FileNames | CrateName => {
let input = match input {
Some(input) => input,
None => early_error(ErrorOutputType::default(), "no input file provided"),
.to_string_lossy());
}
}
- PrintRequest::Cfg => {
+ Cfg => {
let allow_unstable_cfg = UnstableFeatures::from_environment()
.is_nightly_build();
println!("{}", cfg);
}
}
- PrintRequest::RelocationModels => {
- println!("Available relocation models:");
- for &(name, _) in rustc_trans::back::write::RELOC_MODEL_ARGS.iter() {
- println!(" {}", name);
- }
- println!("");
- }
- PrintRequest::CodeModels => {
- println!("Available code models:");
- for &(name, _) in rustc_trans::back::write::CODE_GEN_MODEL_ARGS.iter(){
- println!(" {}", name);
- }
- println!("");
- }
- PrintRequest::TlsModels => {
- println!("Available TLS models:");
- for &(name, _) in rustc_trans::back::write::TLS_MODEL_ARGS.iter(){
- println!(" {}", name);
- }
- println!("");
- }
- PrintRequest::TargetCPUs | PrintRequest::TargetFeatures => {
- rustc_trans::print(*req, sess);
+ RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => {
+ trans.print(*req, sess);
}
// Any output here interferes with Cargo's parsing of other printed output
PrintRequest::NativeStaticLibs => {}
all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
#[cfg(feature="llvm")]
all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
+ all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
}
PpmTyped => {
let control = &driver::CompileController::basic();
- abort_on_err(driver::phase_3_run_analysis_passes(control,
+ abort_on_err(driver::phase_3_run_analysis_passes(&*::DefaultTransCrate::new(&sess),
+ control,
sess,
cstore,
hir_map.clone(),
let mut out = Vec::new();
let control = &driver::CompileController::basic();
- abort_on_err(driver::phase_3_run_analysis_passes(control,
+ abort_on_err(driver::phase_3_run_analysis_passes(&*::DefaultTransCrate::new(&sess),
+ control,
sess,
cstore,
hir_map.clone(),
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use syntax::ast;
-use rustc::session::Session;
-use syntax::symbol::Symbol;
-use rustc_trans;
-
-/// Add `target_feature = "..."` cfgs for a variety of platform
-/// specific features (SSE, NEON etc.).
-///
-/// This is performed by checking whether a whitelisted set of
-/// features is available on the target machine, by querying LLVM.
-pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session) {
- let tf = Symbol::intern("target_feature");
-
- for feat in rustc_trans::target_features(sess) {
- cfg.insert((tf, Some(feat)));
- }
-
- if sess.crt_static_feature() {
- cfg.insert((tf, Some(Symbol::intern("crt-static"))));
- }
-}
use driver;
use rustc_lint;
use rustc_resolve::MakeGlobMap;
-use rustc_trans;
use rustc::middle::region;
use rustc::ty::subst::{Kind, Subst};
use rustc::traits::{ObligationCause, Reveal};
use rustc::hir::map as hir_map;
use rustc::session::{self, config};
use rustc::session::config::{OutputFilenames, OutputTypes};
-use rustc_trans_utils::trans_crate::TransCrate;
use std::rc::Rc;
use syntax::ast;
use syntax::abi::Abi;
options.unstable_features = UnstableFeatures::Allow;
let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
- let cstore = Rc::new(CStore::new(::DefaultTransCrate::metadata_loader()));
let sess = session::build_session_(options,
None,
diagnostic_handler,
Rc::new(CodeMap::new(FilePathMapping::empty())));
- rustc_trans::init(&sess);
+ let cstore = Rc::new(CStore::new(::get_trans(&sess).metadata_loader()));
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let input = config::Input::Str {
name: FileName::Anon,
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This pass is only used for UNIT TESTS related to incremental
+//! compilation. It tests whether a particular `.o` file will be re-used
+//! from a previous compilation or whether it must be regenerated.
+//!
+//! The user adds annotations to the crate of the following form:
+//!
+//! ```
+//! #![rustc_partition_reused(module="spike", cfg="rpass2")]
+//! #![rustc_partition_translated(module="spike-x", cfg="rpass2")]
+//! ```
+//!
+//! The first indicates (in the cfg `rpass2`) that `spike.o` will be
+//! reused, the second that `spike-x.o` will be recreated. If these
+//! annotations are inaccurate, errors are reported.
+//!
+//! The reason that we use `cfg=...` and not `#[cfg_attr]` is so that
+//! the HIR doesn't change as a result of the annotations, which might
+//! perturb the reuse results.
+
+use rustc::dep_graph::{DepNode, DepConstructor};
+use rustc::mir::mono::CodegenUnit;
+use rustc::ty::TyCtxt;
+use syntax::ast;
+use syntax_pos::symbol::Symbol;
+use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED};
+
+const MODULE: &'static str = "module";
+const CFG: &'static str = "cfg";
+
+#[derive(Debug, PartialEq, Clone, Copy)]
+enum Disposition { Reused, Translated }
+
+pub fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ tcx.dep_graph.with_ignore(|| {
+ if tcx.sess.opts.incremental.is_none() {
+ return;
+ }
+
+ let ams = AssertModuleSource { tcx };
+ for attr in &tcx.hir.krate().attrs {
+ ams.check_attr(attr);
+ }
+ })
+}
+
+struct AssertModuleSource<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
+ fn check_attr(&self, attr: &ast::Attribute) {
+ let disposition = if attr.check_name(ATTR_PARTITION_REUSED) {
+ Disposition::Reused
+ } else if attr.check_name(ATTR_PARTITION_TRANSLATED) {
+ Disposition::Translated
+ } else {
+ return;
+ };
+
+ if !self.check_config(attr) {
+ debug!("check_attr: config does not match, ignoring attr");
+ return;
+ }
+
+ let mname = self.field(attr, MODULE);
+ let mangled_cgu_name = CodegenUnit::mangle_name(&mname.as_str());
+ let mangled_cgu_name = Symbol::intern(&mangled_cgu_name).as_str();
+
+ let dep_node = DepNode::new(self.tcx,
+ DepConstructor::CompileCodegenUnit(mangled_cgu_name));
+
+ if let Some(loaded_from_cache) = self.tcx.dep_graph.was_loaded_from_cache(&dep_node) {
+ match (disposition, loaded_from_cache) {
+ (Disposition::Reused, false) => {
+ self.tcx.sess.span_err(
+ attr.span,
+ &format!("expected module named `{}` to be Reused but is Translated",
+ mname));
+ }
+ (Disposition::Translated, true) => {
+ self.tcx.sess.span_err(
+ attr.span,
+ &format!("expected module named `{}` to be Translated but is Reused",
+ mname));
+ }
+ (Disposition::Reused, true) |
+ (Disposition::Translated, false) => {
+ // These are what we would expect.
+ }
+ }
+ } else {
+ self.tcx.sess.span_err(attr.span, &format!("no module named `{}`", mname));
+ }
+ }
+
+ fn field(&self, attr: &ast::Attribute, name: &str) -> ast::Name {
+ for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
+ if item.check_name(name) {
+ if let Some(value) = item.value_str() {
+ return value;
+ } else {
+ self.tcx.sess.span_fatal(
+ item.span,
+ &format!("associated value expected for `{}`", name));
+ }
+ }
+ }
+
+ self.tcx.sess.span_fatal(
+ attr.span,
+ &format!("no field `{}`", name));
+ }
+
+ /// Scan for a `cfg="foo"` attribute and check whether we have a
+ /// cfg flag called `foo`.
+ fn check_config(&self, attr: &ast::Attribute) -> bool {
+ let config = &self.tcx.sess.parse_sess.config;
+ let value = self.field(attr, CFG);
+ debug!("check_config(config={:?}, value={:?})", config, value);
+ if config.iter().any(|&(name, _)| name == value) {
+ debug!("check_config: matched");
+ return true;
+ }
+ debug!("check_config: no match found");
+ return false;
+ }
+
+}
extern crate syntax_pos;
mod assert_dep_graph;
+pub mod assert_module_sources;
mod persist;
pub use assert_dep_graph::assert_dep_graph;
}
match def.adt_kind() {
AdtKind::Struct => {
- if !def.repr.c() {
+ if !def.repr.c() && !def.repr.transparent() {
return FfiUnsafe("found struct without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type");
adding a member to this struct");
}
- // We can't completely trust repr(C) markings; make sure the
- // fields are actually safe.
+ // We can't completely trust repr(C) and repr(transparent) markings;
+ // make sure the fields are actually safe.
let mut all_phantom = true;
for field in &def.non_enum_variant().fields {
let field_ty = cx.fully_normalize_associated_types_in(
&field.ty(cx, substs)
);
+ // repr(transparent) types are allowed to have arbitrary ZSTs, not just
+ // PhantomData -- skip checking all ZST fields
+ if def.repr.transparent() {
+ let is_zst = (cx, cx.param_env(field.did))
+ .layout_of(field_ty)
+ .map(|layout| layout.is_zst())
+ .unwrap_or(false);
+ if is_zst {
+ continue;
+ }
+ }
let r = self.check_type_for_ffi(cache, field_ty);
match r {
FfiSafe => {
Assign(_, ref value) => (value, "assigned value", false),
AssignOp(.., ref value) => (value, "assigned value", false),
InPlace(_, ref value) => (value, "emplacement value", false),
+ Call(_, ref args) => {
+ for arg in args {
+ self.check_unused_parens_core(cx, arg, "function argument", false)
+ }
+ return;
+ },
+ MethodCall(_, ref args) => {
+ for arg in &args[1..] { // first "argument" is self (which sometimes needs parens)
+ self.check_unused_parens_core(cx, arg, "method argument", false)
+ }
+ return;
+ }
_ => return,
};
self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
use native_libs::relevant_lib;
use schema::CrateRoot;
-use rustc::hir::def_id::{CrateNum, DefIndex, CRATE_DEF_INDEX};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX};
use rustc::hir::svh::Svh;
use rustc::middle::allocator::AllocatorKind;
use rustc::middle::cstore::DepKind;
Err(err) => self.sess.span_fatal(span, &err),
};
- let sym = self.sess.generate_derive_registrar_symbol(root.disambiguator,
- root.macro_derive_registrar.unwrap());
+ let sym = self.sess.generate_derive_registrar_symbol(root.disambiguator);
let registrar = unsafe {
let sym = match lib.symbol(&sym) {
Ok(f) => f,
pub fn find_plugin_registrar(&mut self,
span: Span,
name: &str)
- -> Option<(PathBuf, CrateDisambiguator, DefIndex)> {
+ -> Option<(PathBuf, CrateDisambiguator)> {
let name = Symbol::intern(name);
let ekrate = self.read_extension_crate(span, name, name);
}
let root = ekrate.metadata.get_root();
- match (ekrate.dylib.as_ref(), root.plugin_registrar_fn) {
- (Some(dylib), Some(reg)) => {
- Some((dylib.to_path_buf(), root.disambiguator, reg))
+ match ekrate.dylib.as_ref() {
+ Some(dylib) => {
+ Some((dylib.to_path_buf(), root.disambiguator))
}
- (None, Some(_)) => {
+ None => {
span_err!(self.sess, span, E0457,
"plugin `{}` only found in rlib format, but must be available \
in dylib format",
// empty dylib.
None
}
- _ => None,
}
}
syntax_pos = { path = "../libsyntax_pos" }
byteorder = { version = "1.1", features = ["i128"] }
rustc_apfloat = { path = "../librustc_apfloat" }
-rustc_trans_utils = { path = "../librustc_trans_utils" }
fn visit_ty(&mut self, ty: &ty::Ty<'tcx>, ty_context: TyContext) {
match ty_context {
TyContext::ReturnTy(source_info) |
+ TyContext::YieldTy(source_info) |
TyContext::LocalDecl { source_info, .. } => {
span_bug!(source_info.span,
"should not be visiting outside of the CFG: {:?}",
if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
let tables = infcx.tcx.typeck_tables_of(mir_def_id);
- let nice = NiceRegionError::new(infcx.tcx, blame_span, o, f, Some(tables));
+ let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables));
if let Some(ErrorReported) = nice.try_report() {
return;
}
// except according to those terms.
use rustc::ty::subst::Substs;
-use rustc::ty::{self, ClosureSubsts, Ty, TypeFoldable};
+use rustc::ty::{self, ClosureSubsts, GeneratorInterior, Ty, TypeFoldable};
use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
*constant = self.renumber_regions(ty_context, &*constant);
}
+ fn visit_generator_interior(&mut self,
+ interior: &mut GeneratorInterior<'tcx>,
+ location: Location) {
+ debug!(
+ "visit_generator_interior(interior={:?}, location={:?})",
+ interior,
+ location,
+ );
+
+ let ty_context = TyContext::Location(location);
+ *interior = self.renumber_regions(ty_context, interior);
+
+ debug!("visit_generator_interior: interior={:?}", interior);
+ }
+
fn visit_closure_substs(&mut self, substs: &mut ClosureSubsts<'tcx>, location: Location) {
debug!(
"visit_closure_substs(substs={:?}, location={:?})",
self.equate_normalized_input_or_output(start_position, input_ty, mir_input_ty);
}
+ assert!(
+ mir.yield_ty.is_some() && universal_regions.yield_ty.is_some() ||
+ mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
+ );
+ if let Some(mir_yield_ty) = mir.yield_ty {
+ let ur_yield_ty = universal_regions.yield_ty.unwrap();
+ self.equate_normalized_input_or_output(start_position, ur_yield_ty, mir_yield_ty);
+ }
+
// Return types are a bit more complex. They may contain existential `impl Trait`
// types.
debug!(
/// our special inference variable there, we would mess that up.
pub region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
+ pub yield_ty: Option<Ty<'tcx>>,
+
relations: UniversalRegionRelations,
}
num_universals
);
+ let yield_ty = match defining_ty {
+ DefiningTy::Generator(def_id, substs, _) => {
+ Some(substs.generator_yield_ty(def_id, self.infcx.tcx))
+ }
+ _ => None,
+ };
+
UniversalRegions {
indices,
fr_static,
unnormalized_output_ty,
unnormalized_input_tys,
region_bound_pairs: self.region_bound_pairs,
+ yield_ty: yield_ty,
relations: self.relations,
}
}
DefiningTy::FnDef(_, substs) => substs,
- // When we encounter other sorts of constant
- // expressions, such as the `22` in `[foo; 22]`, we can
- // get the type `usize` here. For now, just return an
- // empty vector of substs in this case, since there are no
- // generics in scope in such expressions right now.
+ // When we encounter a constant body, just return whatever
+ // substitutions are in scope for that constant.
DefiningTy::Const(_) => {
- assert!(identity_substs.is_empty());
identity_substs
}
};
sig.inputs_and_output()
}
- // This happens on things like `[foo; 22]`. Hence, no
- // inputs, one output, but it seems like we need a more
- // general way to handle this category of MIR.
+ // For a constant body, there are no inputs, and one
+ // "output" (the type of the constant).
DefiningTy::Const(ty) => ty::Binder::dummy(tcx.mk_type_list(iter::once(ty))),
}
}
/// during initialization. Relies on the `indices` map having been
/// fully initialized.
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
- match r {
- ty::ReEarlyBound(..) | ty::ReStatic => *self.indices.get(&r).unwrap(),
- ty::ReVar(..) => r.to_region_vid(),
- _ => bug!("cannot convert `{:?}` to a region vid", r),
+ if let ty::ReVar(..) = r {
+ r.to_region_vid()
+ } else {
+ *self.indices.get(&r).unwrap_or_else(|| {
+ bug!("cannot convert `{:?}` to a region vid", r)
+ })
}
}
}
}
+ /// Convert a byte array or byte slice to a byte slice.
+ fn to_slice_operand(&mut self,
+ block: BasicBlock,
+ source_info: SourceInfo,
+ operand: Operand<'tcx>)
+ -> Operand<'tcx>
+ {
+ let tcx = self.hir.tcx();
+ let ty = operand.ty(&self.local_decls, tcx);
+ debug!("to_slice_operand({:?}, {:?}: {:?})", block, operand, ty);
+ match ty.sty {
+ ty::TyRef(region, mt) => match mt.ty.sty {
+ ty::TyArray(ety, _) => {
+ let ty = tcx.mk_imm_ref(region, tcx.mk_slice(ety));
+ let temp = self.temp(ty, source_info.span);
+ self.cfg.push_assign(block, source_info, &temp,
+ Rvalue::Cast(CastKind::Unsize, operand, ty));
+ Operand::Move(temp)
+ }
+ ty::TySlice(_) => operand,
+ _ => {
+ span_bug!(source_info.span,
+ "bad operand {:?}: {:?} to `to_slice_operand`", operand, ty)
+ }
+ }
+ _ => {
+ span_bug!(source_info.span,
+ "bad operand {:?}: {:?} to `to_slice_operand`", operand, ty)
+ }
+ }
+
+ }
+
/// Generates the code to perform a test.
pub fn perform_test(&mut self,
block: BasicBlock,
place: &Place<'tcx>,
test: &Test<'tcx>)
-> Vec<BasicBlock> {
+ debug!("perform_test({:?}, {:?}: {:?}, {:?})",
+ block,
+ place,
+ place.ty(&self.local_decls, self.hir.tcx()),
+ test);
let source_info = self.source_info(test.span);
match test.kind {
TestKind::Switch { adt_def, ref variants } => {
ret
}
- TestKind::Eq { value, mut ty } => {
+ TestKind::Eq { value, ty } => {
+ let tcx = self.hir.tcx();
let mut val = Operand::Copy(place.clone());
// If we're using b"..." as a pattern, we need to insert an
// unsizing coercion, as the byte string has the type &[u8; N].
- let expect = if let ConstVal::ByteStr(bytes) = value.val {
- let tcx = self.hir.tcx();
-
- // Unsize the place to &[u8], too, if necessary.
- if let ty::TyRef(region, mt) = ty.sty {
- if let ty::TyArray(_, _) = mt.ty.sty {
- ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8));
- let val_slice = self.temp(ty, test.span);
- self.cfg.push_assign(block, source_info, &val_slice,
- Rvalue::Cast(CastKind::Unsize, val, ty));
- val = Operand::Move(val_slice);
- }
- }
-
- assert!(ty.is_slice());
-
+ //
+ // We want to do this even when the scrutinee is a reference to an
+ // array, so we can call `<[u8]>::eq` rather than having to find an
+ // `<[u8; N]>::eq`.
+ let (expect, val) = if let ConstVal::ByteStr(bytes) = value.val {
let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len() as u64);
let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty);
let array = self.literal_operand(test.span, array_ref, Literal::Value {
value
});
- let slice = self.temp(ty, test.span);
- self.cfg.push_assign(block, source_info, &slice,
- Rvalue::Cast(CastKind::Unsize, array, ty));
- Operand::Move(slice)
+ let val = self.to_slice_operand(block, source_info, val);
+ let slice = self.to_slice_operand(block, source_info, array);
+ (slice, val)
} else {
- self.literal_operand(test.span, ty, Literal::Value {
+ (self.literal_operand(test.span, ty, Literal::Value {
value
- })
+ }), val)
};
// Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq.
let fail = self.cfg.start_new_block();
+ let ty = expect.ty(&self.local_decls, tcx);
if let ty::TyRef(_, mt) = ty.sty {
assert!(ty.is_slice());
let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap();
}
impl ReserveOrActivateIndex {
- fn reserved(i: BorrowIndex) -> Self { ReserveOrActivateIndex::new((i.index() * 2)) }
+ fn reserved(i: BorrowIndex) -> Self { ReserveOrActivateIndex::new(i.index() * 2) }
fn active(i: BorrowIndex) -> Self { ReserveOrActivateIndex::new((i.index() * 2) + 1) }
pub(crate) fn is_reservation(self) -> bool { self.index() % 2 == 0 }
extern crate log_settings;
extern crate rustc_apfloat;
extern crate byteorder;
-extern crate rustc_trans_utils;
mod diagnostics;
use std::iter;
use rustc::mir::mono::Linkage;
use syntax_pos::symbol::Symbol;
+use syntax::codemap::Span;
pub use rustc::mir::mono::MonoItem;
pub fn linkage_by_name(name: &str) -> Option<Linkage> {
result
}
}
+
+ fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Span> {
+ match *self.as_mono_item() {
+ MonoItem::Fn(Instance { def, .. }) => {
+ tcx.hir.as_local_node_id(def.def_id())
+ }
+ MonoItem::Static(node_id) |
+ MonoItem::GlobalAsm(node_id) => {
+ Some(node_id)
+ }
+ }.map(|node_id| tcx.hir.span(node_id))
+ }
}
impl<'a, 'tcx> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
pub mod item;
pub mod partitioning;
+#[inline(never)] // give this a place in the profiler
+pub fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I)
+ where I: Iterator<Item=&'a MonoItem<'tcx>>
+{
+ let mut symbols: Vec<_> = trans_items.map(|trans_item| {
+ (trans_item, trans_item.symbol_name(tcx))
+ }).collect();
+
+ (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{
+ sym1.cmp(sym2)
+ });
+
+ for pair in (&symbols[..]).windows(2) {
+ let sym1 = &pair[0].1;
+ let sym2 = &pair[1].1;
+
+ if *sym1 == *sym2 {
+ let trans_item1 = pair[0].0;
+ let trans_item2 = pair[1].0;
+
+ let span1 = trans_item1.local_span(tcx);
+ let span2 = trans_item2.local_span(tcx);
+
+ // Deterministically select one of the spans for error reporting
+ let span = match (span1, span2) {
+ (Some(span1), Some(span2)) => {
+ Some(if span1.lo().0 > span2.lo().0 {
+ span1
+ } else {
+ span2
+ })
+ }
+ (Some(span), None) |
+ (None, Some(span)) => Some(span),
+ _ => None
+ };
+
+ let error_message = format!("symbol `{}` is already defined", sym1);
+
+ if let Some(span) = span {
+ tcx.sess.span_fatal(span, &error_message)
+ } else {
+ tcx.sess.fatal(&error_message)
+ }
+ }
+ }
+}
+
fn fn_once_adapter_instance<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
closure_did: DefId,
w: &mut Write,
) -> io::Result<()> {
write_mir_sig(tcx, src, mir, w)?;
- writeln!(w, " {{")?;
+ writeln!(w, "{{")?;
// construct a scope tree and write it out
let mut scope_tree: FxHashMap<VisibilityScope, Vec<VisibilityScope>> = FxHashMap();
write!(w, "{:?}: {}", Place::Local(arg), mir.local_decls[arg].ty)?;
}
- write!(w, ") -> {}", mir.return_ty())
+ write!(w, ") -> {}", mir.return_ty())?;
}
(hir::BodyOwnerKind::Const, _) | (hir::BodyOwnerKind::Static(_), _) | (_, Some(_)) => {
assert_eq!(mir.arg_count, 0);
- write!(w, ": {} =", mir.return_ty())
+ write!(w, ": {} =", mir.return_ty())?;
}
}
+
+ if let Some(yield_ty) = mir.yield_ty {
+ writeln!(w)?;
+ writeln!(w, "yields {}", yield_ty)?;
+ }
+
+ Ok(())
}
fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
fn load_plugin(&mut self, span: Span, name: &str, args: Vec<ast::NestedMetaItem>) {
let registrar = self.reader.find_plugin_registrar(span, name);
- if let Some((lib, disambiguator, index)) = registrar {
- let symbol = self.sess.generate_plugin_registrar_symbol(disambiguator, index);
+ if let Some((lib, disambiguator)) = registrar {
+ let symbol = self.sess.generate_plugin_registrar_symbol(disambiguator);
let fun = self.dylink_registrar(span, lib, symbol);
self.plugins.push(PluginRegistrar {
fun,
```
"##,
+E0659: r##"
+An item usage is ambiguous.
+
+Erroneous code example:
+
+```compile_fail,E0659
+pub mod moon {
+ pub fn foo() {}
+}
+
+pub mod earth {
+ pub fn foo() {}
+}
+
+mod collider {
+ pub use moon::*;
+ pub use earth::*;
+}
+
+fn main() {
+ collider::foo(); // ERROR: `foo` is ambiguous
+}
+```
+
+This error generally appears when two items with the same name are imported into
+a module. Here, the `foo` functions are imported and reexported from the
+`collider` module and therefore, when we're using `collider::foo()`, both
+functions collide.
+
+To solve this error, the best solution is generally to keep the path before the
+item when using it. Example:
+
+```
+pub mod moon {
+ pub fn foo() {}
+}
+
+pub mod earth {
+ pub fn foo() {}
+}
+
+mod collider {
+ pub use moon;
+ pub use earth;
+}
+
+fn main() {
+ collider::moon::foo(); // ok!
+ collider::earth::foo(); // ok!
+}
+```
+"##,
+
}
register_diagnostics! {
}
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
enum PathResult<'a> {
Module(Module<'a>),
NonModule(PathResolution),
unresolved_invocations: RefCell::new(FxHashSet()),
no_implicit_prelude: false,
glob_importers: RefCell::new(Vec::new()),
- globs: RefCell::new((Vec::new())),
+ globs: RefCell::new(Vec::new()),
traits: RefCell::new(None),
populated: Cell::new(normal_ancestor_id.is_local()),
span,
let code = source.error_code(def.is_some());
let (base_msg, fallback_label, base_span) = if let Some(def) = def {
(format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str),
- format!("not a {}", expected), span)
+ format!("not a {}", expected),
+ span)
} else {
let item_str = path[path.len() - 1].node;
let item_span = path[path.len() - 1].span;
(mod_prefix, format!("`{}`", names_to_string(mod_path)))
};
(format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
- format!("not found in {}", mod_str), item_span)
+ format!("not found in {}", mod_str),
+ item_span)
};
let code = DiagnosticId::Error(code.into());
let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code);
}
return (err, candidates);
},
- _ if ns == ValueNS && is_struct_like(def) => {
- if let Def::Struct(def_id) = def {
- if let Some((ctor_def, ctor_vis))
- = this.struct_constructors.get(&def_id).cloned() {
- if is_expected(ctor_def) && !this.is_accessible(ctor_vis) {
- err.span_label(span, format!("constructor is not visible \
- here due to private fields"));
- }
+ (Def::Struct(def_id), _) if ns == ValueNS => {
+ if let Some((ctor_def, ctor_vis))
+ = this.struct_constructors.get(&def_id).cloned() {
+ let accessible_ctor = this.is_accessible(ctor_vis);
+ if is_expected(ctor_def) && !accessible_ctor {
+ err.span_label(span, format!("constructor is not visible \
+ here due to private fields"));
}
+ } else {
+ err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
+ path_str));
}
+ return (err, candidates);
+ }
+ (Def::Union(..), _) |
+ (Def::Variant(..), _) |
+ (Def::VariantCtor(_, CtorKind::Fictive), _) if ns == ValueNS => {
err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
path_str));
return (err, candidates);
}
+ (Def::SelfTy(..), _) if ns == ValueNS => {
+ err.span_label(span, fallback_label);
+ err.note("can't use `Self` as a constructor, you must use the \
+ implemented struct");
+ return (err, candidates);
+ }
+ (Def::TyAlias(_), _) | (Def::AssociatedTy(..), _) if ns == ValueNS => {
+ err.note("can't use a type alias as a constructor");
+ return (err, candidates);
+ }
_ => {}
}
}
self.session.buffer_lint(lint::builtin::LEGACY_IMPORTS, id, span, &msg);
} else {
let mut err =
- self.session.struct_span_err(span, &format!("`{}` is ambiguous", name));
+ struct_span_err!(self.session, span, E0659, "`{}` is ambiguous", name);
err.span_note(b1.span, &msg1);
match b2.def() {
Def::Macro(..) if b2.span == DUMMY_SP =>
}
}
-fn is_struct_like(def: Def) -> bool {
- match def {
- Def::VariantCtor(_, CtorKind::Fictive) => true,
- _ => PathSource::Struct.is_expected(def),
- }
-}
-
fn is_self_type(path: &[SpannedIdent], namespace: Namespace) -> bool {
namespace == TypeNS && path.len() == 1 && path[0].node.name == keywords::SelfType.name()
}
}
pub fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>) {
- if self.pad.is_some() {
- *idx += 1;
- }
let mut next = || {
let val = llvm::get_param(bx.llfn(), *idx as c_uint);
*idx += 1;
use ModuleLlvm;
use llvm::{self, False, True};
-pub unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) {
+pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) {
let llcx = mods.llcx;
let llmod = mods.llmod;
let usize = match &tcx.sess.target.target.target_pointer_width[..] {
+++ /dev/null
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! This pass is only used for UNIT TESTS related to incremental
-//! compilation. It tests whether a particular `.o` file will be re-used
-//! from a previous compilation or whether it must be regenerated.
-//!
-//! The user adds annotations to the crate of the following form:
-//!
-//! ```
-//! #![rustc_partition_reused(module="spike", cfg="rpass2")]
-//! #![rustc_partition_translated(module="spike-x", cfg="rpass2")]
-//! ```
-//!
-//! The first indicates (in the cfg `rpass2`) that `spike.o` will be
-//! reused, the second that `spike-x.o` will be recreated. If these
-//! annotations are inaccurate, errors are reported.
-//!
-//! The reason that we use `cfg=...` and not `#[cfg_attr]` is so that
-//! the HIR doesn't change as a result of the annotations, which might
-//! perturb the reuse results.
-
-use rustc::dep_graph::{DepNode, DepConstructor};
-use rustc::mir::mono::CodegenUnit;
-use rustc::ty::TyCtxt;
-use syntax::ast;
-use syntax_pos::symbol::Symbol;
-use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED};
-
-const MODULE: &'static str = "module";
-const CFG: &'static str = "cfg";
-
-#[derive(Debug, PartialEq, Clone, Copy)]
-enum Disposition { Reused, Translated }
-
-pub(crate) fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
- tcx.dep_graph.with_ignore(|| {
- if tcx.sess.opts.incremental.is_none() {
- return;
- }
-
- let ams = AssertModuleSource { tcx };
- for attr in &tcx.hir.krate().attrs {
- ams.check_attr(attr);
- }
- })
-}
-
-struct AssertModuleSource<'a, 'tcx: 'a> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>
-}
-
-impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
- fn check_attr(&self, attr: &ast::Attribute) {
- let disposition = if attr.check_name(ATTR_PARTITION_REUSED) {
- Disposition::Reused
- } else if attr.check_name(ATTR_PARTITION_TRANSLATED) {
- Disposition::Translated
- } else {
- return;
- };
-
- if !self.check_config(attr) {
- debug!("check_attr: config does not match, ignoring attr");
- return;
- }
-
- let mname = self.field(attr, MODULE);
- let mangled_cgu_name = CodegenUnit::mangle_name(&mname.as_str());
- let mangled_cgu_name = Symbol::intern(&mangled_cgu_name).as_str();
-
- let dep_node = DepNode::new(self.tcx,
- DepConstructor::CompileCodegenUnit(mangled_cgu_name));
-
- if let Some(loaded_from_cache) = self.tcx.dep_graph.was_loaded_from_cache(&dep_node) {
- match (disposition, loaded_from_cache) {
- (Disposition::Reused, false) => {
- self.tcx.sess.span_err(
- attr.span,
- &format!("expected module named `{}` to be Reused but is Translated",
- mname));
- }
- (Disposition::Translated, true) => {
- self.tcx.sess.span_err(
- attr.span,
- &format!("expected module named `{}` to be Translated but is Reused",
- mname));
- }
- (Disposition::Reused, true) |
- (Disposition::Translated, false) => {
- // These are what we would expect.
- }
- }
- } else {
- self.tcx.sess.span_err(attr.span, &format!("no module named `{}`", mname));
- }
- }
-
- fn field(&self, attr: &ast::Attribute, name: &str) -> ast::Name {
- for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
- if item.check_name(name) {
- if let Some(value) = item.value_str() {
- return value;
- } else {
- self.tcx.sess.span_fatal(
- item.span,
- &format!("associated value expected for `{}`", name));
- }
- }
- }
-
- self.tcx.sess.span_fatal(
- attr.span,
- &format!("no field `{}`", name));
- }
-
- /// Scan for a `cfg="foo"` attribute and check whether we have a
- /// cfg flag called `foo`.
- fn check_config(&self, attr: &ast::Attribute) -> bool {
- let config = &self.tcx.sess.parse_sess.config;
- let value = self.field(attr, CFG);
- debug!("check_config(config={:?}, value={:?})", config, value);
- if config.iter().any(|&(name, _)| name == value) {
- debug!("check_config: matched");
- return true;
- }
- debug!("check_config: no match found");
- return false;
- }
-
-}
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::io;
-use std::process::{self, Output, Child};
+use std::mem;
+use std::process::{self, Output};
+#[derive(Clone)]
pub struct Command {
- program: OsString,
+ program: Program,
args: Vec<OsString>,
env: Vec<(OsString, OsString)>,
}
+#[derive(Clone)]
+enum Program {
+ Normal(OsString),
+ CmdBatScript(OsString),
+}
+
impl Command {
pub fn new<P: AsRef<OsStr>>(program: P) -> Command {
- Command::_new(program.as_ref())
+ Command::_new(Program::Normal(program.as_ref().to_owned()))
+ }
+
+ pub fn bat_script<P: AsRef<OsStr>>(program: P) -> Command {
+ Command::_new(Program::CmdBatScript(program.as_ref().to_owned()))
}
- fn _new(program: &OsStr) -> Command {
+ fn _new(program: Program) -> Command {
Command {
- program: program.to_owned(),
+ program,
args: Vec::new(),
env: Vec::new(),
}
self.command().output()
}
- pub fn spawn(&mut self) -> io::Result<Child> {
- self.command().spawn()
- }
-
pub fn command(&self) -> process::Command {
- let mut ret = process::Command::new(&self.program);
+ let mut ret = match self.program {
+ Program::Normal(ref p) => process::Command::new(p),
+ Program::CmdBatScript(ref p) => {
+ let mut c = process::Command::new("cmd");
+ c.arg("/c").arg(p);
+ c
+ }
+ };
ret.args(&self.args);
ret.envs(self.env.clone());
return ret
// extensions
- pub fn get_program(&self) -> &OsStr {
- &self.program
+ pub fn take_args(&mut self) -> Vec<OsString> {
+ mem::replace(&mut self.args, Vec::new())
}
- pub fn get_args(&self) -> &[OsString] {
- &self.args
- }
+ /// Returns a `true` if we're pretty sure that this'll blow OS spawn limits,
+ /// or `false` if we should attempt to spawn and see what the OS says.
+ pub fn very_likely_to_exceed_some_spawn_limit(&self) -> bool {
+ // We mostly only care about Windows in this method, on Unix the limits
+ // can be gargantuan anyway so we're pretty unlikely to hit them
+ if cfg!(unix) {
+ return false
+ }
- pub fn get_env(&self) -> &[(OsString, OsString)] {
- &self.env
+ // Ok so on Windows to spawn a process is 32,768 characters in its
+ // command line [1]. Unfortunately we don't actually have access to that
+ // as it's calculated just before spawning. Instead we perform a
+ // poor-man's guess as to how long our command line will be. We're
+ // assuming here that we don't have to escape every character...
+ //
+ // Turns out though that `cmd.exe` has even smaller limits, 8192
+ // characters [2]. Linkers can often be batch scripts (for example
+ // Emscripten, Gecko's current build system) which means that we're
+ // running through batch scripts. These linkers often just forward
+ // arguments elsewhere (and maybe tack on more), so if we blow 8192
+ // bytes we'll typically cause them to blow as well.
+ //
+ // Basically as a result just perform an inflated estimate of what our
+ // command line will look like and test if it's > 8192 (we actually
+ // test against 6k to artificially inflate our estimate). If all else
+ // fails we'll fall back to the normal unix logic of testing the OS
+ // error code if we fail to spawn and automatically re-spawning the
+ // linker with smaller arguments.
+ //
+ // [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
+ // [2]: https://blogs.msdn.microsoft.com/oldnewthing/20031210-00/?p=41553
+
+ let estimated_command_line_len =
+ self.args.iter().map(|a| a.len()).sum::<usize>();
+ estimated_command_line_len > 1024 * 6
}
}
use std::env;
use std::ffi::OsString;
use std::fmt;
-use std::fs::{self, File};
-use std::io::{self, Write, BufWriter};
+use std::fs;
+use std::io;
use std::path::{Path, PathBuf};
use std::process::{Output, Stdio};
use std::str;
let cmd = |linker: &Path| {
if let Some(linker) = linker.to_str() {
if cfg!(windows) && linker.ends_with(".bat") {
- let mut cmd = Command::new("cmd");
- cmd.arg("/c").arg(linker);
- return cmd
+ return Command::bat_script(linker)
}
}
Command::new(linker)
/// Perform the linkage portion of the compilation phase. This will generate all
/// of the requested outputs for this compilation session.
-pub fn link_binary(sess: &Session,
- trans: &CrateTranslation,
- outputs: &OutputFilenames,
- crate_name: &str) -> Vec<PathBuf> {
+pub(crate) fn link_binary(sess: &Session,
+ trans: &CrateTranslation,
+ outputs: &OutputFilenames,
+ crate_name: &str) -> Vec<PathBuf> {
let mut out_filenames = Vec::new();
for &crate_type in sess.crate_types.borrow().iter() {
// Ignore executable crates if we have -Z no-trans, as they will error.
out_filename
}
-pub fn each_linked_rlib(sess: &Session,
- info: &CrateInfo,
- f: &mut FnMut(CrateNum, &Path)) -> Result<(), String> {
+pub(crate) fn each_linked_rlib(sess: &Session,
+ info: &CrateInfo,
+ f: &mut FnMut(CrateNum, &Path)) -> Result<(), String> {
let crates = info.used_crates_static.iter();
let fmts = sess.dependency_formats.borrow();
let fmts = fmts.get(&config::CrateTypeExecutable)
/// It's unusual for a crate to not participate in LTO. Typically only
/// compiler-specific and unstable crates have a reason to not participate in
/// LTO.
-pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool {
+pub(crate) fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool {
// If our target enables builtin function lowering in LLVM then the
// crates providing these functions don't participate in LTO (e.g.
// no_builtins or compiler builtins crates).
// that contains all the arguments. The theory is that this is then
// accepted on all linkers and the linker will read all its options out of
// there instead of looking at the command line.
- match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
- Ok(child) => return child.wait_with_output(),
- Err(ref e) if command_line_too_big(e) => {}
- Err(e) => return Err(e)
+ if !cmd.very_likely_to_exceed_some_spawn_limit() {
+ match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
+ Ok(child) => return child.wait_with_output(),
+ Err(ref e) if command_line_too_big(e) => {}
+ Err(e) => return Err(e)
+ }
}
- let file = tmpdir.join("linker-arguments");
- let mut cmd2 = Command::new(cmd.get_program());
- cmd2.arg(format!("@{}", file.display()));
- for &(ref k, ref v) in cmd.get_env() {
- cmd2.env(k, v);
- }
- let mut f = BufWriter::new(File::create(&file)?);
- for arg in cmd.get_args() {
- writeln!(f, "{}", Escape {
+ let mut cmd2 = cmd.clone();
+ let mut args = String::new();
+ for arg in cmd2.take_args() {
+ args.push_str(&Escape {
arg: arg.to_str().unwrap(),
is_like_msvc: sess.target.target.options.is_like_msvc,
- })?;
+ }.to_string());
+ args.push_str("\n");
}
- f.into_inner()?;
+ let file = tmpdir.join("linker-arguments");
+ fs::write(&file, args.as_bytes())?;
+ cmd2.arg(format!("@{}", file.display()));
return cmd2.output();
#[cfg(unix)]
}
}
-pub enum LtoModuleTranslation {
+pub(crate) enum LtoModuleTranslation {
Fat {
module: Option<ModuleTranslation>,
_serialized_bitcode: Vec<SerializedModule>,
/// points to LLVM data structures owned by this `LtoModuleTranslation`.
/// It's intended that the module returned is immediately code generated and
/// dropped, and then this LTO module is dropped.
- pub unsafe fn optimize(&mut self,
- cgcx: &CodegenContext,
- timeline: &mut Timeline)
+ pub(crate) unsafe fn optimize(&mut self,
+ cgcx: &CodegenContext,
+ timeline: &mut Timeline)
-> Result<ModuleTranslation, FatalError>
{
match *self {
JustThisCrate,
}
-pub fn run(cgcx: &CodegenContext,
+pub(crate) fn run(cgcx: &CodegenContext,
modules: Vec<ModuleTranslation>,
mode: LTOMode,
timeline: &mut Timeline)
if let Some(id) = tcx.sess.derive_registrar_fn.get() {
let def_id = tcx.hir.local_def_id(id);
- let idx = def_id.index;
let disambiguator = tcx.sess.local_crate_disambiguator();
- let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx);
+ let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator);
local_crate.push((registrar, Some(def_id), SymbolExportLevel::C));
}
+++ /dev/null
-// 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.
-
-//! The Rust Linkage Model and Symbol Names
-//! =======================================
-//!
-//! The semantic model of Rust linkage is, broadly, that "there's no global
-//! namespace" between crates. Our aim is to preserve the illusion of this
-//! model despite the fact that it's not *quite* possible to implement on
-//! modern linkers. We initially didn't use system linkers at all, but have
-//! been convinced of their utility.
-//!
-//! There are a few issues to handle:
-//!
-//! - Linkers operate on a flat namespace, so we have to flatten names.
-//! We do this using the C++ namespace-mangling technique. Foo::bar
-//! symbols and such.
-//!
-//! - Symbols for distinct items with the same *name* need to get different
-//! linkage-names. Examples of this are monomorphizations of functions or
-//! items within anonymous scopes that end up having the same path.
-//!
-//! - Symbols in different crates but with same names "within" the crate need
-//! to get different linkage-names.
-//!
-//! - Symbol names should be deterministic: Two consecutive runs of the
-//! compiler over the same code base should produce the same symbol names for
-//! the same items.
-//!
-//! - Symbol names should not depend on any global properties of the code base,
-//! so that small modifications to the code base do not result in all symbols
-//! changing. In previous versions of the compiler, symbol names incorporated
-//! the SVH (Stable Version Hash) of the crate. This scheme turned out to be
-//! infeasible when used in conjunction with incremental compilation because
-//! small code changes would invalidate all symbols generated previously.
-//!
-//! - Even symbols from different versions of the same crate should be able to
-//! live next to each other without conflict.
-//!
-//! In order to fulfill the above requirements the following scheme is used by
-//! the compiler:
-//!
-//! The main tool for avoiding naming conflicts is the incorporation of a 64-bit
-//! hash value into every exported symbol name. Anything that makes a difference
-//! to the symbol being named, but does not show up in the regular path needs to
-//! be fed into this hash:
-//!
-//! - Different monomorphizations of the same item have the same path but differ
-//! in their concrete type parameters, so these parameters are part of the
-//! data being digested for the symbol hash.
-//!
-//! - Rust allows items to be defined in anonymous scopes, such as in
-//! `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have
-//! the path `foo::bar`, since the anonymous scopes do not contribute to the
-//! path of an item. The compiler already handles this case via so-called
-//! disambiguating `DefPaths` which use indices to distinguish items with the
-//! same name. The DefPaths of the functions above are thus `foo[0]::bar[0]`
-//! and `foo[0]::bar[1]`. In order to incorporate this disambiguation
-//! information into the symbol name too, these indices are fed into the
-//! symbol hash, so that the above two symbols would end up with different
-//! hash values.
-//!
-//! The two measures described above suffice to avoid intra-crate conflicts. In
-//! order to also avoid inter-crate conflicts two more measures are taken:
-//!
-//! - The name of the crate containing the symbol is prepended to the symbol
-//! name, i.e. symbols are "crate qualified". For example, a function `foo` in
-//! module `bar` in crate `baz` would get a symbol name like
-//! `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids
-//! simple conflicts between functions from different crates.
-//!
-//! - In order to be able to also use symbols from two versions of the same
-//! crate (which naturally also have the same name), a stronger measure is
-//! required: The compiler accepts an arbitrary "disambiguator" value via the
-//! `-C metadata` commandline argument. This disambiguator is then fed into
-//! the symbol hash of every exported item. Consequently, the symbols in two
-//! identical crates but with different disambiguators are not in conflict
-//! with each other. This facility is mainly intended to be used by build
-//! tools like Cargo.
-//!
-//! A note on symbol name stability
-//! -------------------------------
-//! Previous versions of the compiler resorted to feeding NodeIds into the
-//! symbol hash in order to disambiguate between items with the same path. The
-//! current version of the name generation algorithm takes great care not to do
-//! that, since NodeIds are notoriously unstable: A small change to the
-//! code base will offset all NodeIds after the change and thus, much as using
-//! the SVH in the hash, invalidate an unbounded number of symbol names. This
-//! makes re-using previously compiled code for incremental compilation
-//! virtually impossible. Thus, symbol hash generation exclusively relies on
-//! DefPaths which are much more robust in the face of changes to the code base.
-
-use monomorphize::Instance;
-use trans_item::{BaseMonoItemExt, InstantiationMode};
-
-use rustc::middle::weak_lang_items;
-use rustc::mir::mono::MonoItem;
-use rustc::hir::def_id::DefId;
-use rustc::hir::map as hir_map;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::fold::TypeVisitor;
-use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
-use rustc::ty::maps::Providers;
-use rustc::ty::subst::Substs;
-use rustc::hir::map::definitions::DefPathData;
-use rustc::util::common::record_time;
-
-use syntax::attr;
-use syntax_pos::symbol::Symbol;
-
-use std::fmt::Write;
-
-pub fn provide(providers: &mut Providers) {
- *providers = Providers {
- def_symbol_name,
- symbol_name,
-
- export_name: |tcx, id| {
- tcx.get_attrs(id).iter().fold(None, |ia, attr| {
- if attr.check_name("export_name") {
- if let s @ Some(_) = attr.value_str() {
- s
- } else {
- struct_span_err!(tcx.sess, attr.span, E0558,
- "export_name attribute has invalid format")
- .span_label(attr.span, "did you mean #[export_name=\"*\"]?")
- .emit();
- None
- }
- } else {
- ia
- }
- })
- },
-
- contains_extern_indicator: |tcx, id| {
- attr::contains_name(&tcx.get_attrs(id), "no_mangle") ||
- tcx.export_name(id).is_some()
- },
-
- ..*providers
- };
-}
-
-fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-
- // the DefId of the item this name is for
- def_id: DefId,
-
- // instance this name will be for
- instance: Instance<'tcx>,
-
- // type of the item, without any generic
- // parameters substituted; this is
- // included in the hash as a kind of
- // safeguard.
- item_type: Ty<'tcx>,
-
- // values for generic type parameters,
- // if any.
- substs: &'tcx Substs<'tcx>)
- -> u64 {
- debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
-
- let mut hasher = ty::util::TypeIdHasher::<u64>::new(tcx);
-
- record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
- // the main symbol name is not necessarily unique; hash in the
- // compiler's internal def-path, guaranteeing each symbol has a
- // truly unique path
- hasher.hash(tcx.def_path_hash(def_id));
-
- // Include the main item-type. Note that, in this case, the
- // assertions about `needs_subst` may not hold, but this item-type
- // ought to be the same for every reference anyway.
- assert!(!item_type.has_erasable_regions());
- hasher.visit_ty(item_type);
-
- // If this is a function, we hash the signature as well.
- // This is not *strictly* needed, but it may help in some
- // situations, see the `run-make/a-b-a-linker-guard` test.
- if let ty::TyFnDef(..) = item_type.sty {
- item_type.fn_sig(tcx).visit_with(&mut hasher);
- }
-
- // also include any type parameters (for generic items)
- assert!(!substs.has_erasable_regions());
- assert!(!substs.needs_subst());
- substs.visit_with(&mut hasher);
-
- let mut avoid_cross_crate_conflicts = false;
-
- // If this is an instance of a generic function, we also hash in
- // the ID of the instantiating crate. This avoids symbol conflicts
- // in case the same instances is emitted in two crates of the same
- // project.
- if substs.types().next().is_some() {
- avoid_cross_crate_conflicts = true;
- }
-
- // If we're dealing with an instance of a function that's inlined from
- // another crate but we're marking it as globally shared to our
- // compliation (aka we're not making an internal copy in each of our
- // codegen units) then this symbol may become an exported (but hidden
- // visibility) symbol. This means that multiple crates may do the same
- // and we want to be sure to avoid any symbol conflicts here.
- match MonoItem::Fn(instance).instantiation_mode(tcx) {
- InstantiationMode::GloballyShared { may_conflict: true } => {
- avoid_cross_crate_conflicts = true;
- }
- _ => {}
- }
-
- if avoid_cross_crate_conflicts {
- hasher.hash(tcx.crate_name.as_str());
- hasher.hash(tcx.sess.local_crate_disambiguator());
- }
- });
-
- // 64 bits should be enough to avoid collisions.
- hasher.finish()
-}
-
-fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
- -> ty::SymbolName
-{
- let mut buffer = SymbolPathBuffer::new();
- item_path::with_forced_absolute_paths(|| {
- tcx.push_item_path(&mut buffer, def_id);
- });
- buffer.into_interned()
-}
-
-fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
- -> ty::SymbolName
-{
- ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_str() }
-}
-
-fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
- -> String
-{
- let def_id = instance.def_id();
- let substs = instance.substs;
-
- debug!("symbol_name(def_id={:?}, substs={:?})",
- def_id, substs);
-
- let node_id = tcx.hir.as_local_node_id(def_id);
-
- if let Some(id) = node_id {
- if tcx.sess.plugin_registrar_fn.get() == Some(id) {
- let idx = def_id.index;
- let disambiguator = tcx.sess.local_crate_disambiguator();
- return tcx.sess.generate_plugin_registrar_symbol(disambiguator, idx);
- }
- if tcx.sess.derive_registrar_fn.get() == Some(id) {
- let idx = def_id.index;
- let disambiguator = tcx.sess.local_crate_disambiguator();
- return tcx.sess.generate_derive_registrar_symbol(disambiguator, idx);
- }
- }
-
- // FIXME(eddyb) Precompute a custom symbol name based on attributes.
- let attrs = tcx.get_attrs(def_id);
- let is_foreign = if let Some(id) = node_id {
- match tcx.hir.get(id) {
- hir_map::NodeForeignItem(_) => true,
- _ => false
- }
- } else {
- tcx.is_foreign_item(def_id)
- };
-
- if let Some(name) = weak_lang_items::link_name(&attrs) {
- return name.to_string();
- }
-
- if is_foreign {
- if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") {
- return name.to_string();
- }
- // Don't mangle foreign items.
- return tcx.item_name(def_id).to_string();
- }
-
- if let Some(name) = tcx.export_name(def_id) {
- // Use provided name
- return name.to_string();
- }
-
- if attr::contains_name(&attrs, "no_mangle") {
- // Don't mangle
- return tcx.item_name(def_id).to_string();
- }
-
- // We want to compute the "type" of this item. Unfortunately, some
- // kinds of items (e.g., closures) don't have an entry in the
- // item-type array. So walk back up the find the closest parent
- // that DOES have an entry.
- let mut ty_def_id = def_id;
- let instance_ty;
- loop {
- let key = tcx.def_key(ty_def_id);
- match key.disambiguated_data.data {
- DefPathData::TypeNs(_) |
- DefPathData::ValueNs(_) => {
- instance_ty = tcx.type_of(ty_def_id);
- break;
- }
- _ => {
- // if we're making a symbol for something, there ought
- // to be a value or type-def or something in there
- // *somewhere*
- ty_def_id.index = key.parent.unwrap_or_else(|| {
- bug!("finding type for {:?}, encountered def-id {:?} with no \
- parent", def_id, ty_def_id);
- });
- }
- }
- }
-
- // Erase regions because they may not be deterministic when hashed
- // and should not matter anyhow.
- let instance_ty = tcx.erase_regions(&instance_ty);
-
- let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs);
-
- SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash)
-}
-
-// Follow C++ namespace-mangling style, see
-// http://en.wikipedia.org/wiki/Name_mangling for more info.
-//
-// It turns out that on macOS you can actually have arbitrary symbols in
-// function names (at least when given to LLVM), but this is not possible
-// when using unix's linker. Perhaps one day when we just use a linker from LLVM
-// we won't need to do this name mangling. The problem with name mangling is
-// that it seriously limits the available characters. For example we can't
-// have things like &T in symbol names when one would theoretically
-// want them for things like impls of traits on that type.
-//
-// To be able to work on all platforms and get *some* reasonable output, we
-// use C++ name-mangling.
-struct SymbolPathBuffer {
- result: String,
- temp_buf: String
-}
-
-impl SymbolPathBuffer {
- fn new() -> Self {
- let mut result = SymbolPathBuffer {
- result: String::with_capacity(64),
- temp_buf: String::with_capacity(16)
- };
- result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
- result
- }
-
- fn from_interned(symbol: ty::SymbolName) -> Self {
- let mut result = SymbolPathBuffer {
- result: String::with_capacity(64),
- temp_buf: String::with_capacity(16)
- };
- result.result.push_str(&symbol.name);
- result
- }
-
- fn into_interned(self) -> ty::SymbolName {
- ty::SymbolName { name: Symbol::intern(&self.result).as_str() }
- }
-
- fn finish(mut self, hash: u64) -> String {
- // E = end name-sequence
- let _ = write!(self.result, "17h{:016x}E", hash);
- self.result
- }
-}
-
-impl ItemPathBuffer for SymbolPathBuffer {
- fn root_mode(&self) -> &RootMode {
- const ABSOLUTE: &'static RootMode = &RootMode::Absolute;
- ABSOLUTE
- }
-
- fn push(&mut self, text: &str) {
- self.temp_buf.clear();
- let need_underscore = sanitize(&mut self.temp_buf, text);
- let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize));
- if need_underscore {
- self.result.push('_');
- }
- self.result.push_str(&self.temp_buf);
- }
-}
-
-// Name sanitation. LLVM will happily accept identifiers with weird names, but
-// gas doesn't!
-// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
-//
-// returns true if an underscore must be added at the start
-pub fn sanitize(result: &mut String, s: &str) -> bool {
- for c in s.chars() {
- match c {
- // Escape these with $ sequences
- '@' => result.push_str("$SP$"),
- '*' => result.push_str("$BP$"),
- '&' => result.push_str("$RF$"),
- '<' => result.push_str("$LT$"),
- '>' => result.push_str("$GT$"),
- '(' => result.push_str("$LP$"),
- ')' => result.push_str("$RP$"),
- ',' => result.push_str("$C$"),
-
- // '.' doesn't occur in types and functions, so reuse it
- // for ':' and '-'
- '-' | ':' => result.push('.'),
-
- // These are legal symbols
- 'a' ... 'z'
- | 'A' ... 'Z'
- | '0' ... '9'
- | '_' | '.' | '$' => result.push(c),
-
- _ => {
- result.push('$');
- for c in c.escape_unicode().skip(1) {
- match c {
- '{' => {},
- '}' => result.push('$'),
- c => result.push(c),
- }
- }
- }
- }
- }
-
- // Underscore-qualify anything that didn't start as an ident.
- !result.is_empty() &&
- result.as_bytes()[0] != '_' as u8 &&
- ! (result.as_bytes()[0] as char).is_xid_start()
-}
Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone()))
}
- pub fn config(&self, kind: ModuleKind) -> &ModuleConfig {
+ pub(crate) fn config(&self, kind: ModuleKind) -> &ModuleConfig {
match kind {
ModuleKind::Regular => &self.regular_module_config,
ModuleKind::Metadata => &self.metadata_module_config,
}
}
- pub fn save_temp_bitcode(&self, trans: &ModuleTranslation, name: &str) {
+ pub(crate) fn save_temp_bitcode(&self, trans: &ModuleTranslation, name: &str) {
if !self.save_temps {
return
}
}
}
-pub struct CompiledModules {
+pub(crate) struct CompiledModules {
pub modules: Vec<CompiledModule>,
pub metadata_module: CompiledModule,
pub allocator_module: Option<CompiledModule>,
// These are used in linking steps and will be cleaned up afterward.
}
-pub fn dump_incremental_data(trans: &CrateTranslation) {
+pub(crate) fn dump_incremental_data(trans: &CrateTranslation) {
println!("[incremental] Re-using {} out of {} modules",
trans.modules.iter().filter(|m| m.pre_existing).count(),
trans.modules.len());
}
impl OngoingCrateTranslation {
- pub fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
+ pub(crate) fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
self.shared_emitter_main.check(sess, true);
let compiled_modules = match self.future.join() {
Ok(Ok(compiled_modules)) => compiled_modules,
trans
}
- pub fn submit_pre_translated_module_to_llvm(&self,
- tcx: TyCtxt,
- mtrans: ModuleTranslation) {
+ pub(crate) fn submit_pre_translated_module_to_llvm(&self,
+ tcx: TyCtxt,
+ mtrans: ModuleTranslation) {
self.wait_for_signal_to_translate_item();
self.check_for_errors(tcx.sess);
}
}
-pub fn submit_translated_module_to_llvm(tcx: TyCtxt,
- mtrans: ModuleTranslation,
- cost: u64) {
+pub(crate) fn submit_translated_module_to_llvm(tcx: TyCtxt,
+ mtrans: ModuleTranslation,
+ cost: u64) {
let llvm_work_item = WorkItem::Optimize(mtrans);
drop(tcx.tx_to_llvm_workers.send(Box::new(Message::TranslationDone {
llvm_work_item,
use super::ModuleKind;
use abi;
-use assert_module_sources;
use back::link;
use back::symbol_export;
use back::write::{self, OngoingCrateTranslation, create_target_machine};
use mir;
use monomorphize::Instance;
use monomorphize::partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt};
-use symbol_names_test;
+use rustc_trans_utils::symbol_names_test;
use time_graph;
use trans_item::{MonoItem, BaseMonoItemExt, MonoItemExt, DefPathBasedNames};
use type_::Type;
total_trans_time);
if tcx.sess.opts.incremental.is_some() {
- assert_module_sources::assert_module_sources(tcx);
+ ::rustc_incremental::assert_module_sources::assert_module_sources(tcx);
}
symbol_names_test::report_symbol_names(tcx);
|| rustc_incremental::save_dep_graph(tcx));
}
-#[inline(never)] // give this a place in the profiler
-fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I)
- where I: Iterator<Item=&'a MonoItem<'tcx>>
-{
- let mut symbols: Vec<_> = trans_items.map(|trans_item| {
- (trans_item, trans_item.symbol_name(tcx))
- }).collect();
-
- (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{
- sym1.cmp(sym2)
- });
-
- for pair in (&symbols[..]).windows(2) {
- let sym1 = &pair[0].1;
- let sym2 = &pair[1].1;
-
- if *sym1 == *sym2 {
- let trans_item1 = pair[0].0;
- let trans_item2 = pair[1].0;
-
- let span1 = trans_item1.local_span(tcx);
- let span2 = trans_item2.local_span(tcx);
-
- // Deterministically select one of the spans for error reporting
- let span = match (span1, span2) {
- (Some(span1), Some(span2)) => {
- Some(if span1.lo().0 > span2.lo().0 {
- span1
- } else {
- span2
- })
- }
- (Some(span), None) |
- (None, Some(span)) => Some(span),
- _ => None
- };
-
- let error_message = format!("symbol `{}` is already defined", sym1);
-
- if let Some(span) = span {
- tcx.sess.span_fatal(span, &error_message)
- } else {
- tcx.sess.fatal(&error_message)
- }
- }
- }
-}
-
fn collect_and_partition_translation_items<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cnum: CrateNum,
collector::collect_crate_mono_items(tcx, collection_mode)
});
- assert_symbols_are_distinct(tcx, items.iter());
+ ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, items.iter());
let strategy = if tcx.sess.opts.incremental.is_some() {
PartitioningStrategy::PerModule
```
"##,
-E0558: r##"
-The `export_name` attribute was malformed.
-
-Erroneous code example:
-
-```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
-#[export_name] // error: export_name attribute has invalid format
-pub fn something() {}
-
-fn main() {}
-```
-
-The `export_name` attribute expects a string in order to determine the name of
-the exported symbol. Example:
-
-```
-#[export_name = "some_function"] // ok!
-pub fn something() {}
+}
-fn main() {}
-```
-"##,
+register_diagnostics! {
+ E0558
}
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]
#![feature(conservative_impl_trait)]
+#![feature(optin_builtin_traits)]
use rustc::dep_graph::WorkProduct;
use syntax_pos::symbol::Symbol;
extern crate cc; // Used to locate MSVC
extern crate tempdir;
-pub use base::trans_crate;
use back::bytecode::RLIB_BYTECODE_EXTENSION;
-pub use metadata::LlvmMetadataLoader;
-pub use llvm_util::{init, target_features, print_version, print_passes, print};
+pub use llvm_util::{target_features, print_version, print_passes};
use std::any::Any;
use std::path::PathBuf;
use rustc::hir::def_id::CrateNum;
use rustc::middle::cstore::MetadataLoader;
use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource};
-use rustc::session::Session;
-use rustc::session::config::{OutputFilenames, OutputType};
+use rustc::session::{Session, CompileIncomplete};
+use rustc::session::config::{OutputFilenames, OutputType, PrintRequest};
use rustc::ty::{self, TyCtxt};
use rustc::util::nodemap::{FxHashSet, FxHashMap};
-
use rustc_mir::monomorphize;
+use rustc_trans_utils::trans_crate::TransCrate;
mod diagnostics;
-pub mod back {
+mod back {
+ pub use rustc_trans_utils::symbol_names;
mod archive;
pub mod bytecode;
mod command;
- pub(crate) mod linker;
+ pub mod linker;
pub mod link;
mod lto;
- pub(crate) mod symbol_export;
- pub(crate) mod symbol_names;
+ pub mod symbol_export;
pub mod write;
mod rpath;
}
mod abi;
mod allocator;
mod asm;
-mod assert_module_sources;
mod attributes;
mod base;
mod builder;
mod metadata;
mod meth;
mod mir;
-mod symbol_names_test;
mod time_graph;
mod trans_item;
mod type_;
pub struct LlvmTransCrate(());
+impl !Send for LlvmTransCrate {} // Llvm is on a per-thread basis
+impl !Sync for LlvmTransCrate {}
+
impl LlvmTransCrate {
- pub fn new() -> Self {
- LlvmTransCrate(())
+ pub fn new(sess: &Session) -> Box<TransCrate> {
+ llvm_util::init(sess); // Make sure llvm is inited
+ box LlvmTransCrate(())
}
}
-impl rustc_trans_utils::trans_crate::TransCrate for LlvmTransCrate {
- type MetadataLoader = metadata::LlvmMetadataLoader;
- type OngoingCrateTranslation = back::write::OngoingCrateTranslation;
- type TranslatedCrate = CrateTranslation;
+impl TransCrate for LlvmTransCrate {
+ fn print(&self, req: PrintRequest, sess: &Session) {
+ match req {
+ PrintRequest::RelocationModels => {
+ println!("Available relocation models:");
+ for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() {
+ println!(" {}", name);
+ }
+ println!("");
+ }
+ PrintRequest::CodeModels => {
+ println!("Available code models:");
+ for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){
+ println!(" {}", name);
+ }
+ println!("");
+ }
+ PrintRequest::TlsModels => {
+ println!("Available TLS models:");
+ for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){
+ println!(" {}", name);
+ }
+ println!("");
+ }
+ req => llvm_util::print(req, sess),
+ }
+ }
- fn metadata_loader() -> Box<MetadataLoader> {
+ fn target_features(&self, sess: &Session) -> Vec<Symbol> {
+ target_features(sess)
+ }
+
+ fn metadata_loader(&self) -> Box<MetadataLoader> {
box metadata::LlvmMetadataLoader
}
- fn provide(providers: &mut ty::maps::Providers) {
+ fn provide(&self, providers: &mut ty::maps::Providers) {
back::symbol_names::provide(providers);
back::symbol_export::provide(providers);
base::provide(providers);
attributes::provide(providers);
}
- fn provide_extern(providers: &mut ty::maps::Providers) {
+ fn provide_extern(&self, providers: &mut ty::maps::Providers) {
back::symbol_export::provide_extern(providers);
}
fn trans_crate<'a, 'tcx>(
+ &self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
rx: mpsc::Receiver<Box<Any + Send>>
- ) -> Self::OngoingCrateTranslation {
- base::trans_crate(tcx, rx)
+ ) -> Box<Any> {
+ box base::trans_crate(tcx, rx)
}
- fn join_trans(
- trans: Self::OngoingCrateTranslation,
+ fn join_trans_and_link(
+ &self,
+ trans: Box<Any>,
sess: &Session,
- dep_graph: &DepGraph
- ) -> Self::TranslatedCrate {
- trans.join(sess, dep_graph)
- }
+ dep_graph: &DepGraph,
+ outputs: &OutputFilenames,
+ ) -> Result<(), CompileIncomplete>{
+ use rustc::util::common::time;
+ let trans = trans.downcast::<::back::write::OngoingCrateTranslation>()
+ .expect("Expected LlvmTransCrate's OngoingCrateTranslation, found Box<Any>")
+ .join(sess, dep_graph);
+ if sess.opts.debugging_opts.incremental_info {
+ back::write::dump_incremental_data(&trans);
+ }
- fn link_binary(sess: &Session, trans: &Self::TranslatedCrate, outputs: &OutputFilenames) {
- back::link::link_binary(sess, trans, outputs, &trans.crate_name.as_str());
- }
+ time(sess.time_passes(),
+ "serialize work products",
+ move || rustc_incremental::save_work_products(sess, &dep_graph));
- fn dump_incremental_data(trans: &Self::TranslatedCrate) {
- back::write::dump_incremental_data(trans);
+ sess.compile_status()?;
+
+ if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
+ i == OutputType::Metadata) {
+ return Ok(());
+ }
+
+ // Run the linker on any artifacts that resulted from the LLVM run.
+ // This should produce either a finished executable or library.
+ time(sess.time_passes(), "linking", || {
+ back::link::link_binary(sess, &trans, outputs, &trans.crate_name.as_str());
+ });
+
+ // Now that we won't touch anything in the incremental compilation directory
+ // any more, we can finalize it (which involves renaming it)
+ rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
+
+ Ok(())
}
}
-pub struct ModuleTranslation {
+/// This is the entrypoint for a hot plugged rustc_trans
+#[no_mangle]
+pub fn __rustc_codegen_backend(sess: &Session) -> Box<TransCrate> {
+ LlvmTransCrate::new(sess)
+}
+
+struct ModuleTranslation {
/// The name of the module. When the crate may be saved between
/// compilations, incremental compilation requires that name be
/// unique amongst **all** crates. Therefore, it should contain
/// as the crate name and disambiguator.
name: String,
llmod_id: String,
- pub source: ModuleSource,
- pub kind: ModuleKind,
+ source: ModuleSource,
+ kind: ModuleKind,
}
#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum ModuleKind {
+enum ModuleKind {
Regular,
Metadata,
Allocator,
}
impl ModuleTranslation {
- pub fn llvm(&self) -> Option<&ModuleLlvm> {
+ fn llvm(&self) -> Option<&ModuleLlvm> {
match self.source {
ModuleSource::Translated(ref llvm) => Some(llvm),
ModuleSource::Preexisting(_) => None,
}
}
- pub fn into_compiled_module(self,
+ fn into_compiled_module(self,
emit_obj: bool,
emit_bc: bool,
emit_bc_compressed: bool,
}
#[derive(Debug)]
-pub struct CompiledModule {
- pub name: String,
- pub llmod_id: String,
- pub kind: ModuleKind,
- pub pre_existing: bool,
- pub object: Option<PathBuf>,
- pub bytecode: Option<PathBuf>,
- pub bytecode_compressed: Option<PathBuf>,
+struct CompiledModule {
+ name: String,
+ llmod_id: String,
+ kind: ModuleKind,
+ pre_existing: bool,
+ object: Option<PathBuf>,
+ bytecode: Option<PathBuf>,
+ bytecode_compressed: Option<PathBuf>,
}
-pub enum ModuleSource {
+enum ModuleSource {
/// Copy the `.o` files or whatever from the incr. comp. directory.
Preexisting(WorkProduct),
}
#[derive(Debug)]
-pub struct ModuleLlvm {
+struct ModuleLlvm {
llcx: llvm::ContextRef,
- pub llmod: llvm::ModuleRef,
+ llmod: llvm::ModuleRef,
tm: llvm::TargetMachineRef,
}
}
}
-pub struct CrateTranslation {
- pub crate_name: Symbol,
- pub modules: Vec<CompiledModule>,
+struct CrateTranslation {
+ crate_name: Symbol,
+ modules: Vec<CompiledModule>,
allocator_module: Option<CompiledModule>,
metadata_module: CompiledModule,
- pub link: rustc::middle::cstore::LinkMeta,
- pub metadata: rustc::middle::cstore::EncodedMetadata,
+ link: rustc::middle::cstore::LinkMeta,
+ metadata: rustc::middle::cstore::EncodedMetadata,
windows_subsystem: Option<String>,
linker_info: back::linker::LinkerInfo,
crate_info: CrateInfo,
}
// Misc info we load from metadata to persist beyond the tcx
-pub struct CrateInfo {
+struct CrateInfo {
panic_runtime: Option<CrateNum>,
compiler_builtins: Option<CrateNum>,
profiler_runtime: Option<CrateNum>,
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;
-pub fn init(sess: &Session) {
+static POISONED: AtomicBool = AtomicBool::new(false);
+static INIT: Once = Once::new();
+
+pub(crate) fn init(sess: &Session) {
unsafe {
// Before we touch LLVM, make sure that multithreading is enabled.
- static POISONED: AtomicBool = AtomicBool::new(false);
- static INIT: Once = Once::new();
INIT.call_once(|| {
if llvm::LLVMStartMultithreaded() != 1 {
// use an extra bool to make sure that all future usage of LLVM
}
}
+fn require_inited() {
+ INIT.call_once(|| bug!("llvm is not initialized"));
+ if POISONED.load(Ordering::SeqCst) {
+ bug!("couldn't enable multi-threaded LLVM");
+ }
+}
+
unsafe fn configure_llvm(sess: &Session) {
let mut llvm_c_strs = Vec::new();
let mut llvm_args = Vec::new();
}
pub fn print_version() {
+ // Can be called without initializing LLVM
unsafe {
println!("LLVM version: {}.{}",
llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
}
pub fn print_passes() {
+ // Can be called without initializing LLVM
unsafe { llvm::LLVMRustPrintPasses(); }
}
-pub fn print(req: PrintRequest, sess: &Session) {
+pub(crate) fn print(req: PrintRequest, sess: &Session) {
+ require_inited();
let tm = create_target_machine(sess);
unsafe {
match req {
for i in 0..tupled_arg_tys.len() {
let arg = &fx.fn_ty.args[idx];
idx += 1;
+ if arg.pad.is_some() {
+ llarg_idx += 1;
+ }
arg.store_fn_arg(bx, &mut llarg_idx, place.project_field(bx, i));
}
+++ /dev/null
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Walks the crate looking for items/impl-items/trait-items that have
-//! either a `rustc_symbol_name` or `rustc_item_path` attribute and
-//! generates an error giving, respectively, the symbol name or
-//! item-path. This is used for unit testing the code that generates
-//! paths etc in all kinds of annoying scenarios.
-
-use rustc::hir;
-use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use rustc::ty::TyCtxt;
-use syntax::ast;
-
-use monomorphize::Instance;
-
-const SYMBOL_NAME: &'static str = "rustc_symbol_name";
-const ITEM_PATH: &'static str = "rustc_item_path";
-
-pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
- // if the `rustc_attrs` feature is not enabled, then the
- // attributes we are interested in cannot be present anyway, so
- // skip the walk.
- if !tcx.sess.features.borrow().rustc_attrs {
- return;
- }
-
- tcx.dep_graph.with_ignore(|| {
- let mut visitor = SymbolNamesTest { tcx: tcx };
- // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
- tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
- })
-}
-
-struct SymbolNamesTest<'a, 'tcx:'a> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
-}
-
-impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> {
- fn process_attrs(&mut self,
- node_id: ast::NodeId) {
- let tcx = self.tcx;
- let def_id = tcx.hir.local_def_id(node_id);
- for attr in tcx.get_attrs(def_id).iter() {
- if attr.check_name(SYMBOL_NAME) {
- // for now, can only use on monomorphic names
- let instance = Instance::mono(tcx, def_id);
- let name = self.tcx.symbol_name(instance);
- tcx.sess.span_err(attr.span, &format!("symbol-name({})", name));
- } else if attr.check_name(ITEM_PATH) {
- let path = tcx.item_path_str(def_id);
- tcx.sess.span_err(attr.span, &format!("item-path({})", path));
- }
-
- // (*) The formatting of `tag({})` is chosen so that tests can elect
- // to test the entirety of the string, if they choose, or else just
- // some subset.
- }
- }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for SymbolNamesTest<'a, 'tcx> {
- fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::None
- }
-
- fn visit_item(&mut self, item: &'tcx hir::Item) {
- self.process_attrs(item.id);
- intravisit::walk_item(self, item);
- }
-
- fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
- self.process_attrs(ti.id);
- intravisit::walk_trait_item(self, ti)
- }
-
- fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
- self.process_attrs(ii.id);
- intravisit::walk_impl_item(self, ii)
- }
-}
use type_of::LayoutLlvmExt;
use rustc::hir;
use rustc::mir::mono::{Linkage, Visibility};
-use rustc::ty::{TyCtxt, TypeFoldable};
+use rustc::ty::TypeFoldable;
use rustc::ty::layout::LayoutOf;
use syntax::ast;
use syntax::attr;
-use syntax_pos::Span;
use std::fmt;
pub use rustc::mir::mono::MonoItem;
cx.codegen_unit.name());
}
- fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Span> {
- match *self.as_mono_item() {
- MonoItem::Fn(Instance { def, .. }) => {
- tcx.hir.as_local_node_id(def.def_id())
- }
- MonoItem::Static(node_id) |
- MonoItem::GlobalAsm(node_id) => {
- Some(node_id)
- }
- }.map(|node_id| tcx.hir.span(node_id))
- }
-
fn to_raw_string(&self) -> String {
match *self.as_mono_item() {
MonoItem::Fn(instance) => {
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_mir = { path = "../librustc_mir" }
+rustc_incremental = { path = "../librustc_incremental" }
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(non_snake_case)]
+
+register_long_diagnostics! {
+
+E0558: r##"
+The `export_name` attribute was malformed.
+
+Erroneous code example:
+
+```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
+#[export_name] // error: export_name attribute has invalid format
+pub fn something() {}
+
+fn main() {}
+```
+
+The `export_name` attribute expects a string in order to determine the name of
+the exported symbol. Example:
+
+```
+#[export_name = "some_function"] // ok!
+pub fn something() {}
+
+fn main() {}
+```
+"##,
+
+}
#[macro_use]
extern crate rustc;
extern crate rustc_back;
+extern crate rustc_mir;
+extern crate rustc_incremental;
+#[macro_use]
extern crate syntax;
extern crate syntax_pos;
extern crate rustc_data_structures;
+pub extern crate rustc as __rustc;
+
use rustc::ty::{TyCtxt, Instance};
use rustc::hir;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc::hir::map as hir_map;
use rustc::util::nodemap::NodeSet;
+pub mod diagnostics;
pub mod link;
pub mod trans_crate;
+pub mod symbol_names;
+pub mod symbol_names_test;
/// check for the #[rustc_error] annotation, which forces an
/// error in trans. This is used to write compile-fail tests
}
}).collect()
}
+
+#[cfg(not(stage0))] // remove after the next snapshot
+__build_diagnostic_array! { librustc_trans_utils, DIAGNOSTICS }
--- /dev/null
+// 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.
+
+//! The Rust Linkage Model and Symbol Names
+//! =======================================
+//!
+//! The semantic model of Rust linkage is, broadly, that "there's no global
+//! namespace" between crates. Our aim is to preserve the illusion of this
+//! model despite the fact that it's not *quite* possible to implement on
+//! modern linkers. We initially didn't use system linkers at all, but have
+//! been convinced of their utility.
+//!
+//! There are a few issues to handle:
+//!
+//! - Linkers operate on a flat namespace, so we have to flatten names.
+//! We do this using the C++ namespace-mangling technique. Foo::bar
+//! symbols and such.
+//!
+//! - Symbols for distinct items with the same *name* need to get different
+//! linkage-names. Examples of this are monomorphizations of functions or
+//! items within anonymous scopes that end up having the same path.
+//!
+//! - Symbols in different crates but with same names "within" the crate need
+//! to get different linkage-names.
+//!
+//! - Symbol names should be deterministic: Two consecutive runs of the
+//! compiler over the same code base should produce the same symbol names for
+//! the same items.
+//!
+//! - Symbol names should not depend on any global properties of the code base,
+//! so that small modifications to the code base do not result in all symbols
+//! changing. In previous versions of the compiler, symbol names incorporated
+//! the SVH (Stable Version Hash) of the crate. This scheme turned out to be
+//! infeasible when used in conjunction with incremental compilation because
+//! small code changes would invalidate all symbols generated previously.
+//!
+//! - Even symbols from different versions of the same crate should be able to
+//! live next to each other without conflict.
+//!
+//! In order to fulfill the above requirements the following scheme is used by
+//! the compiler:
+//!
+//! The main tool for avoiding naming conflicts is the incorporation of a 64-bit
+//! hash value into every exported symbol name. Anything that makes a difference
+//! to the symbol being named, but does not show up in the regular path needs to
+//! be fed into this hash:
+//!
+//! - Different monomorphizations of the same item have the same path but differ
+//! in their concrete type parameters, so these parameters are part of the
+//! data being digested for the symbol hash.
+//!
+//! - Rust allows items to be defined in anonymous scopes, such as in
+//! `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have
+//! the path `foo::bar`, since the anonymous scopes do not contribute to the
+//! path of an item. The compiler already handles this case via so-called
+//! disambiguating `DefPaths` which use indices to distinguish items with the
+//! same name. The DefPaths of the functions above are thus `foo[0]::bar[0]`
+//! and `foo[0]::bar[1]`. In order to incorporate this disambiguation
+//! information into the symbol name too, these indices are fed into the
+//! symbol hash, so that the above two symbols would end up with different
+//! hash values.
+//!
+//! The two measures described above suffice to avoid intra-crate conflicts. In
+//! order to also avoid inter-crate conflicts two more measures are taken:
+//!
+//! - The name of the crate containing the symbol is prepended to the symbol
+//! name, i.e. symbols are "crate qualified". For example, a function `foo` in
+//! module `bar` in crate `baz` would get a symbol name like
+//! `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids
+//! simple conflicts between functions from different crates.
+//!
+//! - In order to be able to also use symbols from two versions of the same
+//! crate (which naturally also have the same name), a stronger measure is
+//! required: The compiler accepts an arbitrary "disambiguator" value via the
+//! `-C metadata` commandline argument. This disambiguator is then fed into
+//! the symbol hash of every exported item. Consequently, the symbols in two
+//! identical crates but with different disambiguators are not in conflict
+//! with each other. This facility is mainly intended to be used by build
+//! tools like Cargo.
+//!
+//! A note on symbol name stability
+//! -------------------------------
+//! Previous versions of the compiler resorted to feeding NodeIds into the
+//! symbol hash in order to disambiguate between items with the same path. The
+//! current version of the name generation algorithm takes great care not to do
+//! that, since NodeIds are notoriously unstable: A small change to the
+//! code base will offset all NodeIds after the change and thus, much as using
+//! the SVH in the hash, invalidate an unbounded number of symbol names. This
+//! makes re-using previously compiled code for incremental compilation
+//! virtually impossible. Thus, symbol hash generation exclusively relies on
+//! DefPaths which are much more robust in the face of changes to the code base.
+
+use rustc::middle::weak_lang_items;
+use rustc_mir::monomorphize::Instance;
+use rustc_mir::monomorphize::item::{MonoItem, MonoItemExt, InstantiationMode};
+use rustc::hir::def_id::DefId;
+use rustc::hir::map as hir_map;
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::fold::TypeVisitor;
+use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
+use rustc::ty::maps::Providers;
+use rustc::ty::subst::Substs;
+use rustc::hir::map::definitions::DefPathData;
+use rustc::util::common::record_time;
+
+use syntax::attr;
+use syntax_pos::symbol::Symbol;
+
+use std::fmt::Write;
+
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers {
+ def_symbol_name,
+ symbol_name,
+
+ export_name: |tcx, id| {
+ tcx.get_attrs(id).iter().fold(None, |ia, attr| {
+ if attr.check_name("export_name") {
+ if let s @ Some(_) = attr.value_str() {
+ s
+ } else {
+ struct_span_err!(tcx.sess, attr.span, E0558,
+ "export_name attribute has invalid format")
+ .span_label(attr.span, "did you mean #[export_name=\"*\"]?")
+ .emit();
+ None
+ }
+ } else {
+ ia
+ }
+ })
+ },
+
+ contains_extern_indicator: |tcx, id| {
+ attr::contains_name(&tcx.get_attrs(id), "no_mangle") ||
+ tcx.export_name(id).is_some()
+ },
+
+ ..*providers
+ };
+}
+
+fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+
+ // the DefId of the item this name is for
+ def_id: DefId,
+
+ // instance this name will be for
+ instance: Instance<'tcx>,
+
+ // type of the item, without any generic
+ // parameters substituted; this is
+ // included in the hash as a kind of
+ // safeguard.
+ item_type: Ty<'tcx>,
+
+ // values for generic type parameters,
+ // if any.
+ substs: &'tcx Substs<'tcx>)
+ -> u64 {
+ debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
+
+ let mut hasher = ty::util::TypeIdHasher::<u64>::new(tcx);
+
+ record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
+ // the main symbol name is not necessarily unique; hash in the
+ // compiler's internal def-path, guaranteeing each symbol has a
+ // truly unique path
+ hasher.hash(tcx.def_path_hash(def_id));
+
+ // Include the main item-type. Note that, in this case, the
+ // assertions about `needs_subst` may not hold, but this item-type
+ // ought to be the same for every reference anyway.
+ assert!(!item_type.has_erasable_regions());
+ hasher.visit_ty(item_type);
+
+ // If this is a function, we hash the signature as well.
+ // This is not *strictly* needed, but it may help in some
+ // situations, see the `run-make/a-b-a-linker-guard` test.
+ if let ty::TyFnDef(..) = item_type.sty {
+ item_type.fn_sig(tcx).visit_with(&mut hasher);
+ }
+
+ // also include any type parameters (for generic items)
+ assert!(!substs.has_erasable_regions());
+ assert!(!substs.needs_subst());
+ substs.visit_with(&mut hasher);
+
+ let mut avoid_cross_crate_conflicts = false;
+
+ // If this is an instance of a generic function, we also hash in
+ // the ID of the instantiating crate. This avoids symbol conflicts
+ // in case the same instances is emitted in two crates of the same
+ // project.
+ if substs.types().next().is_some() {
+ avoid_cross_crate_conflicts = true;
+ }
+
+ // If we're dealing with an instance of a function that's inlined from
+ // another crate but we're marking it as globally shared to our
+ // compliation (aka we're not making an internal copy in each of our
+ // codegen units) then this symbol may become an exported (but hidden
+ // visibility) symbol. This means that multiple crates may do the same
+ // and we want to be sure to avoid any symbol conflicts here.
+ match MonoItem::Fn(instance).instantiation_mode(tcx) {
+ InstantiationMode::GloballyShared { may_conflict: true } => {
+ avoid_cross_crate_conflicts = true;
+ }
+ _ => {}
+ }
+
+ if avoid_cross_crate_conflicts {
+ hasher.hash(tcx.crate_name.as_str());
+ hasher.hash(tcx.sess.local_crate_disambiguator());
+ }
+ });
+
+ // 64 bits should be enough to avoid collisions.
+ hasher.finish()
+}
+
+fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+ -> ty::SymbolName
+{
+ let mut buffer = SymbolPathBuffer::new();
+ item_path::with_forced_absolute_paths(|| {
+ tcx.push_item_path(&mut buffer, def_id);
+ });
+ buffer.into_interned()
+}
+
+fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
+ -> ty::SymbolName
+{
+ ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_str() }
+}
+
+fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
+ -> String
+{
+ let def_id = instance.def_id();
+ let substs = instance.substs;
+
+ debug!("symbol_name(def_id={:?}, substs={:?})",
+ def_id, substs);
+
+ let node_id = tcx.hir.as_local_node_id(def_id);
+
+ if let Some(id) = node_id {
+ if tcx.sess.plugin_registrar_fn.get() == Some(id) {
+ let disambiguator = tcx.sess.local_crate_disambiguator();
+ return tcx.sess.generate_plugin_registrar_symbol(disambiguator);
+ }
+ if tcx.sess.derive_registrar_fn.get() == Some(id) {
+ let disambiguator = tcx.sess.local_crate_disambiguator();
+ return tcx.sess.generate_derive_registrar_symbol(disambiguator);
+ }
+ }
+
+ // FIXME(eddyb) Precompute a custom symbol name based on attributes.
+ let attrs = tcx.get_attrs(def_id);
+ let is_foreign = if let Some(id) = node_id {
+ match tcx.hir.get(id) {
+ hir_map::NodeForeignItem(_) => true,
+ _ => false
+ }
+ } else {
+ tcx.is_foreign_item(def_id)
+ };
+
+ if let Some(name) = weak_lang_items::link_name(&attrs) {
+ return name.to_string();
+ }
+
+ if is_foreign {
+ if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") {
+ return name.to_string();
+ }
+ // Don't mangle foreign items.
+ return tcx.item_name(def_id).to_string();
+ }
+
+ if let Some(name) = tcx.export_name(def_id) {
+ // Use provided name
+ return name.to_string();
+ }
+
+ if attr::contains_name(&attrs, "no_mangle") {
+ // Don't mangle
+ return tcx.item_name(def_id).to_string();
+ }
+
+ // We want to compute the "type" of this item. Unfortunately, some
+ // kinds of items (e.g., closures) don't have an entry in the
+ // item-type array. So walk back up the find the closest parent
+ // that DOES have an entry.
+ let mut ty_def_id = def_id;
+ let instance_ty;
+ loop {
+ let key = tcx.def_key(ty_def_id);
+ match key.disambiguated_data.data {
+ DefPathData::TypeNs(_) |
+ DefPathData::ValueNs(_) => {
+ instance_ty = tcx.type_of(ty_def_id);
+ break;
+ }
+ _ => {
+ // if we're making a symbol for something, there ought
+ // to be a value or type-def or something in there
+ // *somewhere*
+ ty_def_id.index = key.parent.unwrap_or_else(|| {
+ bug!("finding type for {:?}, encountered def-id {:?} with no \
+ parent", def_id, ty_def_id);
+ });
+ }
+ }
+ }
+
+ // Erase regions because they may not be deterministic when hashed
+ // and should not matter anyhow.
+ let instance_ty = tcx.erase_regions(&instance_ty);
+
+ let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs);
+
+ SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash)
+}
+
+// Follow C++ namespace-mangling style, see
+// http://en.wikipedia.org/wiki/Name_mangling for more info.
+//
+// It turns out that on macOS you can actually have arbitrary symbols in
+// function names (at least when given to LLVM), but this is not possible
+// when using unix's linker. Perhaps one day when we just use a linker from LLVM
+// we won't need to do this name mangling. The problem with name mangling is
+// that it seriously limits the available characters. For example we can't
+// have things like &T in symbol names when one would theoretically
+// want them for things like impls of traits on that type.
+//
+// To be able to work on all platforms and get *some* reasonable output, we
+// use C++ name-mangling.
+struct SymbolPathBuffer {
+ result: String,
+ temp_buf: String
+}
+
+impl SymbolPathBuffer {
+ fn new() -> Self {
+ let mut result = SymbolPathBuffer {
+ result: String::with_capacity(64),
+ temp_buf: String::with_capacity(16)
+ };
+ result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
+ result
+ }
+
+ fn from_interned(symbol: ty::SymbolName) -> Self {
+ let mut result = SymbolPathBuffer {
+ result: String::with_capacity(64),
+ temp_buf: String::with_capacity(16)
+ };
+ result.result.push_str(&symbol.name);
+ result
+ }
+
+ fn into_interned(self) -> ty::SymbolName {
+ ty::SymbolName { name: Symbol::intern(&self.result).as_str() }
+ }
+
+ fn finish(mut self, hash: u64) -> String {
+ // E = end name-sequence
+ let _ = write!(self.result, "17h{:016x}E", hash);
+ self.result
+ }
+}
+
+impl ItemPathBuffer for SymbolPathBuffer {
+ fn root_mode(&self) -> &RootMode {
+ const ABSOLUTE: &'static RootMode = &RootMode::Absolute;
+ ABSOLUTE
+ }
+
+ fn push(&mut self, text: &str) {
+ self.temp_buf.clear();
+ let need_underscore = sanitize(&mut self.temp_buf, text);
+ let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize));
+ if need_underscore {
+ self.result.push('_');
+ }
+ self.result.push_str(&self.temp_buf);
+ }
+}
+
+// Name sanitation. LLVM will happily accept identifiers with weird names, but
+// gas doesn't!
+// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
+//
+// returns true if an underscore must be added at the start
+pub fn sanitize(result: &mut String, s: &str) -> bool {
+ for c in s.chars() {
+ match c {
+ // Escape these with $ sequences
+ '@' => result.push_str("$SP$"),
+ '*' => result.push_str("$BP$"),
+ '&' => result.push_str("$RF$"),
+ '<' => result.push_str("$LT$"),
+ '>' => result.push_str("$GT$"),
+ '(' => result.push_str("$LP$"),
+ ')' => result.push_str("$RP$"),
+ ',' => result.push_str("$C$"),
+
+ // '.' doesn't occur in types and functions, so reuse it
+ // for ':' and '-'
+ '-' | ':' => result.push('.'),
+
+ // These are legal symbols
+ 'a' ... 'z'
+ | 'A' ... 'Z'
+ | '0' ... '9'
+ | '_' | '.' | '$' => result.push(c),
+
+ _ => {
+ result.push('$');
+ for c in c.escape_unicode().skip(1) {
+ match c {
+ '{' => {},
+ '}' => result.push('$'),
+ c => result.push(c),
+ }
+ }
+ }
+ }
+ }
+
+ // Underscore-qualify anything that didn't start as an ident.
+ !result.is_empty() &&
+ result.as_bytes()[0] != '_' as u8 &&
+ ! (result.as_bytes()[0] as char).is_xid_start()
+}
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Walks the crate looking for items/impl-items/trait-items that have
+//! either a `rustc_symbol_name` or `rustc_item_path` attribute and
+//! generates an error giving, respectively, the symbol name or
+//! item-path. This is used for unit testing the code that generates
+//! paths etc in all kinds of annoying scenarios.
+
+use rustc::hir;
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
+use rustc::ty::TyCtxt;
+use syntax::ast;
+
+use rustc_mir::monomorphize::Instance;
+
+const SYMBOL_NAME: &'static str = "rustc_symbol_name";
+const ITEM_PATH: &'static str = "rustc_item_path";
+
+pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ // if the `rustc_attrs` feature is not enabled, then the
+ // attributes we are interested in cannot be present anyway, so
+ // skip the walk.
+ if !tcx.sess.features.borrow().rustc_attrs {
+ return;
+ }
+
+ tcx.dep_graph.with_ignore(|| {
+ let mut visitor = SymbolNamesTest { tcx: tcx };
+ // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
+ tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
+ })
+}
+
+struct SymbolNamesTest<'a, 'tcx:'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+}
+
+impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> {
+ fn process_attrs(&mut self,
+ node_id: ast::NodeId) {
+ let tcx = self.tcx;
+ let def_id = tcx.hir.local_def_id(node_id);
+ for attr in tcx.get_attrs(def_id).iter() {
+ if attr.check_name(SYMBOL_NAME) {
+ // for now, can only use on monomorphic names
+ let instance = Instance::mono(tcx, def_id);
+ let name = self.tcx.symbol_name(instance);
+ tcx.sess.span_err(attr.span, &format!("symbol-name({})", name));
+ } else if attr.check_name(ITEM_PATH) {
+ let path = tcx.item_path_str(def_id);
+ tcx.sess.span_err(attr.span, &format!("item-path({})", path));
+ }
+
+ // (*) The formatting of `tag({})` is chosen so that tests can elect
+ // to test the entirety of the string, if they choose, or else just
+ // some subset.
+ }
+ }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for SymbolNamesTest<'a, 'tcx> {
+ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_item(&mut self, item: &'tcx hir::Item) {
+ self.process_attrs(item.id);
+ intravisit::walk_item(self, item);
+ }
+
+ fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
+ self.process_attrs(ti.id);
+ intravisit::walk_trait_item(self, ti)
+ }
+
+ fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
+ self.process_attrs(ii.id);
+ intravisit::walk_impl_item(self, ii)
+ }
+}
use std::io::{self, Cursor};
use std::fs::File;
use std::path::Path;
+use std::rc::Rc;
use std::sync::mpsc;
use rustc_data_structures::owning_ref::{ErasedBoxRef, OwningRef};
use syntax::symbol::Symbol;
use rustc::hir::def_id::LOCAL_CRATE;
-use rustc::session::Session;
-use rustc::session::config::{CrateType, OutputFilenames};
+use rustc::session::{Session, CompileIncomplete};
+use rustc::session::config::{CrateType, OutputFilenames, PrintRequest};
use rustc::ty::TyCtxt;
use rustc::ty::maps::Providers;
use rustc::middle::cstore::EncodedMetadata;
-use rustc::middle::cstore::MetadataLoader as MetadataLoaderTrait;
+use rustc::middle::cstore::MetadataLoader;
use rustc::dep_graph::DepGraph;
use rustc_back::target::Target;
+use rustc_mir::monomorphize::collector;
use link::{build_link_meta, out_filename};
pub trait TransCrate {
- type MetadataLoader: MetadataLoaderTrait;
- type OngoingCrateTranslation;
- type TranslatedCrate;
+ fn print(&self, _req: PrintRequest, _sess: &Session) {}
+ fn target_features(&self, _sess: &Session) -> Vec<Symbol> { vec![] }
- fn metadata_loader() -> Box<MetadataLoaderTrait>;
- fn provide(_providers: &mut Providers);
- fn provide_extern(_providers: &mut Providers);
+ fn metadata_loader(&self) -> Box<MetadataLoader>;
+ fn provide(&self, _providers: &mut Providers);
+ fn provide_extern(&self, _providers: &mut Providers);
fn trans_crate<'a, 'tcx>(
+ &self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
rx: mpsc::Receiver<Box<Any + Send>>
- ) -> Self::OngoingCrateTranslation;
- fn join_trans(
- trans: Self::OngoingCrateTranslation,
+ ) -> Box<Any>;
+
+ /// This is called on the returned `Box<Any>` from `trans_crate`
+ ///
+ /// # Panics
+ ///
+ /// Panics when the passed `Box<Any>` was not returned by `trans_crate`.
+ fn join_trans_and_link(
+ &self,
+ trans: Box<Any>,
sess: &Session,
- dep_graph: &DepGraph
- ) -> Self::TranslatedCrate;
- fn link_binary(sess: &Session, trans: &Self::TranslatedCrate, outputs: &OutputFilenames);
- fn dump_incremental_data(trans: &Self::TranslatedCrate);
+ dep_graph: &DepGraph,
+ outputs: &OutputFilenames,
+ ) -> Result<(), CompileIncomplete>;
}
pub struct DummyTransCrate;
impl TransCrate for DummyTransCrate {
- type MetadataLoader = DummyMetadataLoader;
- type OngoingCrateTranslation = ();
- type TranslatedCrate = ();
-
- fn metadata_loader() -> Box<MetadataLoaderTrait> {
+ fn metadata_loader(&self) -> Box<MetadataLoader> {
box DummyMetadataLoader(())
}
- fn provide(_providers: &mut Providers) {
+ fn provide(&self, _providers: &mut Providers) {
bug!("DummyTransCrate::provide");
}
- fn provide_extern(_providers: &mut Providers) {
+ fn provide_extern(&self, _providers: &mut Providers) {
bug!("DummyTransCrate::provide_extern");
}
fn trans_crate<'a, 'tcx>(
+ &self,
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
_rx: mpsc::Receiver<Box<Any + Send>>
- ) -> Self::OngoingCrateTranslation {
+ ) -> Box<Any> {
bug!("DummyTransCrate::trans_crate");
}
- fn join_trans(
- _trans: Self::OngoingCrateTranslation,
+ fn join_trans_and_link(
+ &self,
+ _trans: Box<Any>,
_sess: &Session,
- _dep_graph: &DepGraph
- ) -> Self::TranslatedCrate {
- bug!("DummyTransCrate::join_trans");
- }
-
- fn link_binary(_sess: &Session, _trans: &Self::TranslatedCrate, _outputs: &OutputFilenames) {
- bug!("DummyTransCrate::link_binary");
- }
-
- fn dump_incremental_data(_trans: &Self::TranslatedCrate) {
- bug!("DummyTransCrate::dump_incremental_data");
+ _dep_graph: &DepGraph,
+ _outputs: &OutputFilenames,
+ ) -> Result<(), CompileIncomplete> {
+ bug!("DummyTransCrate::join_trans_and_link");
}
}
pub struct DummyMetadataLoader(());
-impl MetadataLoaderTrait for DummyMetadataLoader {
+impl MetadataLoader for DummyMetadataLoader {
fn get_rlib_metadata(
&self,
_target: &Target,
pub struct NoLlvmMetadataLoader;
-impl MetadataLoaderTrait for NoLlvmMetadataLoader {
+impl MetadataLoader for NoLlvmMetadataLoader {
fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<ErasedBoxRef<[u8]>, String> {
let file = File::open(filename)
.map_err(|e| format!("metadata file open err: {:?}", e))?;
}
}
-pub struct MetadataOnlyTransCrate;
+pub struct MetadataOnlyTransCrate(());
pub struct OngoingCrateTranslation {
metadata: EncodedMetadata,
metadata_version: Vec<u8>,
crate_name: Symbol,
}
-pub struct TranslatedCrate(OngoingCrateTranslation);
impl MetadataOnlyTransCrate {
- #[allow(dead_code)]
- pub fn new() -> Self {
- MetadataOnlyTransCrate
+ pub fn new(sess: &Session) -> Box<TransCrate> {
+ for cty in sess.opts.crate_types.iter() {
+ match *cty {
+ CrateType::CrateTypeRlib | CrateType::CrateTypeDylib |
+ CrateType::CrateTypeExecutable => {},
+ _ => {
+ sess.parse_sess.span_diagnostic.warn(
+ &format!("LLVM unsupported, so output type {} is not supported", cty)
+ );
+ },
+ }
+ }
+
+ box MetadataOnlyTransCrate(())
}
}
impl TransCrate for MetadataOnlyTransCrate {
- type MetadataLoader = NoLlvmMetadataLoader;
- type OngoingCrateTranslation = OngoingCrateTranslation;
- type TranslatedCrate = TranslatedCrate;
-
- fn metadata_loader() -> Box<MetadataLoaderTrait> {
+ fn metadata_loader(&self) -> Box<MetadataLoader> {
box NoLlvmMetadataLoader
}
- fn provide(_providers: &mut Providers) {}
- fn provide_extern(_providers: &mut Providers) {}
+ fn provide(&self, providers: &mut Providers) {
+ ::symbol_names::provide(providers);
+ providers.target_features_enabled = |_tcx, _id| {
+ Rc::new(Vec::new()) // Just a dummy
+ };
+ }
+ fn provide_extern(&self, _providers: &mut Providers) {}
fn trans_crate<'a, 'tcx>(
+ &self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_rx: mpsc::Receiver<Box<Any + Send>>
- ) -> Self::OngoingCrateTranslation {
+ ) -> Box<Any> {
+ use rustc_mir::monomorphize::item::MonoItem;
+
::check_for_rustc_errors_attr(tcx);
+ ::symbol_names_test::report_symbol_names(tcx);
+ ::rustc_incremental::assert_dep_graph(tcx);
+ ::rustc_incremental::assert_module_sources::assert_module_sources(tcx);
+ ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx,
+ collector::collect_crate_mono_items(
+ tcx,
+ collector::MonoItemCollectionMode::Eager
+ ).0.iter()
+ );
+ ::rustc::middle::dependency_format::calculate(tcx);
let _ = tcx.link_args(LOCAL_CRATE);
let _ = tcx.native_libraries(LOCAL_CRATE);
+ for trans_item in
+ collector::collect_crate_mono_items(
+ tcx,
+ collector::MonoItemCollectionMode::Eager
+ ).0 {
+ match trans_item {
+ MonoItem::Fn(inst) => {
+ let def_id = inst.def_id();
+ if def_id.is_local() {
+ let _ = tcx.export_name(def_id);
+ let _ = tcx.contains_extern_indicator(def_id);
+ let _ = inst.def.is_inline(tcx);
+ let attrs = inst.def.attrs(tcx);
+ let _ =
+ ::syntax::attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs);
+ }
+ }
+ _ => {}
+ }
+ }
tcx.sess.abort_if_errors();
let link_meta = build_link_meta(tcx.crate_hash(LOCAL_CRATE));
let exported_symbols = ::find_exported_symbols(tcx);
let metadata = tcx.encode_metadata(&link_meta, &exported_symbols);
- OngoingCrateTranslation {
+ box OngoingCrateTranslation {
metadata: metadata,
metadata_version: tcx.metadata_encoding_version().to_vec(),
crate_name: tcx.crate_name(LOCAL_CRATE),
}
}
- fn join_trans(
- trans: Self::OngoingCrateTranslation,
- _sess: &Session,
+ fn join_trans_and_link(
+ &self,
+ trans: Box<Any>,
+ sess: &Session,
_dep_graph: &DepGraph,
- ) -> Self::TranslatedCrate {
- TranslatedCrate(trans)
- }
-
- fn link_binary(sess: &Session, trans: &Self::TranslatedCrate, outputs: &OutputFilenames) {
+ outputs: &OutputFilenames,
+ ) -> Result<(), CompileIncomplete> {
+ let trans = trans.downcast::<OngoingCrateTranslation>()
+ .expect("Expected MetadataOnlyTransCrate's OngoingCrateTranslation, found Box<Any>");
for &crate_type in sess.opts.crate_types.iter() {
if crate_type != CrateType::CrateTypeRlib && crate_type != CrateType::CrateTypeDylib {
continue;
}
let output_name =
- out_filename(sess, crate_type, &outputs, &trans.0.crate_name.as_str());
- let mut compressed = trans.0.metadata_version.clone();
+ out_filename(sess, crate_type, &outputs, &trans.crate_name.as_str());
+ let mut compressed = trans.metadata_version.clone();
let metadata = if crate_type == CrateType::CrateTypeDylib {
DeflateEncoder::new(&mut compressed, Compression::fast())
- .write_all(&trans.0.metadata.raw_data)
+ .write_all(&trans.metadata.raw_data)
.unwrap();
&compressed
} else {
- &trans.0.metadata.raw_data
+ &trans.metadata.raw_data
};
let mut builder = Builder::new(File::create(&output_name).unwrap());
let header = Header::new("rust.metadata.bin".to_string(), metadata.len() as u64);
builder.append(&header, Cursor::new(metadata)).unwrap();
}
+ sess.abort_if_errors();
if !sess.opts.crate_types.contains(&CrateType::CrateTypeRlib)
- && !sess.opts.crate_types.contains(&CrateType::CrateTypeDylib) {
+ && !sess.opts.crate_types.contains(&CrateType::CrateTypeDylib)
+ {
sess.fatal("Executables are not supported by the metadata-only backend.");
}
+ Ok(())
}
-
- fn dump_incremental_data(_trans: &Self::TranslatedCrate) {}
}
}
}
}
- let mut err = type_error_struct!(self.tcx.sess, call_expr.span, callee_ty, E0618,
- "expected function, found `{}`",
- if let Some(ref path) = unit_variant {
- path.to_string()
- } else {
- callee_ty.to_string()
- });
- if let Some(path) = unit_variant {
- err.help(&format!("did you mean to write `{}`?", path));
+
+ let mut err = type_error_struct!(
+ self.tcx.sess,
+ call_expr.span,
+ callee_ty,
+ E0618,
+ "expected function, found {}",
+ match unit_variant {
+ Some(ref path) => format!("enum variant `{}`", path),
+ None => format!("`{}`", callee_ty),
+ });
+
+ err.span_label(call_expr.span, "not a function");
+
+ if let Some(ref path) = unit_variant {
+ err.span_suggestion(call_expr.span,
+ &format!("`{}` is a unit variant, you need to write it \
+ without the parenthesis", path),
+ path.to_string());
}
if let hir::ExprCall(ref expr, _) = call_expr.node {
_ => self.tcx.hir.span_if_local(def.def_id())
};
if let Some(span) = def_span {
- err.span_note(span, "defined here");
+ let name = match unit_variant {
+ Some(path) => path,
+ None => callee_ty.to_string(),
+ };
+ err.span_label(span, format!("`{}` defined here", name));
}
}
self_descr);
err.span_label(impl_m_span, format!("`{}` used in impl", self_descr));
if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
- err.span_label(span, format!("trait declared without `{}`", self_descr));
+ err.span_label(span, format!("trait method declared without `{}`", self_descr));
+ } else {
+ err.note_trait_signature(trait_m.name.to_string(),
+ trait_m.signature(&tcx));
}
err.emit();
return Err(ErrorReported);
not in the impl",
trait_m.name,
self_descr);
- err.span_label(impl_m_span,
- format!("expected `{}` in impl", self_descr));
+ err.span_label(impl_m_span, format!("expected `{}` in impl", self_descr));
if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
err.span_label(span, format!("`{}` used in trait", self_descr));
} else {
use rustc::traits::ObligationCause;
use syntax::ast;
+use syntax::util::parser::AssocOp;
use syntax_pos::{self, Span};
use rustc::hir;
use rustc::hir::print;
if let Some((msg, suggestion)) = self.check_ref(expr, checked_ty, expected) {
err.span_suggestion(expr.span, msg, suggestion);
- } else {
+ } else if !self.check_for_cast(&mut err, expr, expr_ty, expected) {
let methods = self.get_conversion_methods(expected, checked_ty);
if let Ok(expr_text) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
let suggestions = iter::repeat(expr_text).zip(methods.iter())
// Maybe remove `&`?
hir::ExprAddrOf(_, ref expr) => {
if let Ok(code) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
- return Some(("consider removing the borrow",
- code));
+ return Some(("consider removing the borrow", code));
}
}
format!("*{}", code)));
}
}
- },
+ }
}
}
None
_ => None,
}
}
+
+ fn check_for_cast(&self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ expr: &hir::Expr,
+ checked_ty: Ty<'tcx>,
+ expected_ty: Ty<'tcx>)
+ -> bool {
+ let will_truncate = "will truncate the source value";
+ let depending_on_isize = "will truncate or zero-extend depending on the bit width of \
+ `isize`";
+ let depending_on_usize = "will truncate or zero-extend depending on the bit width of \
+ `usize`";
+ let will_sign_extend = "will sign-extend the source value";
+ let will_zero_extend = "will zero-extend the source value";
+
+ // If casting this expression to a given numeric type would be appropriate in case of a type
+ // mismatch.
+ //
+ // We want to minimize the amount of casting operations that are suggested, as it can be a
+ // lossy operation with potentially bad side effects, so we only suggest when encountering
+ // an expression that indicates that the original type couldn't be directly changed.
+ //
+ // For now, don't suggest casting with `as`.
+ let can_cast = false;
+
+ let needs_paren = expr.precedence().order() < (AssocOp::As.precedence() as i8);
+
+ if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) {
+ let msg = format!("you can cast an `{}` to `{}`", checked_ty, expected_ty);
+ let cast_suggestion = format!("{}{}{} as {}",
+ if needs_paren { "(" } else { "" },
+ src,
+ if needs_paren { ")" } else { "" },
+ expected_ty);
+ let into_suggestion = format!("{}{}{}.into()",
+ if needs_paren { "(" } else { "" },
+ src,
+ if needs_paren { ")" } else { "" });
+
+ match (&expected_ty.sty, &checked_ty.sty) {
+ (&ty::TyInt(ref exp), &ty::TyInt(ref found)) => {
+ match (found.bit_width(), exp.bit_width()) {
+ (Some(found), Some(exp)) if found > exp => {
+ if can_cast {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}", msg, will_truncate),
+ cast_suggestion);
+ }
+ }
+ (None, _) | (_, None) => {
+ if can_cast {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}",
+ msg,
+ depending_on_isize),
+ cast_suggestion);
+ }
+ }
+ _ => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}", msg, will_sign_extend),
+ into_suggestion);
+ }
+ }
+ true
+ }
+ (&ty::TyUint(ref exp), &ty::TyUint(ref found)) => {
+ match (found.bit_width(), exp.bit_width()) {
+ (Some(found), Some(exp)) if found > exp => {
+ if can_cast {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}", msg, will_truncate),
+ cast_suggestion);
+ }
+ }
+ (None, _) | (_, None) => {
+ if can_cast {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}",
+ msg,
+ depending_on_usize),
+ cast_suggestion);
+ }
+ }
+ _ => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}", msg, will_zero_extend),
+ into_suggestion);
+ }
+ }
+ true
+ }
+ (&ty::TyInt(ref exp), &ty::TyUint(ref found)) => {
+ if can_cast {
+ match (found.bit_width(), exp.bit_width()) {
+ (Some(found), Some(exp)) if found > exp - 1 => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}", msg, will_truncate),
+ cast_suggestion);
+ }
+ (None, None) => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}", msg, will_truncate),
+ cast_suggestion);
+ }
+ (None, _) => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}",
+ msg,
+ depending_on_isize),
+ cast_suggestion);
+ }
+ (_, None) => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}",
+ msg,
+ depending_on_usize),
+ cast_suggestion);
+ }
+ _ => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}", msg, will_zero_extend),
+ cast_suggestion);
+ }
+ }
+ }
+ true
+ }
+ (&ty::TyUint(ref exp), &ty::TyInt(ref found)) => {
+ if can_cast {
+ match (found.bit_width(), exp.bit_width()) {
+ (Some(found), Some(exp)) if found - 1 > exp => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}", msg, will_truncate),
+ cast_suggestion);
+ }
+ (None, None) => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}", msg, will_sign_extend),
+ cast_suggestion);
+ }
+ (None, _) => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}",
+ msg,
+ depending_on_usize),
+ cast_suggestion);
+ }
+ (_, None) => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}",
+ msg,
+ depending_on_isize),
+ cast_suggestion);
+ }
+ _ => {
+ err.span_suggestion(expr.span,
+ &format!("{}, which {}", msg, will_sign_extend),
+ cast_suggestion);
+ }
+ }
+ }
+ true
+ }
+ (&ty::TyFloat(ref exp), &ty::TyFloat(ref found)) => {
+ if found.bit_width() < exp.bit_width() {
+ err.span_suggestion(expr.span,
+ &format!("{} in a lossless way",
+ msg),
+ into_suggestion);
+ } else if can_cast {
+ err.span_suggestion(expr.span,
+ &format!("{}, producing the closest possible value",
+ msg),
+ cast_suggestion);
+ err.warn("casting here will cause undefined behavior if the value is \
+ finite but larger or smaller than the largest or smallest \
+ finite value representable by `f32` (this is a bug and will be \
+ fixed)");
+ }
+ true
+ }
+ (&ty::TyUint(_), &ty::TyFloat(_)) | (&ty::TyInt(_), &ty::TyFloat(_)) => {
+ if can_cast {
+ err.span_suggestion(expr.span,
+ &format!("{}, rounding the float towards zero",
+ msg),
+ cast_suggestion);
+ err.warn("casting here will cause undefined behavior if the rounded value \
+ cannot be represented by the target integer type, including \
+ `Inf` and `NaN` (this is a bug and will be fixed)");
+ }
+ true
+ }
+ (&ty::TyFloat(ref exp), &ty::TyUint(ref found)) => {
+ // if `found` is `None` (meaning found is `usize`), don't suggest `.into()`
+ if exp.bit_width() > found.bit_width().unwrap_or(256) {
+ err.span_suggestion(expr.span,
+ &format!("{}, producing the floating point \
+ representation of the integer",
+ msg),
+ into_suggestion);
+ } else if can_cast {
+ err.span_suggestion(expr.span,
+ &format!("{}, producing the floating point \
+ representation of the integer, rounded if \
+ necessary",
+ msg),
+ cast_suggestion);
+ }
+ true
+ }
+ (&ty::TyFloat(ref exp), &ty::TyInt(ref found)) => {
+ // if `found` is `None` (meaning found is `isize`), don't suggest `.into()`
+ if exp.bit_width() > found.bit_width().unwrap_or(256) {
+ err.span_suggestion(expr.span,
+ &format!("{}, producing the floating point \
+ representation of the integer",
+ msg),
+ into_suggestion);
+ } else if can_cast {
+ err.span_suggestion(expr.span,
+ &format!("{}, producing the floating point \
+ representation of the integer, rounded if \
+ necessary",
+ msg),
+ cast_suggestion);
+ }
+ true
+ }
+ _ => false,
+ }
+ } else {
+ false
+ }
+ }
}
use rustc::ty::fold::TypeFoldable;
use rustc::ty::maps::Providers;
use rustc::ty::util::{Representability, IntTypeExt};
+use rustc::ty::layout::LayoutOf;
use errors::{DiagnosticBuilder, DiagnosticId};
use require_c_abi_if_variadic;
use session::{CompileIncomplete, config, Session};
check_simd(tcx, span, def_id);
}
+ check_transparent(tcx, span, def_id);
check_packed(tcx, span, def_id);
}
false
}
+fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) {
+ let adt = tcx.adt_def(def_id);
+ if !adt.repr.transparent() {
+ return;
+ }
+
+ // For each field, figure out if it's known to be a ZST and align(1)
+ let field_infos: Vec<_> = adt.non_enum_variant().fields.iter().map(|field| {
+ let ty = field.ty(tcx, Substs::identity_for_item(tcx, field.did));
+ let param_env = tcx.param_env(field.did);
+ let layout = (tcx, param_env).layout_of(ty);
+ // We are currently checking the type this field came from, so it must be local
+ let span = tcx.hir.span_if_local(field.did).unwrap();
+ let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false);
+ let align1 = layout.map(|layout| layout.align.abi() == 1).unwrap_or(false);
+ (span, zst, align1)
+ }).collect();
+
+ let non_zst_fields = field_infos.iter().filter(|(_span, zst, _align1)| !*zst);
+ let non_zst_count = non_zst_fields.clone().count();
+ if non_zst_count != 1 {
+ let field_spans: Vec<_> = non_zst_fields.map(|(span, _zst, _align1)| *span).collect();
+ struct_span_err!(tcx.sess, sp, E0690,
+ "transparent struct needs exactly one non-zero-sized field, but has {}",
+ non_zst_count)
+ .span_note(field_spans, "non-zero-sized field")
+ .emit();
+ }
+ for &(span, zst, align1) in &field_infos {
+ if zst && !align1 {
+ span_err!(tcx.sess, span, E0691,
+ "zero-sized field in transparent struct has alignment larger than 1");
+ }
+ }
+}
+
#[allow(trivial_numeric_casts)]
pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
sp: Span,
let _ = (2.0 as f32).powi(2);
```
"##,
+
+E0690: r##"
+A struct with the representation hint `repr(transparent)` had zero or more than
+on fields that were not guaranteed to be zero-sized.
+
+Erroneous code example:
+
+```compile_fail,E0690
+#![feature(repr_transparent)]
+
+#[repr(transparent)]
+struct LengthWithUnit<U> { // error: transparent struct needs exactly one
+ value: f32, // non-zero-sized field, but has 2
+ unit: U,
+}
+```
+
+Because transparent structs are represented exactly like one of their fields at
+run time, said field must be uniquely determined. If there is no field, or if
+there are multiple fields, it is not clear how the struct should be represented.
+Note that fields of zero-typed types (e.g., `PhantomData`) can also exist
+alongside the field that contains the actual data, they do not count for this
+error. When generic types are involved (as in the above example), an error is
+reported because the type parameter could be non-zero-sized.
+
+To combine `repr(transparent)` with type parameters, `PhantomData` may be
+useful:
+
+```
+#![feature(repr_transparent)]
+
+use std::marker::PhantomData;
+
+#[repr(transparent)]
+struct LengthWithUnit<U> {
+ value: f32,
+ unit: PhantomData<U>,
+}
+```
+"##,
+
+E0691: r##"
+A struct with the `repr(transparent)` representation hint contains a zero-sized
+field that requires non-trivial alignment.
+
+Erroneous code example:
+
+```compile_fail,E0691
+#![feature(repr_transparent, repr_align, attr_literals)]
+
+#[repr(align(32))]
+struct ForceAlign32;
+
+#[repr(transparent)]
+struct Wrapper(f32, ForceAlign32); // error: zero-sized field in transparent
+ // struct has alignment larger than 1
+```
+
+A transparent struct is supposed to be represented exactly like the piece of
+data it contains. Zero-sized fields with different alignment requirements
+potentially conflict with this property. In the example above, `Wrapper` would
+have to be aligned to 32 bytes even though `f32` has a smaller alignment
+requirement.
+
+Consider removing the over-aligned zero-sized field:
+
+```
+#![feature(repr_transparent)]
+
+#[repr(transparent)]
+struct Wrapper(f32);
+```
+
+Alternatively, `PhantomData<T>` has alignment 1 for all `T`, so you can use it
+if you need to keep the field for some reason:
+
+```
+#![feature(repr_transparent, repr_align, attr_literals)]
+
+use std::marker::PhantomData;
+
+#[repr(align(32))]
+struct ForceAlign32;
+
+#[repr(transparent)]
+struct Wrapper(f32, PhantomData<ForceAlign32>);
+```
+
+Note that empty arrays `[T; 0]` have the same alignment requirement as the
+element type `T`. Also note that the error is conservatively reported even when
+the alignment of the zero-sized type is less than or equal to the data field's
+alignment.
+"##,
}
register_diagnostics! {
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
#![feature(conservative_impl_trait)]
+#![feature(copy_closures, clone_closures)]
#![feature(from_ref)]
#![feature(match_default_bindings)]
#![feature(never_type)]
use rustc::lint;
use rustc::util::nodemap::FxHashMap;
use rustc_trans;
-use rustc_trans::back::link;
use rustc_resolve as resolve;
use rustc_metadata::cstore::CStore;
false,
Some(codemap.clone()));
- let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
sessopts, cpath, diagnostic_handler, codemap,
);
- rustc_trans::init(&sess);
+ let trans = rustc_trans::LlvmTransCrate::new(&sess);
+ let cstore = Rc::new(CStore::new(trans.metadata_loader()));
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
- target_features::add_configuration(&mut cfg, &sess);
+ target_features::add_configuration(&mut cfg, &sess, &*trans);
sess.parse_sess.config = cfg;
let control = &driver::CompileController::basic();
let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
- let name = link::find_crate_name(Some(&sess), &krate.attrs, &input);
+ let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
let driver::ExpansionResult { defs, analysis, resolutions, mut hir_forest, .. } = {
let result = driver::phase_2_configure_and_expand(&sess,
&[],
&sess);
- abort_on_err(driver::phase_3_run_analysis_passes(control,
+ abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
+ control,
&sess,
&*cstore,
hir_map,
<h2>Keyboard Shortcuts</h2>
<dl>
- <dt>?</dt>
+ <dt><kbd>?</kbd></dt>
<dd>Show this help dialog</dd>
- <dt>S</dt>
+ <dt><kbd>S</kbd></dt>
<dd>Focus the search field</dd>
- <dt>↑</dt>
+ <dt><kbd>↑</kbd></dt>
<dd>Move up in search results</dd>
- <dt>↓</dt>
+ <dt><kbd>↓</kbd></dt>
<dd>Move down in search results</dd>
- <dt>↹</dt>
+ <dt><kbd>↹</kbd></dt>
<dd>Switch tab</dd>
- <dt>⏎</dt>
+ <dt><kbd>⏎</kbd></dt>
<dd>Go to active search result</dd>
- <dt style="width:31px;">+ / -</dt>
- <dd>Collapse/expand all sections</dd>
+ <dt><kbd>+</kbd></dt>
+ <dd>Expand all sections</dd>
+ <dt><kbd>-</kbd></dt>
+ <dd>Collapse all sections</dd>
</dl>
</div>
flex: 0 0 auto;
box-shadow: 0 0 6px rgba(0,0,0,.2);
width: 550px;
- height: 354px;
+ height: auto;
border: 1px solid;
}
#help dt {
float: left;
- border-radius: 4px;
- border: 1px solid;
- width: 23px;
- text-align: center;
clear: left;
display: block;
- margin-top: -1px;
}
#help dd { margin: 5px 35px; }
#help .infos { padding-left: 0; }
left: -42px;
margin-top: 2px;
}
+
+kbd {
+ display: inline-block;
+ padding: 3px 5px;
+ font: 15px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ line-height: 10px;
+ vertical-align: middle;
+ border: solid 1px;
+ border-radius: 3px;
+ box-shadow: inset 0 -1px 0;
+}
border-color: #bfbfbf;
}
-#help dt {
- border-color: #bfbfbf;
- background: #fff;
-}
-
.since {
color: grey;
}
border-bottom-color: #e0e0e0;
}
}
+
+kbd {
+ color: #444d56;
+ background-color: #fafbfc;
+ border-color: #d1d5da;
+ border-bottom-color: #c6cbd1;
+ box-shadow-color: #c6cbd1;
+}
extern crate rustc;
extern crate rustc_data_structures;
extern crate rustc_const_math;
-extern crate rustc_trans;
+extern crate rustc_trans_utils;
extern crate rustc_driver;
extern crate rustc_resolve;
extern crate rustc_lint;
use std::process;
use std::sync::mpsc::channel;
+use rustc_driver::rustc_trans;
+
use externalfiles::ExternalHtml;
use rustc::session::search_paths::SearchPaths;
use rustc::session::config::{ErrorOutputType, RustcOptGroup, nightly_options,
use rustc_metadata::cstore::CStore;
use rustc_resolve::MakeGlobMap;
use rustc_trans;
-use rustc_trans::back::link;
use syntax::ast;
use syntax::codemap::CodeMap;
use syntax::feature_gate::UnstableFeatures;
true, false,
Some(codemap.clone()));
- let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
sessopts, Some(input_path.to_owned()), handler, codemap.clone(),
);
- rustc_trans::init(&sess);
+ let trans = rustc_trans::LlvmTransCrate::new(&sess);
+ let cstore = Rc::new(CStore::new(trans.metadata_loader()));
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
sess.parse_sess.config =
config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
};
let crate_name = crate_name.unwrap_or_else(|| {
- link::find_crate_name(None, &hir_forest.krate().attrs, &input)
+ ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
});
let opts = scrape_test_config(hir_forest.krate());
let mut collector = Collector::new(crate_name,
// Compile the code
let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
- let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
sessopts, None, diagnostic_handler, codemap,
);
- rustc_trans::init(&sess);
+ let trans = rustc_trans::LlvmTransCrate::new(&sess);
+ let cstore = Rc::new(CStore::new(trans.metadata_loader()));
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir"));
}
let res = panic::catch_unwind(AssertUnwindSafe(|| {
- driver::compile_input(&sess, &cstore, &None, &input, &out, &None, None, &control)
+ driver::compile_input(
+ trans,
+ &sess,
+ &cstore,
+ &None,
+ &input,
+ &out,
+ &None,
+ None,
+ &control
+ )
}));
let compile_result = match res {
// except according to those terms.
#[inline]
-fn write_to_vec(vec: &mut Vec<u8>, position: usize, byte: u8) {
+pub fn write_to_vec(vec: &mut Vec<u8>, position: usize, byte: u8) {
if position == vec.len() {
vec.push(byte);
} else {
}
}
-#[inline]
-/// encodes an integer using unsigned leb128 encoding and stores
-/// the result using a callback function.
-///
-/// The callback `write` is called once for each position
-/// that is to be written to with the byte to be encoded
-/// at that position.
-pub fn write_unsigned_leb128_to<W>(mut value: u128, mut write: W) -> usize
- where W: FnMut(usize, u8)
-{
- let mut position = 0;
- loop {
- let mut byte = (value & 0x7F) as u8;
- value >>= 7;
- if value != 0 {
- byte |= 0x80;
- }
-
- write(position, byte);
- position += 1;
+#[cfg(target_pointer_width = "32")]
+const USIZE_LEB128_SIZE: usize = 5;
+#[cfg(target_pointer_width = "64")]
+const USIZE_LEB128_SIZE: usize = 10;
+
+macro_rules! leb128_size {
+ (u16) => (3);
+ (u32) => (5);
+ (u64) => (10);
+ (u128) => (19);
+ (usize) => (USIZE_LEB128_SIZE);
+}
- if value == 0 {
- break;
+macro_rules! impl_write_unsigned_leb128 {
+ ($fn_name:ident, $int_ty:ident) => (
+ #[inline]
+ pub fn $fn_name(out: &mut Vec<u8>, start_position: usize, mut value: $int_ty) -> usize {
+ let mut position = start_position;
+ for _ in 0 .. leb128_size!($int_ty) {
+ let mut byte = (value & 0x7F) as u8;
+ value >>= 7;
+ if value != 0 {
+ byte |= 0x80;
+ }
+
+ write_to_vec(out, position, byte);
+ position += 1;
+
+ if value == 0 {
+ break;
+ }
+ }
+
+ position - start_position
}
- }
-
- position
+ )
}
-pub fn write_unsigned_leb128(out: &mut Vec<u8>, start_position: usize, value: u128) -> usize {
- write_unsigned_leb128_to(value, |i, v| write_to_vec(out, start_position+i, v))
+impl_write_unsigned_leb128!(write_u16_leb128, u16);
+impl_write_unsigned_leb128!(write_u32_leb128, u32);
+impl_write_unsigned_leb128!(write_u64_leb128, u64);
+impl_write_unsigned_leb128!(write_u128_leb128, u128);
+impl_write_unsigned_leb128!(write_usize_leb128, usize);
+
+
+macro_rules! impl_read_unsigned_leb128 {
+ ($fn_name:ident, $int_ty:ident) => (
+ #[inline]
+ pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
+ let mut result: $int_ty = 0;
+ let mut shift = 0;
+ let mut position = 0;
+
+ for _ in 0 .. leb128_size!($int_ty) {
+ let byte = unsafe {
+ *slice.get_unchecked(position)
+ };
+ position += 1;
+ result |= ((byte & 0x7F) as $int_ty) << shift;
+ if (byte & 0x80) == 0 {
+ break;
+ }
+ shift += 7;
+ }
+
+ // Do a single bounds check at the end instead of for every byte.
+ assert!(position <= slice.len());
+
+ (result, position)
+ }
+ )
}
-#[inline]
-pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u128, usize) {
- let mut result = 0;
- let mut shift = 0;
- let mut position = start_position;
- loop {
- let byte = data[position];
- position += 1;
- result |= ((byte & 0x7F) as u128) << shift;
- if (byte & 0x80) == 0 {
- break;
- }
- shift += 7;
- }
+impl_read_unsigned_leb128!(read_u16_leb128, u16);
+impl_read_unsigned_leb128!(read_u32_leb128, u32);
+impl_read_unsigned_leb128!(read_u64_leb128, u64);
+impl_read_unsigned_leb128!(read_u128_leb128, u128);
+impl_read_unsigned_leb128!(read_usize_leb128, usize);
+
- (result, position - start_position)
-}
#[inline]
/// encodes an integer using signed leb128 encoding and stores
(result, position - start_position)
}
-#[test]
-fn test_unsigned_leb128() {
- let mut stream = Vec::with_capacity(10000);
-
- for x in 0..62 {
- let pos = stream.len();
- let bytes_written = write_unsigned_leb128(&mut stream, pos, 3 << x);
- assert_eq!(stream.len(), pos + bytes_written);
- }
-
- let mut position = 0;
- for x in 0..62 {
- let expected = 3 << x;
- let (actual, bytes_read) = read_unsigned_leb128(&stream, position);
- assert_eq!(expected, actual);
- position += bytes_read;
- }
- assert_eq!(stream.len(), position);
+macro_rules! impl_test_unsigned_leb128 {
+ ($test_name:ident, $write_fn_name:ident, $read_fn_name:ident, $int_ty:ident) => (
+ #[test]
+ fn $test_name() {
+ let mut stream = Vec::new();
+
+ for x in 0..62 {
+ let pos = stream.len();
+ let bytes_written = $write_fn_name(&mut stream, pos, (3u64 << x) as $int_ty);
+ assert_eq!(stream.len(), pos + bytes_written);
+ }
+
+ let mut position = 0;
+ for x in 0..62 {
+ let expected = (3u64 << x) as $int_ty;
+ let (actual, bytes_read) = $read_fn_name(&stream[position ..]);
+ assert_eq!(expected, actual);
+ position += bytes_read;
+ }
+ assert_eq!(stream.len(), position);
+ }
+ )
}
+impl_test_unsigned_leb128!(test_u16_leb128, write_u16_leb128, read_u16_leb128, u16);
+impl_test_unsigned_leb128!(test_u32_leb128, write_u32_leb128, read_u32_leb128, u32);
+impl_test_unsigned_leb128!(test_u64_leb128, write_u64_leb128, read_u64_leb128, u64);
+impl_test_unsigned_leb128!(test_u128_leb128, write_u128_leb128, read_u128_leb128, u128);
+impl_test_unsigned_leb128!(test_usize_leb128, write_usize_leb128, read_usize_leb128, usize);
+
#[test]
fn test_signed_leb128() {
let values: Vec<_> = (-500..500).map(|i| i * 0x12345789ABCDEF).collect();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128};
+use leb128::{self, read_signed_leb128, write_signed_leb128};
use std::borrow::Cow;
use std::io::{self, Write};
use serialize;
macro_rules! write_uleb128 {
- ($enc:expr, $value:expr) => {{
+ ($enc:expr, $value:expr, $fun:ident) => {{
let pos = $enc.cursor.position() as usize;
- let bytes_written = write_unsigned_leb128($enc.cursor.get_mut(), pos, $value as u128);
+ let bytes_written = leb128::$fun($enc.cursor.get_mut(), pos, $value);
$enc.cursor.set_position((pos + bytes_written) as u64);
Ok(())
}}
impl<'a> serialize::Encoder for Encoder<'a> {
type Error = io::Error;
+ #[inline]
fn emit_nil(&mut self) -> EncodeResult {
Ok(())
}
+ #[inline]
fn emit_usize(&mut self, v: usize) -> EncodeResult {
- write_uleb128!(self, v)
+ write_uleb128!(self, v, write_usize_leb128)
}
+ #[inline]
fn emit_u128(&mut self, v: u128) -> EncodeResult {
- write_uleb128!(self, v)
+ write_uleb128!(self, v, write_u128_leb128)
}
+ #[inline]
fn emit_u64(&mut self, v: u64) -> EncodeResult {
- write_uleb128!(self, v)
+ write_uleb128!(self, v, write_u64_leb128)
}
+ #[inline]
fn emit_u32(&mut self, v: u32) -> EncodeResult {
- write_uleb128!(self, v)
+ write_uleb128!(self, v, write_u32_leb128)
}
+ #[inline]
fn emit_u16(&mut self, v: u16) -> EncodeResult {
- write_uleb128!(self, v)
+ write_uleb128!(self, v, write_u16_leb128)
}
+ #[inline]
fn emit_u8(&mut self, v: u8) -> EncodeResult {
- let _ = self.cursor.write_all(&[v]);
+ let pos = self.cursor.position() as usize;
+ leb128::write_to_vec(self.cursor.get_mut(), pos, v);
+ self.cursor.set_position((pos + 1) as u64);
Ok(())
}
+ #[inline]
fn emit_isize(&mut self, v: isize) -> EncodeResult {
write_sleb128!(self, v)
}
+ #[inline]
fn emit_i128(&mut self, v: i128) -> EncodeResult {
write_sleb128!(self, v)
}
+ #[inline]
fn emit_i64(&mut self, v: i64) -> EncodeResult {
write_sleb128!(self, v)
}
+ #[inline]
fn emit_i32(&mut self, v: i32) -> EncodeResult {
write_sleb128!(self, v)
}
+ #[inline]
fn emit_i16(&mut self, v: i16) -> EncodeResult {
write_sleb128!(self, v)
}
+ #[inline]
fn emit_i8(&mut self, v: i8) -> EncodeResult {
let as_u8: u8 = unsafe { ::std::mem::transmute(v) };
- let _ = self.cursor.write_all(&[as_u8]);
- Ok(())
+ self.emit_u8(as_u8)
}
+ #[inline]
fn emit_bool(&mut self, v: bool) -> EncodeResult {
self.emit_u8(if v {
1
})
}
+ #[inline]
fn emit_f64(&mut self, v: f64) -> EncodeResult {
let as_u64: u64 = unsafe { ::std::mem::transmute(v) };
self.emit_u64(as_u64)
}
+ #[inline]
fn emit_f32(&mut self, v: f32) -> EncodeResult {
let as_u32: u32 = unsafe { ::std::mem::transmute(v) };
self.emit_u32(as_u32)
}
+ #[inline]
fn emit_char(&mut self, v: char) -> EncodeResult {
self.emit_u32(v as u32)
}
+ #[inline]
fn emit_str(&mut self, v: &str) -> EncodeResult {
self.emit_usize(v.len())?;
let _ = self.cursor.write_all(v.as_bytes());
}
impl<'a> Encoder<'a> {
+ #[inline]
pub fn position(&self) -> usize {
self.cursor.position() as usize
}
}
}
+ #[inline]
pub fn position(&self) -> usize {
self.position
}
+ #[inline]
pub fn set_position(&mut self, pos: usize) {
self.position = pos
}
+ #[inline]
pub fn advance(&mut self, bytes: usize) {
self.position += bytes;
}
}
macro_rules! read_uleb128 {
- ($dec:expr, $t:ty) => ({
- let (value, bytes_read) = read_unsigned_leb128($dec.data, $dec.position);
+ ($dec:expr, $t:ty, $fun:ident) => ({
+ let (value, bytes_read) = leb128::$fun(&$dec.data[$dec.position ..]);
$dec.position += bytes_read;
- Ok(value as $t)
+ Ok(value)
})
}
#[inline]
fn read_u128(&mut self) -> Result<u128, Self::Error> {
- read_uleb128!(self, u128)
+ read_uleb128!(self, u128, read_u128_leb128)
}
#[inline]
fn read_u64(&mut self) -> Result<u64, Self::Error> {
- read_uleb128!(self, u64)
+ read_uleb128!(self, u64, read_u64_leb128)
}
#[inline]
fn read_u32(&mut self) -> Result<u32, Self::Error> {
- read_uleb128!(self, u32)
+ read_uleb128!(self, u32, read_u32_leb128)
}
#[inline]
fn read_u16(&mut self) -> Result<u16, Self::Error> {
- read_uleb128!(self, u16)
+ read_uleb128!(self, u16, read_u16_leb128)
}
#[inline]
#[inline]
fn read_usize(&mut self) -> Result<usize, Self::Error> {
- read_uleb128!(self, usize)
+ read_uleb128!(self, usize, read_usize_leb128)
}
#[inline]
use mem::{align_of, size_of, needs_drop};
use mem;
use ops::{Deref, DerefMut};
-use ptr::{self, Unique, Shared};
+use ptr::{self, Unique, NonNull};
use self::BucketState::*;
elems_left,
marker: marker::PhantomData,
},
- table: Shared::from(self),
+ table: NonNull::from(self),
marker: marker::PhantomData,
}
}
/// Iterator over the entries in a table, clearing the table.
pub struct Drain<'a, K: 'a, V: 'a> {
- table: Shared<RawTable<K, V>>,
+ table: NonNull<RawTable<K, V>>,
iter: RawBuckets<'static, K, V>,
marker: marker::PhantomData<&'a RawTable<K, V>>,
}
//! * You want a map, with no extra functionality.
//!
//! ### Use a `BTreeMap` when:
+//! * You want a map sorted by its keys.
+//! * You want to be able to get a range of entries on-demand.
//! * You're interested in what the smallest or largest key-value pair is.
//! * You want to find the largest or smallest key that is smaller or larger
//! than something.
-//! * You want to be able to get all of the entries in order on-demand.
-//! * You want a map sorted by its keys.
//!
//! ### Use the `Set` variant of any of these `Map`s when:
//! * You just want to remember which keys you've seen.
#![feature(placement_in_syntax)]
#![feature(placement_new_protocol)]
#![feature(prelude_import)]
+#![feature(ptr_internals)]
#![feature(rand)]
#![feature(raw)]
#![feature(repr_align)]
#![feature(rustc_attrs)]
-#![feature(shared)]
#![feature(sip_hash_13)]
#![feature(slice_bytes)]
#![feature(slice_concat_ext)]
#![feature(try_from)]
#![feature(unboxed_closures)]
#![feature(unicode)]
-#![feature(unique)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
use hash;
use io;
use mem;
-use net::{lookup_host, ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr};
+use net::{ntoh, hton, IpAddr, Ipv4Addr, Ipv6Addr};
+#[allow(deprecated)]
+use net::lookup_host;
use option;
use sys::net::netc as c;
use sys_common::{FromInner, AsInner, IntoInner};
}
}
+#[allow(deprecated)]
fn resolve_socket_addr(s: &str, p: u16) -> io::Result<vec::IntoIter<SocketAddr>> {
let ips = lookup_host(s)?;
let v: Vec<_> = ips.map(|mut a| { a.set_port(p); a }).collect();
iterator and returning socket \
addresses",
issue = "27705")]
+#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")]
pub struct LookupHost(net_imp::LookupHost);
#[unstable(feature = "lookup_host", reason = "unsure about the returned \
iterator and returning socket \
addresses",
issue = "27705")]
+#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")]
+#[allow(deprecated)]
impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> { self.0.next() }
iterator and returning socket \
addresses",
issue = "27705")]
+#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")]
+#[allow(deprecated)]
impl fmt::Debug for LookupHost {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("LookupHost { .. }")
iterator and returning socket \
addresses",
issue = "27705")]
+#[rustc_deprecated(since = "1.25", reason = "Use the ToSocketAddrs trait instead")]
+#[allow(deprecated)]
pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
net_imp::lookup_host(host).map(LookupHost)
}
use fmt;
use ops::{Deref, DerefMut};
use panicking;
-use ptr::{Unique, Shared};
+use ptr::{Unique, NonNull};
use rc::Rc;
use sync::{Arc, Mutex, RwLock, atomic};
use thread::Result;
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
-#[unstable(feature = "unique", issue = "27730")]
+#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
-#[unstable(feature = "shared", issue = "27730")]
-impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Shared<T> {}
+#[stable(feature = "nonnull", since = "1.24.0")]
+impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> UnwindSafe for Mutex<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
///
/// let path = Path::new("/test/haha/foo.txt");
///
+ /// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt")));
/// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt")));
+ /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt")));
+ /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new("")));
+ /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new("")));
/// assert_eq!(path.strip_prefix("test").is_ok(), false);
/// assert_eq!(path.strip_prefix("/haha").is_ok(), false);
/// ```
/// let path = Path::new("/etc/passwd");
///
/// assert!(path.starts_with("/etc"));
+ /// assert!(path.starts_with("/etc/"));
+ /// assert!(path.starts_with("/etc/passwd"));
+ /// assert!(path.starts_with("/etc/passwd/"));
///
/// assert!(!path.starts_with("/e"));
/// ```
pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
unimpl!();
}
-
- pub fn res_init_if_glibc_before_2_26() -> io::Result<()> {
- unimpl!();
- }
}
if err == 0 {
return Ok(())
}
+
+ // We may need to trigger a glibc workaround. See on_resolver_failure() for details.
+ on_resolver_failure();
+
if err == EAI_SYSTEM {
return Err(io::Error::last_os_error())
}
// res_init unconditionally, we call it only when we detect we're linking
// against glibc version < 2.26. (That is, when we both know its needed and
// believe it's thread-safe).
-pub fn res_init_if_glibc_before_2_26() -> io::Result<()> {
+#[cfg(target_env = "gnu")]
+fn on_resolver_failure() {
// If the version fails to parse, we treat it the same as "not glibc".
if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) {
if let Some(version) = parse_glibc_version(version_str) {
if version < (2, 26) {
- let ret = unsafe { libc::res_init() };
- if ret != 0 {
- return Err(io::Error::last_os_error());
- }
+ unsafe { libc::res_init() };
}
}
}
- Ok(())
}
+#[cfg(not(target_env = "gnu"))]
+fn on_resolver_failure() {}
+
+#[cfg(target_env = "gnu")]
fn glibc_version_cstr() -> Option<&'static CStr> {
weak! {
fn gnu_get_libc_version() -> *const libc::c_char
// Returns Some((major, minor)) if the string is a valid "x.y" version,
// ignoring any extra dot-separated parts. Otherwise return None.
+#[cfg(target_env = "gnu")]
fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
let mut parsed_ints = version.split(".").map(str::parse::<usize>).fuse();
match (parsed_ints.next(), parsed_ints.next()) {
}
}
-#[cfg(test)]
+#[cfg(all(test, taget_env = "gnu"))]
mod test {
use super::*;
#[cfg(target_os = "macos")]
pub unsafe fn current() -> Option<usize> {
- Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize -
- libc::pthread_get_stacksize_np(libc::pthread_self())))
+ Some(libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize -
+ libc::pthread_get_stacksize_np(libc::pthread_self()))
}
#[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
hints.ai_socktype = c::SOCK_STREAM;
let mut res = ptr::null_mut();
unsafe {
- match cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) {
- Ok(_) => {
- Ok(LookupHost { original: res, cur: res })
- },
- #[cfg(unix)]
- Err(e) => {
- // If we're running glibc prior to version 2.26, the lookup
- // failure could be caused by caching a stale /etc/resolv.conf.
- // We need to call libc::res_init() to clear the cache. But we
- // shouldn't call it in on any other platform, because other
- // res_init implementations aren't thread-safe. See
- // https://github.com/rust-lang/rust/issues/41570 and
- // https://github.com/rust-lang/rust/issues/43592.
- use sys::net::res_init_if_glibc_before_2_26;
- let _ = res_init_if_glibc_before_2_26();
- Err(e)
- },
- // the cfg is needed here to avoid an "unreachable pattern" warning
- #[cfg(not(unix))]
- Err(e) => Err(e),
- }
+ cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)).map(|_| {
+ LookupHost { original: res, cur: res }
+ })
}
}
pub use self::PathParameters::*;
pub use symbol::{Ident, Symbol as Name};
pub use util::ThinVec;
+pub use util::parser::ExprPrecedence;
use syntax_pos::{Span, DUMMY_SP};
use codemap::{respan, Spanned};
_ => false
}
}
+
pub fn is_comparison(&self) -> bool {
use self::BinOpKind::*;
match *self {
false,
}
}
+
/// Returns `true` if the binary operator takes its arguments by value
pub fn is_by_value(&self) -> bool {
!self.is_comparison()
Some(P(Ty { node, id: self.id, span: self.span }))
}
+
+ pub fn precedence(&self) -> ExprPrecedence {
+ match self.node {
+ ExprKind::Box(_) => ExprPrecedence::Box,
+ ExprKind::InPlace(..) => ExprPrecedence::InPlace,
+ ExprKind::Array(_) => ExprPrecedence::Array,
+ ExprKind::Call(..) => ExprPrecedence::Call,
+ ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
+ ExprKind::Tup(_) => ExprPrecedence::Tup,
+ ExprKind::Binary(op, ..) => ExprPrecedence::Binary(op.node),
+ ExprKind::Unary(..) => ExprPrecedence::Unary,
+ ExprKind::Lit(_) => ExprPrecedence::Lit,
+ ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
+ ExprKind::If(..) => ExprPrecedence::If,
+ ExprKind::IfLet(..) => ExprPrecedence::IfLet,
+ ExprKind::While(..) => ExprPrecedence::While,
+ ExprKind::WhileLet(..) => ExprPrecedence::WhileLet,
+ ExprKind::ForLoop(..) => ExprPrecedence::ForLoop,
+ ExprKind::Loop(..) => ExprPrecedence::Loop,
+ ExprKind::Match(..) => ExprPrecedence::Match,
+ ExprKind::Closure(..) => ExprPrecedence::Closure,
+ ExprKind::Block(..) => ExprPrecedence::Block,
+ ExprKind::Catch(..) => ExprPrecedence::Catch,
+ ExprKind::Assign(..) => ExprPrecedence::Assign,
+ ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
+ ExprKind::Field(..) => ExprPrecedence::Field,
+ ExprKind::TupField(..) => ExprPrecedence::TupField,
+ ExprKind::Index(..) => ExprPrecedence::Index,
+ ExprKind::Range(..) => ExprPrecedence::Range,
+ ExprKind::Path(..) => ExprPrecedence::Path,
+ ExprKind::AddrOf(..) => ExprPrecedence::AddrOf,
+ ExprKind::Break(..) => ExprPrecedence::Break,
+ ExprKind::Continue(..) => ExprPrecedence::Continue,
+ ExprKind::Ret(..) => ExprPrecedence::Ret,
+ ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
+ ExprKind::Mac(..) => ExprPrecedence::Mac,
+ ExprKind::Struct(..) => ExprPrecedence::Struct,
+ ExprKind::Repeat(..) => ExprPrecedence::Repeat,
+ ExprKind::Paren(..) => ExprPrecedence::Paren,
+ ExprKind::Try(..) => ExprPrecedence::Try,
+ ExprKind::Yield(..) => ExprPrecedence::Yield,
+ }
+ }
}
impl fmt::Debug for Expr {
/// Valid repr contents: any of the primitive integral type names (see
/// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
/// the same discriminant size that the corresponding C enum would or C
-/// structure layout, and `packed` to remove padding.
+/// structure layout, `packed` to remove padding, and `transparent` to elegate representation
+/// concerns to the only non-ZST field.
pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> {
let mut acc = Vec::new();
if attr.path == "repr" {
"C" => Some(ReprC),
"packed" => Some(ReprPacked),
"simd" => Some(ReprSimd),
+ "transparent" => Some(ReprTransparent),
_ => match int_type_of_word(word) {
Some(ity) => Some(ReprInt(ity)),
None => {
ReprC,
ReprPacked,
ReprSimd,
+ ReprTransparent,
ReprAlign(u32),
}
// `extern` in paths
(active, extern_in_paths, "1.23.0", Some(44660)),
+
+ // Allows `#[repr(transparent)]` attribute on newtype structs
+ (active, repr_transparent, "1.25.0", Some(43036)),
);
declare_features! (
"the struct `#[repr(align(u16))]` attribute \
is experimental");
}
+ if item.check_name("transparent") {
+ gate_feature_post!(&self, repr_transparent, attr.span,
+ "the `#[repr(transparent)]` attribute \
+ is experimental");
+ }
}
}
}
}
pub fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) -> io::Result<()> {
- let needs_par = parser::expr_precedence(expr) < prec;
+ let needs_par = expr.precedence().order() < prec;
if needs_par {
self.popen()?;
}
// except according to those terms.
use parse::token::{Token, BinOpToken};
use symbol::keywords;
-use ast::{self, BinOpKind, ExprKind};
+use ast::{self, BinOpKind};
+
+use std::cmp::Ordering;
/// Associative operator with precedence.
///
pub const PREC_PAREN: i8 = 99;
pub const PREC_FORCE_PAREN: i8 = 100;
-pub fn expr_precedence(expr: &ast::Expr) -> i8 {
- match expr.node {
- ExprKind::Closure(..) => PREC_CLOSURE,
-
- ExprKind::Break(..) |
- ExprKind::Continue(..) |
- ExprKind::Ret(..) |
- ExprKind::Yield(..) => PREC_JUMP,
-
- // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to parse,
- // instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence ensures that
- // `pprust` will add parentheses in the right places to get the desired parse.
- ExprKind::Range(..) => PREC_RANGE,
-
- // Binop-like expr kinds, handled by `AssocOp`.
- ExprKind::Binary(op, _, _) =>
- AssocOp::from_ast_binop(op.node).precedence() as i8,
-
- ExprKind::InPlace(..) => AssocOp::Inplace.precedence() as i8,
- ExprKind::Cast(..) => AssocOp::As.precedence() as i8,
- ExprKind::Type(..) => AssocOp::Colon.precedence() as i8,
-
- ExprKind::Assign(..) |
- ExprKind::AssignOp(..) => AssocOp::Assign.precedence() as i8,
-
- // Unary, prefix
- ExprKind::Box(..) |
- ExprKind::AddrOf(..) |
- ExprKind::Unary(..) => PREC_PREFIX,
-
- // Unary, postfix
- ExprKind::Call(..) |
- ExprKind::MethodCall(..) |
- ExprKind::Field(..) |
- ExprKind::TupField(..) |
- ExprKind::Index(..) |
- ExprKind::Try(..) |
- ExprKind::InlineAsm(..) |
- ExprKind::Mac(..) => PREC_POSTFIX,
-
- // Never need parens
- ExprKind::Array(..) |
- ExprKind::Repeat(..) |
- ExprKind::Tup(..) |
- ExprKind::Lit(..) |
- ExprKind::Path(..) |
- ExprKind::Paren(..) |
- ExprKind::If(..) |
- ExprKind::IfLet(..) |
- ExprKind::While(..) |
- ExprKind::WhileLet(..) |
- ExprKind::ForLoop(..) |
- ExprKind::Loop(..) |
- ExprKind::Match(..) |
- ExprKind::Block(..) |
- ExprKind::Catch(..) |
- ExprKind::Struct(..) => PREC_PAREN,
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ExprPrecedence {
+ Closure,
+ Break,
+ Continue,
+ Ret,
+ Yield,
+
+ Range,
+
+ Binary(BinOpKind),
+
+ InPlace,
+ Cast,
+ Type,
+
+ Assign,
+ AssignOp,
+
+ Box,
+ AddrOf,
+ Unary,
+
+ Call,
+ MethodCall,
+ Field,
+ TupField,
+ Index,
+ Try,
+ InlineAsm,
+ Mac,
+
+ Array,
+ Repeat,
+ Tup,
+ Lit,
+ Path,
+ Paren,
+ If,
+ IfLet,
+ While,
+ WhileLet,
+ ForLoop,
+ Loop,
+ Match,
+ Block,
+ Catch,
+ Struct,
+}
+
+impl PartialOrd for ExprPrecedence {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.order().cmp(&other.order()))
+ }
+}
+
+impl Ord for ExprPrecedence {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.order().cmp(&other.order())
}
}
+impl ExprPrecedence {
+ pub fn order(self) -> i8 {
+ match self {
+ ExprPrecedence::Closure => PREC_CLOSURE,
+
+ ExprPrecedence::Break |
+ ExprPrecedence::Continue |
+ ExprPrecedence::Ret |
+ ExprPrecedence::Yield => PREC_JUMP,
+
+ // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
+ // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
+ // ensures that `pprust` will add parentheses in the right places to get the desired
+ // parse.
+ ExprPrecedence::Range => PREC_RANGE,
+
+ // Binop-like expr kinds, handled by `AssocOp`.
+ ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
+ ExprPrecedence::InPlace => AssocOp::Inplace.precedence() as i8,
+ ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
+ ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
+
+ ExprPrecedence::Assign |
+ ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
+
+ // Unary, prefix
+ ExprPrecedence::Box |
+ ExprPrecedence::AddrOf |
+ ExprPrecedence::Unary => PREC_PREFIX,
+
+ // Unary, postfix
+ ExprPrecedence::Call |
+ ExprPrecedence::MethodCall |
+ ExprPrecedence::Field |
+ ExprPrecedence::TupField |
+ ExprPrecedence::Index |
+ ExprPrecedence::Try |
+ ExprPrecedence::InlineAsm |
+ ExprPrecedence::Mac => PREC_POSTFIX,
+
+ // Never need parens
+ ExprPrecedence::Array |
+ ExprPrecedence::Repeat |
+ ExprPrecedence::Tup |
+ ExprPrecedence::Lit |
+ ExprPrecedence::Path |
+ ExprPrecedence::Paren |
+ ExprPrecedence::If |
+ ExprPrecedence::IfLet |
+ ExprPrecedence::While |
+ ExprPrecedence::WhileLet |
+ ExprPrecedence::ForLoop |
+ ExprPrecedence::Loop |
+ ExprPrecedence::Match |
+ ExprPrecedence::Block |
+ ExprPrecedence::Catch |
+ ExprPrecedence::Struct => PREC_PAREN,
+ }
+ }
+}
+
+
/// Expressions that syntactically contain an "exterior" struct literal i.e. not surrounded by any
/// parens or other delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
for a in type_attrs {
for r in &attr::find_repr_attrs(diagnostic, a) {
repr_type_name = match *r {
- attr::ReprPacked | attr::ReprSimd | attr::ReprAlign(_) => continue,
+ attr::ReprPacked | attr::ReprSimd | attr::ReprAlign(_) | attr::ReprTransparent =>
+ continue,
+
attr::ReprC => "i32",
attr::ReprInt(attr::SignedInt(ast::IntTy::Isize)) => "isize",
--- /dev/null
+// Copyright 2018 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.
+
+// -C no-prepopulate-passes
+#![crate_type="staticlib"]
+
+#[repr(C)]
+pub struct Foo(u64);
+
+// CHECK: define {{.*}} @foo(
+#[no_mangle]
+pub extern fn foo(_: Foo) -> Foo { loop {} }
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+// ignore-arm
+// ignore-mips
+// ignore-mips64
+// ignore-powerpc
+// ignore-powerpc64
+// See repr-transparent.rs
+
+#![crate_type="lib"]
+#![feature(repr_transparent)]
+
+
+#[repr(C)]
+pub struct Big([u32; 16]);
+
+#[repr(transparent)]
+pub struct BigW(Big);
+
+// CHECK: define void @test_Big(%Big* [[BIG_RET_ATTRS:.*]], %Big* [[BIG_ARG_ATTRS:.*]])
+#[no_mangle]
+pub extern fn test_Big(_: Big) -> Big { loop {} }
+
+// CHECK: define void @test_BigW(%BigW* [[BIG_RET_ATTRS]], %BigW* [[BIG_ARG_ATTRS]])
+#[no_mangle]
+pub extern fn test_BigW(_: BigW) -> BigW { loop {} }
+
+
+#[repr(C)]
+pub union BigU {
+ foo: [u32; 16],
+}
+
+#[repr(transparent)]
+pub struct BigUw(BigU);
+
+// CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], %BigU* [[BIGU_ARG_ATTRS:.*]])
+#[no_mangle]
+pub extern fn test_BigU(_: BigU) -> BigU { loop {} }
+
+// CHECK: define void @test_BigUw(%BigUw* [[BIGU_RET_ATTRS]], %BigUw* [[BIGU_ARG_ATTRS]])
+#[no_mangle]
+pub extern fn test_BigUw(_: BigUw) -> BigUw { loop {} }
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+// ignore-aarch64
+// ignore-asmjs
+// ignore-s390x
+// ignore-wasm
+// ignore-x86
+// ignore-x86_64
+// See repr-transparent.rs
+
+#![crate_type="lib"]
+#![feature(repr_transparent)]
+
+
+#[repr(C)]
+pub struct Big([u32; 16]);
+
+#[repr(transparent)]
+pub struct BigW(Big);
+
+// CHECK: define void @test_Big(%Big* [[BIG_RET_ATTRS:.*]], [16 x i32]
+#[no_mangle]
+pub extern fn test_Big(_: Big) -> Big { loop {} }
+
+// CHECK: define void @test_BigW(%BigW* [[BIG_RET_ATTRS]], [16 x i32]
+#[no_mangle]
+pub extern fn test_BigW(_: BigW) -> BigW { loop {} }
+
+
+#[repr(C)]
+pub union BigU {
+ foo: [u32; 16],
+}
+
+#[repr(transparent)]
+pub struct BigUw(BigU);
+
+// CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], [16 x i32]
+#[no_mangle]
+pub extern fn test_BigU(_: BigU) -> BigU { loop {} }
+
+// CHECK: define void @test_BigUw(%BigUw* [[BIGU_RET_ATTRS]], [16 x i32]
+#[no_mangle]
+pub extern fn test_BigUw(_: BigUw) -> BigUw { loop {} }
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type="lib"]
+#![feature(repr_transparent, repr_simd)]
+
+use std::marker::PhantomData;
+
+pub struct Zst1;
+pub struct Zst2(());
+
+#[repr(transparent)]
+pub struct F32(f32);
+
+// CHECK: define float @test_F32(float %arg0)
+#[no_mangle]
+pub extern fn test_F32(_: F32) -> F32 { loop {} }
+
+#[repr(transparent)]
+pub struct Ptr(*mut u8);
+
+// CHECK: define i8* @test_Ptr(i8* %arg0)
+#[no_mangle]
+pub extern fn test_Ptr(_: Ptr) -> Ptr { loop {} }
+
+#[repr(transparent)]
+pub struct WithZst(u64, Zst1);
+
+// CHECK: define i64 @test_WithZst(i64 %arg0)
+#[no_mangle]
+pub extern fn test_WithZst(_: WithZst) -> WithZst { loop {} }
+
+#[repr(transparent)]
+pub struct WithZeroSizedArray(*const f32, [i8; 0]);
+
+// Apparently we use i32* when newtype-unwrapping f32 pointers. Whatever.
+// CHECK: define i32* @test_WithZeroSizedArray(i32* %arg0)
+#[no_mangle]
+pub extern fn test_WithZeroSizedArray(_: WithZeroSizedArray) -> WithZeroSizedArray { loop {} }
+
+#[repr(transparent)]
+pub struct Generic<T>(T);
+
+// CHECK: define double @test_Generic(double %arg0)
+#[no_mangle]
+pub extern fn test_Generic(_: Generic<f64>) -> Generic<f64> { loop {} }
+
+#[repr(transparent)]
+pub struct GenericPlusZst<T>(T, Zst2);
+
+#[repr(u8)]
+pub enum Bool { True, False, FileNotFound }
+
+// CHECK: define{{( zeroext)?}} i8 @test_Gpz(i8{{( zeroext)?}} %arg0)
+#[no_mangle]
+pub extern fn test_Gpz(_: GenericPlusZst<Bool>) -> GenericPlusZst<Bool> { loop {} }
+
+#[repr(transparent)]
+pub struct LifetimePhantom<'a, T: 'a>(*const T, PhantomData<&'a T>);
+
+// CHECK: define i16* @test_LifetimePhantom(i16* %arg0)
+#[no_mangle]
+pub extern fn test_LifetimePhantom(_: LifetimePhantom<i16>) -> LifetimePhantom<i16> { loop {} }
+
+// This works despite current alignment resrictions because PhantomData is always align(1)
+#[repr(transparent)]
+pub struct UnitPhantom<T, U> { val: T, unit: PhantomData<U> }
+
+pub struct Px;
+
+// CHECK: define float @test_UnitPhantom(float %arg0)
+#[no_mangle]
+pub extern fn test_UnitPhantom(_: UnitPhantom<f32, Px>) -> UnitPhantom<f32, Px> { loop {} }
+
+#[repr(transparent)]
+pub struct TwoZsts(Zst1, i8, Zst2);
+
+// CHECK: define{{( signext)?}} i8 @test_TwoZsts(i8{{( signext)?}} %arg0)
+#[no_mangle]
+pub extern fn test_TwoZsts(_: TwoZsts) -> TwoZsts { loop {} }
+
+#[repr(transparent)]
+pub struct Nested1(Zst2, Generic<f64>);
+
+// CHECK: define double @test_Nested1(double %arg0)
+#[no_mangle]
+pub extern fn test_Nested1(_: Nested1) -> Nested1 { loop {} }
+
+#[repr(transparent)]
+pub struct Nested2(Nested1, Zst1);
+
+// CHECK: define double @test_Nested2(double %arg0)
+#[no_mangle]
+pub extern fn test_Nested2(_: Nested2) -> Nested2 { loop {} }
+
+#[repr(simd)]
+struct f32x4(f32, f32, f32, f32);
+
+#[repr(transparent)]
+pub struct Vector(f32x4);
+
+// CHECK: define <4 x float> @test_Vector(<4 x float> %arg0)
+#[no_mangle]
+pub extern fn test_Vector(_: Vector) -> Vector { loop {} }
+
+trait Mirror { type It: ?Sized; }
+impl<T: ?Sized> Mirror for T { type It = Self; }
+
+#[repr(transparent)]
+pub struct StructWithProjection(<f32 as Mirror>::It);
+
+// CHECK: define float @test_Projection(float %arg0)
+#[no_mangle]
+pub extern fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} }
+
+
+// The rest of this file tests newtypes around small aggregates on an ABI where small aggregates are
+// packed into one register. This is ABI-dependent, so instead we focus on one ABI and supply a
+// dummy definition for other ABIs to keep FileCheck happy.
+//
+// Bigger aggregates are tested in separate files called repr-transparent-aggregate-*.rs because
+// there, the expected LLVM IR function signatures vary so much that it's not reasonably possible to
+// cover all of them with a single CHECK line. Instead we group ABIs by the general "shape" of the
+// signature and have a separate test file for each bin.
+//
+// PS: You may be wondering why we don't just compare the return types and argument types for
+// equality with FileCheck regex captures. Well, rustc doesn't perform newtype unwrapping on
+// newtypes containing aggregates. This is OK on all ABIs we support, but because LLVM has not
+// gotten rid of pointee types yet, the IR function signature will be syntactically different (%Foo*
+// vs %FooWrapper*).
+
+#[repr(C)]
+pub struct Rgb8 { r: u8, g: u8, b: u8 }
+
+#[repr(transparent)]
+pub struct Rgb8Wrap(Rgb8);
+
+// NB: closing parenthesis is missing because sometimes the argument has a name and sometimes not
+// CHECK: define i32 @test_Rgb8Wrap(i32
+#[no_mangle]
+#[cfg(all(target_arch="x86_64", target_os="linux"))]
+pub extern fn test_Rgb8Wrap(_: Rgb8Wrap) -> Rgb8Wrap { loop {} }
+
+#[cfg(not(all(target_arch="x86_64", target_os="linux")))]
+#[no_mangle]
+pub extern fn test_Rgb8Wrap(_: u32) -> u32 { loop {} }
+
+// Same as with the small struct above: ABI-dependent, we only test the interesting case
+// (ABIs that pack the aggregate into a scalar) and stub it out on other ABIs
+
+#[repr(C)]
+pub union FloatBits {
+ float: f32,
+ bits: u32,
+}
+
+#[repr(transparent)]
+pub struct SmallUnion(FloatBits);
+
+// NB: closing parenthesis is missing because sometimes the argument has a name and sometimes not
+// CHECK: define i32 @test_SmallUnion(i32
+#[no_mangle]
+#[cfg(all(target_arch="x86_64", target_os="linux"))]
+pub extern fn test_SmallUnion(_: SmallUnion) -> SmallUnion { loop {} }
+
+#[cfg(not(all(target_arch="x86_64", target_os="linux")))]
+#[no_mangle]
+pub extern fn test_SmallUnion(_: u32) -> u32 { loop {} }
// except according to those terms.
trait Foo {
- fn foo(); //~ trait declared without `&self`
+ fn foo();
+ //~^ NOTE trait method declared without `&self`
}
struct Bar;
impl Foo for Bar {
- fn foo(&self) {} //~ ERROR E0185
- //~^ `&self` used in impl
+ fn foo(&self) {}
+ //~^ ERROR E0185
+ //~| NOTE `&self` used in impl
}
fn main() {
}
fn main() {
- X::Entry(); //~ ERROR expected function, found `X::Entry` [E0618]
+ X::Entry();
+ //~^ ERROR expected function, found enum variant `X::Entry` [E0618]
let x = 0i32;
- x(); //~ ERROR expected function, found `i32` [E0618]
+ x();
+ //~^ ERROR expected function, found `i32` [E0618]
}
--- /dev/null
+// Copyright 2018 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.
+
+mod moon {
+ pub fn foo() {}
+}
+
+mod earth {
+ pub fn foo() {}
+}
+
+mod collider {
+ pub use moon::*;
+ pub use earth::*;
+}
+
+fn main() {
+ collider::foo(); //~ ERROR E0659
+}
+++ /dev/null
-// 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.
-
-#![allow(warnings)]
-
-fn closure_expecting_bound<F>(_: F)
- where F: FnOnce(&u32)
-{
-}
-
-fn closure_expecting_free<'a, F>(_: F)
- where F: FnOnce(&'a u32)
-{
-}
-
-fn expect_bound_supply_nothing() {
- // Because `x` is inferred to have a bound region, we cannot allow
- // it to escape into `f`:
- let mut f: Option<&u32> = None;
- closure_expecting_bound(|x| {
- f = Some(x); //~ ERROR E0495
- });
-}
-
-fn expect_bound_supply_bound() {
- // Because `x` is inferred to have a bound region, we cannot allow
- // it to escape into `f`, even with an explicit type annotation on
- // closure:
- let mut f: Option<&u32> = None;
- closure_expecting_bound(|x: &u32| {
- f = Some(x); //~ ERROR E0495
- });
-}
-
-fn expect_bound_supply_named<'x>() {
- let mut f: Option<&u32> = None;
-
- // Here we give a type annotation that `x` should be free. We get
- // an error because of that.
- closure_expecting_bound(|x: &'x u32| {
- //~^ ERROR mismatched types
- //~| ERROR mismatched types
-
- // And we still cannot let `x` escape into `f`.
- f = Some(x);
- //~^ ERROR cannot infer
- });
-}
-
-fn expect_free_supply_nothing() {
- let mut f: Option<&u32> = None;
- closure_expecting_free(|x| f = Some(x)); // OK
-}
-
-fn expect_free_supply_bound() {
- let mut f: Option<&u32> = None;
-
- // Here, even though the annotation `&u32` could be seen as being
- // bound in the closure, we permit it to be defined as a free
- // region (which is inferred to something in the fn body).
- closure_expecting_free(|x: &u32| f = Some(x)); // OK
-}
-
-fn expect_free_supply_named<'x>() {
- let mut f: Option<&u32> = None;
-
- // Here, even though the annotation `&u32` could be seen as being
- // bound in the closure, we permit it to be defined as a free
- // region (which is inferred to something in the fn body).
- closure_expecting_free(|x: &'x u32| f = Some(x)); // OK
-}
-
-fn main() { }
+++ /dev/null
-// Copyright 2013 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.
-
-
-pub struct CrateId {
- local_path: String,
- junk: String
-}
-
-impl CrateId {
- fn new(s: &str) -> CrateId {
- CrateId {
- local_path: s.to_string(),
- junk: "wutevs".to_string()
- }
- }
-}
-
-pub fn remove_package_from_database() {
- let mut lines_to_use: Vec<&CrateId> = Vec::new(); //~ ERROR E0495
- let push_id = |installed_id: &CrateId| {
- lines_to_use.push(installed_id);
- };
- list_database(push_id);
-
- for l in &lines_to_use {
- println!("{}", l.local_path);
- }
-
-}
-
-pub fn list_database<F>(mut f: F) where F: FnMut(&CrateId) {
- let stuff = ["foo", "bar"];
-
- for l in &stuff {
- f(&CrateId::new(*l));
- }
-}
-
-pub fn main() {
- remove_package_from_database();
-}
// except according to those terms.
#![deny(improper_ctypes)]
-#![feature(libc, i128_type)]
+#![feature(libc, i128_type, repr_transparent)]
extern crate libc;
+use std::marker::PhantomData;
+
trait Mirror { type It: ?Sized; }
impl<T: ?Sized> Mirror for T { type It = Self; }
#[repr(C)]
pub type RustBadRet = extern fn() -> Box<u32>;
pub type CVoidRet = ();
pub struct Foo;
+#[repr(transparent)]
+pub struct TransparentI128(i128);
+#[repr(transparent)]
+pub struct TransparentStr(&'static str);
+#[repr(transparent)]
+pub struct TransparentBadFn(RustBadRet);
+#[repr(transparent)]
+pub struct TransparentInt(u32);
+#[repr(transparent)]
+pub struct TransparentRef<'a>(&'a TransparentInt);
+#[repr(transparent)]
+pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
+#[repr(transparent)]
+pub struct TransparentUnit<U>(f32, PhantomData<U>);
+#[repr(transparent)]
+pub struct TransparentCustomZst(i32, ZeroSize);
#[repr(C)]
pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust
pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust
pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without
+ pub fn transparent_i128(p: TransparentI128); //~ ERROR: found Rust type `i128`
+ pub fn transparent_str(p: TransparentStr); //~ ERROR: found Rust type `str`
+ pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: found struct without
pub fn good3(fptr: Option<extern fn()>);
pub fn good4(aptr: &[u8; 4 as usize]);
pub fn good10() -> CVoidRet;
pub fn good11(size: isize);
pub fn good12(size: usize);
+ pub fn good13(n: TransparentInt);
+ pub fn good14(p: TransparentRef);
+ pub fn good15(p: TransparentLifetime);
+ pub fn good16(p: TransparentUnit<ZeroSize>);
+ pub fn good17(p: TransparentCustomZst);
}
#[cfg(not(target_arch = "wasm32"))]
#[derive(Eq, PartialEq)]
struct X { y: bool }
impl X {
- fn foo(&self) -> bool { self.y }
+ fn foo(&self, conjunct: bool) -> bool { self.y && conjunct }
}
fn foo() -> isize {
return (1); //~ ERROR unnecessary parentheses around `return` value
}
-fn bar() -> X {
- return (X { y: true }); //~ ERROR unnecessary parentheses around `return` value
+fn bar(y: bool) -> X {
+ return (X { y }); //~ ERROR unnecessary parentheses around `return` value
}
fn main() {
foo();
- bar();
+ bar((true)); //~ ERROR unnecessary parentheses around function argument
if (true) {} //~ ERROR unnecessary parentheses around `if` condition
while (true) {} //~ ERROR unnecessary parentheses around `while` condition
if (X { y: true } == v) {}
if (X { y: false }.y) {}
- while (X { y: false }.foo()) {}
+ while (X { y: false }.foo(true)) {}
while (true | X { y: false }.y) {}
match (X { y: false }) {
_ => {}
}
+ X { y: false }.foo((true)); //~ ERROR unnecessary parentheses around method argument
+
let mut _a = (0); //~ ERROR unnecessary parentheses around assigned value
_a = (0); //~ ERROR unnecessary parentheses around assigned value
_a += (1); //~ ERROR unnecessary parentheses around assigned value
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue #47053
+
+#![feature(nll)]
+#![feature(thread_local)]
+
+#[thread_local]
+static FOO: isize = 5;
+
+fn main() {
+ FOO = 6; //~ ERROR cannot assign to immutable item `FOO` [E0594]
+}
+++ /dev/null
-// Copyright 2012 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.
-
-fn with_int<F>(f: F) where F: FnOnce(&isize) {
- let x = 3;
- f(&x);
-}
-
-fn main() {
- let mut x = None;
- with_int(|y| x = Some(y));
- //~^ ERROR cannot infer
-}
+++ /dev/null
-// Copyright 2012 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.
-
-fn with_int<F>(f: F) where F: FnOnce(&isize) {
- let x = 3;
- f(&x);
-}
-
-fn main() {
- let mut x: Option<&isize> = None;
- with_int(|y| x = Some(y)); //~ ERROR cannot infer
-}
+++ /dev/null
-// Copyright 2012 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.
-
-fn with_int(f: &mut FnMut(&isize)) {
-}
-
-fn main() {
- let mut x: Option<&isize> = None;
- with_int(&mut |y| x = Some(y)); //~ ERROR cannot infer
-}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(repr_transparent)]
+
+// See also repr-transparent.rs
+
+#[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum
+enum Void {} //~| ERROR should be applied to struct
+
+#[repr(transparent)] //~ ERROR should be applied to struct
+enum FieldlessEnum {
+ Foo,
+ Bar,
+}
+
+#[repr(transparent)] //~ ERROR should be applied to struct
+enum Enum {
+ Foo(String),
+ Bar(u32),
+}
+
+#[repr(transparent)] //~ ERROR should be applied to struct
+union Foo {
+ u: u32,
+ s: i32
+}
+
+#[repr(transparent)] //~ ERROR should be applied to struct
+fn cant_repr_this() {}
+
+#[repr(transparent)] //~ ERROR should be applied to struct
+static CANT_REPR_THIS: u32 = 0;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(repr_transparent, repr_align, attr_literals)]
+
+// See also repr-transparent.rs
+
+#[repr(transparent, C)] //~ ERROR cannot have other repr
+struct TransparentPlusC {
+ ptr: *const u8
+}
+
+#[repr(transparent, packed)] //~ ERROR cannot have other repr
+struct TransparentPlusPacked(*const u8);
+
+#[repr(transparent, align(2))] //~ ERROR cannot have other repr
+struct TransparentPlusAlign(u8);
+
+#[repr(transparent)] //~ ERROR cannot have other repr
+#[repr(C)]
+struct SeparateAttributes(*mut u8);
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This file tests repr(transparent)-related errors reported during typeck. Other errors
+// that are reported earlier and therefore preempt these are tested in:
+// - repr-transparent-other-reprs.rs
+// - repr-transparent-other-items.rs
+
+#![feature(repr_align, attr_literals)]
+#![feature(repr_transparent)]
+
+use std::marker::PhantomData;
+
+#[repr(transparent)]
+struct NoFields; //~ ERROR needs exactly one non-zero-sized field
+
+#[repr(transparent)]
+struct ContainsOnlyZst(()); //~ ERROR needs exactly one non-zero-sized field
+
+#[repr(transparent)]
+struct ContainsOnlyZstArray([bool; 0]); //~ ERROR needs exactly one non-zero-sized field
+
+#[repr(transparent)]
+struct ContainsMultipleZst(PhantomData<*const i32>, NoFields);
+//~^ ERROR needs exactly one non-zero-sized field
+
+#[repr(transparent)]
+struct MultipleNonZst(u8, u8); //~ ERROR needs exactly one non-zero-sized field
+
+trait Mirror { type It: ?Sized; }
+impl<T: ?Sized> Mirror for T { type It = Self; }
+
+#[repr(transparent)]
+pub struct StructWithProjection(f32, <f32 as Mirror>::It);
+//~^ ERROR needs exactly one non-zero-sized field
+
+#[repr(transparent)]
+struct NontrivialAlignZst(u32, [u16; 0]); //~ ERROR alignment larger than 1
+
+#[repr(align(32))]
+struct ZstAlign32<T>(PhantomData<T>);
+
+#[repr(transparent)]
+struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR alignment larger than 1
--- /dev/null
+// Copyright 2018 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+// Add a function to shift DefIndex of registrar function
+#[cfg(cfail2)]
+fn foo() {}
+
+#[proc_macro_derive(IncrementalMacro)]
+pub fn derive(input: TokenStream) -> TokenStream {
+ #[cfg(cfail2)]
+ {
+ foo();
+ }
+
+ "".parse().unwrap()
+}
--- /dev/null
+// Copyright 2018 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.
+
+// aux-build:incremental_proc_macro_aux.rs
+// ignore-stage1
+// revisions: cfail1 cfail2
+// must-compile-successfully
+
+// This test makes sure that we still find the proc-macro registrar function
+// when we compile proc-macros incrementally (see #47292).
+
+#![crate_type = "rlib"]
+
+#[macro_use]
+extern crate incremental_proc_macro_aux;
+
+#[derive(IncrementalMacro)]
+pub struct Foo {
+ x: u32
+}
--- /dev/null
+include ../tools.mk
+
+all:
+ /bin/echo || exit 0 # This test requires /bin/echo to exist
+ $(RUSTC) the_backend.rs --crate-name the_backend --crate-type dylib \
+ -o $(TMPDIR)/the_backend.dylib
+ $(RUSTC) some_crate.rs --crate-name some_crate --crate-type bin -o $(TMPDIR)/some_crate \
+ -Z codegen-backend=$(TMPDIR)/the_backend.dylib -Z unstable-options
+ grep -x "This has been \"compiled\" succesfully." $(TMPDIR)/some_crate
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ ::std::process::exit(1);
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_private)]
+
+extern crate syntax;
+extern crate rustc;
+extern crate rustc_trans_utils;
+
+use std::any::Any;
+use std::sync::mpsc;
+use syntax::symbol::Symbol;
+use rustc::session::{Session, CompileIncomplete};
+use rustc::session::config::OutputFilenames;
+use rustc::ty::TyCtxt;
+use rustc::ty::maps::Providers;
+use rustc::middle::cstore::MetadataLoader;
+use rustc::dep_graph::DepGraph;
+use rustc_trans_utils::trans_crate::{TransCrate, MetadataOnlyTransCrate};
+
+struct TheBackend(Box<TransCrate>);
+
+impl TransCrate for TheBackend {
+ fn metadata_loader(&self) -> Box<MetadataLoader> {
+ self.0.metadata_loader()
+ }
+
+ fn provide(&self, providers: &mut Providers) {
+ self.0.provide(providers);
+ }
+
+ fn provide_extern(&self, providers: &mut Providers) {
+ self.0.provide_extern(providers);
+ }
+
+ fn trans_crate<'a, 'tcx>(
+ &self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ _rx: mpsc::Receiver<Box<Any + Send>>
+ ) -> Box<Any> {
+ use rustc::hir::def_id::LOCAL_CRATE;
+
+ Box::new(tcx.crate_name(LOCAL_CRATE) as Symbol)
+ }
+
+ fn join_trans_and_link(
+ &self,
+ trans: Box<Any>,
+ sess: &Session,
+ _dep_graph: &DepGraph,
+ outputs: &OutputFilenames,
+ ) -> Result<(), CompileIncomplete> {
+ use std::io::Write;
+ use rustc::session::config::CrateType;
+ use rustc_trans_utils::link::out_filename;
+ let crate_name = trans.downcast::<Symbol>()
+ .expect("in join_trans_and_link: trans is not a Symbol");
+ for &crate_type in sess.opts.crate_types.iter() {
+ if crate_type != CrateType::CrateTypeExecutable {
+ sess.fatal(&format!("Crate type is {:?}", crate_type));
+ }
+ let output_name =
+ out_filename(sess, crate_type, &outputs, &*crate_name.as_str());
+ let mut out_file = ::std::fs::File::create(output_name).unwrap();
+ write!(out_file, "This has been \"compiled\" succesfully.").unwrap();
+ }
+ Ok(())
+ }
+}
+
+/// This is the entrypoint for a hot plugged rustc_trans
+#[no_mangle]
+pub fn __rustc_codegen_backend(sess: &Session) -> Box<TransCrate> {
+ Box::new(TheBackend(MetadataOnlyTransCrate::new(sess)))
+}
extern crate rustc_metadata;
extern crate rustc_errors;
extern crate rustc_trans;
+extern crate rustc_trans_utils;
extern crate syntax;
use rustc::session::{build_session, Session};
use rustc_metadata::cstore::CStore;
use rustc_errors::registry::Registry;
use syntax::codemap::FileName;
+use rustc_trans_utils::trans_crate::TransCrate;
use std::path::PathBuf;
use std::rc::Rc;
compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
}
-fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) {
+fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>, Box<TransCrate>) {
let mut opts = basic_options();
opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
opts.maybe_sysroot = Some(sysroot);
}
let descriptions = Registry::new(&rustc::DIAGNOSTICS);
- let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader)));
let sess = build_session(opts, None, descriptions);
- rustc_trans::init(&sess);
+ let trans = rustc_trans::LlvmTransCrate::new(&sess);
+ let cstore = Rc::new(CStore::new(trans.metadata_loader()));
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
- (sess, cstore)
+ (sess, cstore, trans)
}
fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
- let (sess, cstore) = basic_sess(sysroot);
+ let (sess, cstore, trans) = basic_sess(sysroot);
let control = CompileController::basic();
let input = Input::Str { name: FileName::Anon, input: code };
- let _ = compile_input(&sess, &cstore, &None, &input, &None, &Some(output), None, &control);
+ let _ = compile_input(
+ trans,
+ &sess,
+ &cstore,
+ &None,
+ &input,
+ &None,
+ &Some(output),
+ None,
+ &control
+ );
}
+++ /dev/null
--include ../tools.mk
-
-all:
- $(RUSTC) test.rs
- $(call RUN,test $(RUSTC))
+++ /dev/null
-// 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.
-
-#![feature(plugin, rustc_private, box_syntax)]
-
-extern crate rustc;
-extern crate rustc_driver;
-extern crate rustc_llvm;
-extern crate rustc_trans;
-#[macro_use] extern crate syntax;
-extern crate getopts;
-
-use rustc_driver::{CompilerCalls, Compilation};
-use rustc_driver::driver::CompileController;
-use rustc_trans::ModuleSource;
-use rustc::session::Session;
-use syntax::codemap::FileLoader;
-use std::env;
-use std::io;
-use std::path::{PathBuf, Path};
-
-struct JitLoader;
-
-impl FileLoader for JitLoader {
- fn file_exists(&self, _: &Path) -> bool { true }
- fn abs_path(&self, _: &Path) -> Option<PathBuf> { None }
- fn read_file(&self, _: &Path) -> io::Result<String> {
- Ok(r#"
-#[no_mangle]
-pub fn test_add(a: i32, b: i32) -> i32 { a + b }
-"#.to_string())
- }
-}
-
-#[derive(Copy, Clone)]
-struct JitCalls;
-
-impl<'a> CompilerCalls<'a> for JitCalls {
- fn build_controller(&mut self,
- _: &Session,
- _: &getopts::Matches)
- -> CompileController<'a> {
- let mut cc = CompileController::basic();
- cc.after_llvm.stop = Compilation::Stop;
- cc.after_llvm.run_callback_on_error = true;
- cc.after_llvm.callback = Box::new(|state| {
- state.session.abort_if_errors();
- let trans = state.trans.unwrap();
- assert_eq!(trans.modules.len(), 1);
- println!("name of compiled module = {}", trans.modules[0].name);
- });
- cc
- }
-}
-
-fn main() {
- use rustc_driver;
-
- let mut path = match std::env::args().nth(2) {
- Some(path) => PathBuf::from(&path),
- None => panic!("missing rustc path")
- };
-
- // Remove two segments from rustc path to get sysroot.
- path.pop();
- path.pop();
-
- let mut args: Vec<String> =
- format!("_ _ --sysroot {} --crate-type dylib", path.to_str().unwrap())
- .split(' ').map(|s| s.to_string()).collect();
- args.push("--out-dir".to_string());
- args.push(env::var("TMPDIR").unwrap());
- args.push("-Ccodegen-units=1".to_string());
-
- let (result, _) = rustc_driver::run_compiler(
- &args, &mut JitCalls, Some(box JitLoader), None);
- if let Err(n) = result {
- panic!("Error {:?}", n);
- }
-}
--- /dev/null
+-include ../tools.mk
+
+all:
+ $(RUSTC) foo.rs -g
+ cp foo.bat $(TMPDIR)/
+ OUT_DIR="$(TMPDIR)" RUSTC="$(RUSTC_ORIGINAL)" $(call RUN,foo)
--- /dev/null
+%MY_LINKER% %*
--- /dev/null
+// Copyright 2018 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.
+
+// Like the `long-linker-command-lines` test this test attempts to blow
+// a command line limit for running the linker. Unlike that test, however,
+// this test is testing `cmd.exe` specifically rather than the OS.
+//
+// Unfortunately `cmd.exe` has a 8192 limit which is relatively small
+// in the grand scheme of things and anyone sripting rustc's linker
+// is probably using a `*.bat` script and is likely to hit this limit.
+//
+// This test uses a `foo.bat` script as the linker which just simply
+// delegates back to this program. The compiler should use a lower
+// limit for arguments before passing everything via `@`, which
+// means that everything should still succeed here.
+
+use std::env;
+use std::fs::{self, File};
+use std::io::{BufWriter, Write, Read};
+use std::path::PathBuf;
+use std::process::Command;
+
+fn main() {
+ if !cfg!(windows) {
+ return
+ }
+
+ let tmpdir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
+ let ok = tmpdir.join("ok");
+ let not_ok = tmpdir.join("not_ok");
+ if env::var("YOU_ARE_A_LINKER").is_ok() {
+ match env::args().find(|a| a.contains("@")) {
+ Some(file) => { fs::copy(&file[1..], &ok).unwrap(); }
+ None => { File::create(¬_ok).unwrap(); }
+ }
+ return
+ }
+
+ let rustc = env::var_os("RUSTC").unwrap_or("rustc".into());
+ let me = env::current_exe().unwrap();
+ let bat = me.parent()
+ .unwrap()
+ .join("foo.bat");
+ let bat_linker = format!("linker={}", bat.display());
+ for i in (1..).map(|i| i * 10) {
+ println!("attempt: {}", i);
+
+ let file = tmpdir.join("bar.rs");
+ let mut f = BufWriter::new(File::create(&file).unwrap());
+ let mut lib_name = String::new();
+ for _ in 0..i {
+ lib_name.push_str("foo");
+ }
+ for j in 0..i {
+ writeln!(f, "#[link(name = \"{}{}\")]", lib_name, j).unwrap();
+ }
+ writeln!(f, "extern {{}}\nfn main() {{}}").unwrap();
+ f.into_inner().unwrap();
+
+ drop(fs::remove_file(&ok));
+ drop(fs::remove_file(¬_ok));
+ let status = Command::new(&rustc)
+ .arg(&file)
+ .arg("-C").arg(&bat_linker)
+ .arg("--out-dir").arg(&tmpdir)
+ .env("YOU_ARE_A_LINKER", "1")
+ .env("MY_LINKER", &me)
+ .status()
+ .unwrap();
+
+ if !status.success() {
+ panic!("rustc didn't succeed: {}", status);
+ }
+
+ if !ok.exists() {
+ assert!(not_ok.exists());
+ continue
+ }
+
+ let mut contents = String::new();
+ File::open(&ok).unwrap().read_to_string(&mut contents).unwrap();
+
+ for j in 0..i {
+ assert!(contents.contains(&format!("{}{}", lib_name, j)));
+ }
+
+ break
+ }
+}
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
+extern crate rustc_trans_utils;
extern crate syntax;
extern crate rustc_errors as errors;
use rustc::session::Session;
use rustc::session::config::{self, Input};
use rustc_driver::{driver, CompilerCalls, Compilation};
+use rustc_trans_utils::trans_crate::TransCrate;
use syntax::ast;
use std::path::PathBuf;
}
fn late_callback(&mut self,
+ _: &TransCrate,
_: &getopts::Matches,
_: &Session,
_: &CrateStore,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(allocator_api, unique)]
+#![feature(allocator_api, nonnull)]
use std::heap::{Heap, Alloc};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// revisions:lexical nll
+#![cfg_attr(nll, feature(nll))]
+
#![feature(generators)]
fn bar<'a>() {
// Don't fail if we encounter a NonZero<*T> where T is an unsized type
-#![feature(unique)]
-
-use std::ptr::Unique;
+use std::ptr::NonNull;
fn main() {
let mut a = [0u8; 5];
- let b: Option<Unique<[u8]>> = Some(Unique::from(&mut a));
+ let b: Option<NonNull<[u8]>> = Some(NonNull::from(&mut a));
match b {
Some(_) => println!("Got `Some`"),
None => panic!("Unexpected `None`"),
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const CURSOR_PARTITION_LABEL: &'static [u8] = b"partition";
+const CURSOR_EVENT_TYPE_LABEL: &'static [u8] = b"event_type";
+const BYTE_PATTERN: &'static [u8; 5] = b"hello";
+
+fn match_slice(x: &[u8]) -> u32 {
+ match x {
+ CURSOR_PARTITION_LABEL => 0,
+ CURSOR_EVENT_TYPE_LABEL => 1,
+ _ => 2,
+ }
+}
+
+fn match_array(x: &[u8; 5]) -> bool {
+ match x {
+ BYTE_PATTERN => true,
+ _ => false
+ }
+}
+
+fn main() {
+ assert_eq!(match_slice(b"abcde"), 2);
+ assert_eq!(match_slice(b"event_type"), 1);
+ assert_eq!(match_slice(b"partition"), 0);
+
+ assert_eq!(match_array(b"hello"), true);
+ assert_eq!(match_array(b"hella"), false);
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod my_mod {
+ #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
+ pub struct Name<'a> {
+ source: &'a str,
+ }
+
+ pub const JSON: Name = Name { source: "JSON" };
+}
+
+pub fn crash() -> bool {
+ match (my_mod::JSON, None) {
+ (_, Some(my_mod::JSON)) => true,
+ (my_mod::JSON, None) => true,
+ _ => false,
+ }
+}
+
+fn main() {}
--- /dev/null
+// 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.
+
+// Regression test for #47153: constants in a generic context (such as
+// a trait) used to ICE.
+
+#![feature(nll)]
+#![allow(warnings)]
+
+trait Foo {
+ const B: bool = true;
+}
+
+struct Bar<T> { x: T }
+
+impl<T> Bar<T> {
+ const B: bool = true;
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2018 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.
+
+#![feature(transpose_result)]
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+struct BadNumErr;
+
+fn try_num(x: i32) -> Result<i32, BadNumErr> {
+ if x <= 5 {
+ Ok(x + 1)
+ } else {
+ Err(BadNumErr)
+ }
+}
+
+type ResOpt = Result<Option<i32>, BadNumErr>;
+type OptRes = Option<Result<i32, BadNumErr>>;
+
+fn main() {
+ let mut x: ResOpt = Ok(Some(5));
+ let mut y: OptRes = Some(Ok(5));
+ assert_eq!(x, y.transpose());
+ assert_eq!(x.transpose(), y);
+
+ x = Ok(None);
+ y = None;
+ assert_eq!(x, y.transpose());
+ assert_eq!(x.transpose(), y);
+
+ x = Err(BadNumErr);
+ y = Some(Err(BadNumErr));
+ assert_eq!(x, y.transpose());
+ assert_eq!(x.transpose(), y);
+
+ let res: Result<Vec<i32>, BadNumErr> =
+ (0..10)
+ .map(|x| {
+ let y = try_num(x)?;
+ Ok(if y % 2 == 0 {
+ Some(y - 1)
+ } else {
+ None
+ })
+ })
+ .filter_map(Result::transpose)
+ .collect();
+
+ assert_eq!(res, Err(BadNumErr))
+}
{ 'path': 'std::char', 'name': 'from_u32' },
{ 'path': 'std::str', 'name': 'from_utf8' },
{ 'path': 'std::string::String', 'name': 'from_utf8' },
- { 'path': 'std::boxed::Box', 'name': 'from_unique' },
{ 'path': 'std::i32', 'name': 'from_unsigned' },
{ 'path': 'std::i128', 'name': 'from_unsigned' },
],
--> $DIR/issue-20862.rs:17:13
|
17 | let x = foo(5)(2);
- | ^^^^^^^^^
+ | ^^^^^^^^^ not a function
error: aborting due to 2 previous errors
--- /dev/null
+// Copyright 2018 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.
+
+fn give_any<F: for<'r> FnOnce(&'r ())>(f: F) {
+ f(&());
+}
+
+fn main() {
+ let x = None;
+ give_any(|y| x = Some(y));
+ //~^ ERROR borrowed data cannot be stored outside of its closure
+}
--- /dev/null
+error: borrowed data cannot be stored outside of its closure
+ --> $DIR/issue-45983.rs:17:27
+ |
+16 | let x = None;
+ | - borrowed data cannot be stored into here...
+17 | give_any(|y| x = Some(y));
+ | --- ^ cannot be stored outside of its closure
+ | |
+ | ...because it cannot outlive this closure
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2013 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.
+
+
+pub struct CrateId {
+ local_path: String,
+ junk: String
+}
+
+impl CrateId {
+ fn new(s: &str) -> CrateId {
+ CrateId {
+ local_path: s.to_string(),
+ junk: "wutevs".to_string()
+ }
+ }
+}
+
+pub fn remove_package_from_database() {
+ let mut lines_to_use: Vec<&CrateId> = Vec::new();
+ //~^ NOTE cannot infer an appropriate lifetime
+ let push_id = |installed_id: &CrateId| {
+ //~^ NOTE borrowed data cannot outlive this closure
+ //~| NOTE ...so that variable is valid at time of its declaration
+ lines_to_use.push(installed_id);
+ //~^ ERROR borrowed data cannot be stored outside of its closure
+ //~| NOTE cannot be stored outside of its closure
+ };
+ list_database(push_id);
+
+ for l in &lines_to_use {
+ println!("{}", l.local_path);
+ }
+
+}
+
+pub fn list_database<F>(mut f: F) where F: FnMut(&CrateId) {
+ let stuff = ["foo", "bar"];
+
+ for l in &stuff {
+ f(&CrateId::new(*l));
+ }
+}
+
+pub fn main() {
+ remove_package_from_database();
+}
--- /dev/null
+error: borrowed data cannot be stored outside of its closure
+ --> $DIR/issue-7573.rs:32:27
+ |
+27 | let mut lines_to_use: Vec<&CrateId> = Vec::new();
+ | - cannot infer an appropriate lifetime...
+28 | //~^ NOTE cannot infer an appropriate lifetime
+29 | let push_id = |installed_id: &CrateId| {
+ | ------- ------------------------ borrowed data cannot outlive this closure
+ | |
+ | ...so that variable is valid at time of its declaration
+...
+32 | lines_to_use.push(installed_id);
+ | ^^^^^^^^^^^^ cannot be stored outside of its closure
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2012 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.
+
+fn with_int<F>(f: F) where F: FnOnce(&isize) {
+ let x = 3;
+ f(&x);
+}
+
+fn main() {
+ let mut x = None;
+ with_int(|y| x = Some(y));
+ //~^ ERROR borrowed data cannot be stored outside of its closure
+}
--- /dev/null
+error: borrowed data cannot be stored outside of its closure
+ --> $DIR/regions-escape-bound-fn-2.rs:18:27
+ |
+17 | let mut x = None;
+ | ----- borrowed data cannot be stored into here...
+18 | with_int(|y| x = Some(y));
+ | --- ^ cannot be stored outside of its closure
+ | |
+ | ...because it cannot outlive this closure
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2012 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.
+
+fn with_int<F>(f: F) where F: FnOnce(&isize) {
+ let x = 3;
+ f(&x);
+}
+
+fn main() {
+ let mut x: Option<&isize> = None;
+ with_int(|y| x = Some(y));
+ //~^ ERROR borrowed data cannot be stored outside of its closure
+}
--- /dev/null
+error: borrowed data cannot be stored outside of its closure
+ --> $DIR/regions-escape-bound-fn.rs:18:27
+ |
+17 | let mut x: Option<&isize> = None;
+ | ----- borrowed data cannot be stored into here...
+18 | with_int(|y| x = Some(y));
+ | --- ^ cannot be stored outside of its closure
+ | |
+ | ...because it cannot outlive this closure
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2012 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.
+
+fn with_int(f: &mut FnMut(&isize)) {
+}
+
+fn main() {
+ let mut x: Option<&isize> = None;
+ with_int(&mut |y| x = Some(y));
+ //~^ ERROR borrowed data cannot be stored outside of its closure
+}
--- /dev/null
+error: borrowed data cannot be stored outside of its closure
+ --> $DIR/regions-escape-unboxed-closure.rs:16:32
+ |
+15 | let mut x: Option<&isize> = None;
+ | ----- borrowed data cannot be stored into here...
+16 | with_int(&mut |y| x = Some(y));
+ | --- ^ cannot be stored outside of its closure
+ | |
+ | ...because it cannot outlive this closure
+
+error: aborting due to previous error
+
--- /dev/null
+// 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.
+
+#![allow(warnings)]
+
+fn closure_expecting_bound<F>(_: F)
+ where F: FnOnce(&u32)
+{
+}
+
+fn closure_expecting_free<'a, F>(_: F)
+ where F: FnOnce(&'a u32)
+{
+}
+
+fn expect_bound_supply_nothing() {
+ // Because `x` is inferred to have a bound region, we cannot allow
+ // it to escape into `f`:
+ let mut f: Option<&u32> = None;
+ closure_expecting_bound(|x| {
+ f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
+ });
+}
+
+fn expect_bound_supply_bound() {
+ // Because `x` is inferred to have a bound region, we cannot allow
+ // it to escape into `f`, even with an explicit type annotation on
+ // closure:
+ let mut f: Option<&u32> = None;
+ closure_expecting_bound(|x: &u32| {
+ f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
+ });
+}
+
+fn expect_bound_supply_named<'x>() {
+ let mut f: Option<&u32> = None;
+
+ // Here we give a type annotation that `x` should be free. We get
+ // an error because of that.
+ closure_expecting_bound(|x: &'x u32| {
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+
+ // And we still cannot let `x` escape into `f`.
+ f = Some(x);
+ //~^ ERROR borrowed data cannot be stored outside of its closure
+ });
+}
+
+fn expect_free_supply_nothing() {
+ let mut f: Option<&u32> = None;
+ closure_expecting_free(|x| f = Some(x)); // OK
+}
+
+fn expect_free_supply_bound() {
+ let mut f: Option<&u32> = None;
+
+ // Here, even though the annotation `&u32` could be seen as being
+ // bound in the closure, we permit it to be defined as a free
+ // region (which is inferred to something in the fn body).
+ closure_expecting_free(|x: &u32| f = Some(x)); // OK
+}
+
+fn expect_free_supply_named<'x>() {
+ let mut f: Option<&u32> = None;
+
+ // Here, even though the annotation `&u32` could be seen as being
+ // bound in the closure, we permit it to be defined as a free
+ // region (which is inferred to something in the fn body).
+ closure_expecting_free(|x: &'x u32| f = Some(x)); // OK
+}
+
+fn main() { }
--- /dev/null
+error: borrowed data cannot be stored outside of its closure
+ --> $DIR/expect-region-supply-region.rs:28:18
+ |
+26 | let mut f: Option<&u32> = None;
+ | ----- borrowed data cannot be stored into here...
+27 | closure_expecting_bound(|x| {
+ | --- ...because it cannot outlive this closure
+28 | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
+ | ^ cannot be stored outside of its closure
+
+error: borrowed data cannot be stored outside of its closure
+ --> $DIR/expect-region-supply-region.rs:38:18
+ |
+36 | let mut f: Option<&u32> = None;
+ | ----- borrowed data cannot be stored into here...
+37 | closure_expecting_bound(|x: &u32| {
+ | --------- ...because it cannot outlive this closure
+38 | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
+ | ^ cannot be stored outside of its closure
+
+error[E0308]: mismatched types
+ --> $DIR/expect-region-supply-region.rs:47:33
+ |
+47 | closure_expecting_bound(|x: &'x u32| {
+ | ^^^^^^^ lifetime mismatch
+ |
+ = note: expected type `&u32`
+ found type `&'x u32`
+note: the anonymous lifetime #2 defined on the body at 47:29...
+ --> $DIR/expect-region-supply-region.rs:47:29
+ |
+47 | closure_expecting_bound(|x: &'x u32| {
+ | _____________________________^
+48 | | //~^ ERROR mismatched types
+49 | | //~| ERROR mismatched types
+50 | |
+... |
+53 | | //~^ ERROR borrowed data cannot be stored outside of its closure
+54 | | });
+ | |_____^
+note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 42:1
+ --> $DIR/expect-region-supply-region.rs:42:1
+ |
+42 | / fn expect_bound_supply_named<'x>() {
+43 | | let mut f: Option<&u32> = None;
+44 | |
+45 | | // Here we give a type annotation that `x` should be free. We get
+... |
+54 | | });
+55 | | }
+ | |_^
+
+error[E0308]: mismatched types
+ --> $DIR/expect-region-supply-region.rs:47:33
+ |
+47 | closure_expecting_bound(|x: &'x u32| {
+ | ^^^^^^^ lifetime mismatch
+ |
+ = note: expected type `&u32`
+ found type `&'x u32`
+note: the lifetime 'x as defined on the function body at 42:1...
+ --> $DIR/expect-region-supply-region.rs:42:1
+ |
+42 | / fn expect_bound_supply_named<'x>() {
+43 | | let mut f: Option<&u32> = None;
+44 | |
+45 | | // Here we give a type annotation that `x` should be free. We get
+... |
+54 | | });
+55 | | }
+ | |_^
+note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 47:29
+ --> $DIR/expect-region-supply-region.rs:47:29
+ |
+47 | closure_expecting_bound(|x: &'x u32| {
+ | _____________________________^
+48 | | //~^ ERROR mismatched types
+49 | | //~| ERROR mismatched types
+50 | |
+... |
+53 | | //~^ ERROR borrowed data cannot be stored outside of its closure
+54 | | });
+ | |_____^
+
+error: borrowed data cannot be stored outside of its closure
+ --> $DIR/expect-region-supply-region.rs:52:18
+ |
+43 | let mut f: Option<&u32> = None;
+ | ----- borrowed data cannot be stored into here...
+...
+47 | closure_expecting_bound(|x: &'x u32| {
+ | ------------ ...because it cannot outlive this closure
+...
+52 | f = Some(x);
+ | ^ cannot be stored outside of its closure
+
+error: aborting due to 5 previous errors
+
fn main() {
let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
let e4 = E::Empty4();
- //~^ ERROR expected function, found `E::Empty4` [E0618]
+ //~^ ERROR expected function, found enum variant `E::Empty4` [E0618]
let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2`
let xe4 = XE::XEmpty4();
- //~^ ERROR expected function, found `XE::XEmpty4` [E0618]
+ //~^ ERROR expected function, found enum variant `XE::XEmpty4` [E0618]
}
error[E0618]: expected function, found `Empty2`
--> $DIR/empty-struct-unit-expr.rs:25:14
|
-25 | let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
- | ^^^^^^^^
- |
-note: defined here
- --> $DIR/empty-struct-unit-expr.rs:18:1
- |
18 | struct Empty2;
- | ^^^^^^^^^^^^^^
+ | -------------- `Empty2` defined here
+...
+25 | let e2 = Empty2(); //~ ERROR expected function, found `Empty2`
+ | ^^^^^^^^ not a function
-error[E0618]: expected function, found `E::Empty4`
+error[E0618]: expected function, found enum variant `E::Empty4`
--> $DIR/empty-struct-unit-expr.rs:26:14
|
+21 | Empty4
+ | ------ `E::Empty4` defined here
+...
26 | let e4 = E::Empty4();
- | ^^^^^^^^^^^
- |
- = help: did you mean to write `E::Empty4`?
-note: defined here
- --> $DIR/empty-struct-unit-expr.rs:21:5
+ | ^^^^^^^^^^^ not a function
+help: `E::Empty4` is a unit variant, you need to write it without the parenthesis
|
-21 | Empty4
- | ^^^^^^
+26 | let e4 = E::Empty4;
+ | ^^^^^^^^^
error[E0618]: expected function, found `empty_struct::XEmpty2`
--> $DIR/empty-struct-unit-expr.rs:28:15
|
28 | let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2`
- | ^^^^^^^^^
+ | ^^^^^^^^^ not a function
-error[E0618]: expected function, found `XE::XEmpty4`
+error[E0618]: expected function, found enum variant `XE::XEmpty4`
--> $DIR/empty-struct-unit-expr.rs:29:15
|
29 | let xe4 = XE::XEmpty4();
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^ not a function
+help: `XE::XEmpty4` is a unit variant, you need to write it without the parenthesis
|
- = help: did you mean to write `XE::XEmpty4`?
+29 | let xe4 = XE::XEmpty4;
+ | ^^^^^^^^^^^
error: aborting due to 4 previous errors
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[repr(transparent)] //~ error: the `#[repr(transparent)]` attribute is experimental
+struct Foo(u64);
+
+fn main() {}
--- /dev/null
+error[E0658]: the `#[repr(transparent)]` attribute is experimental (see issue #43036)
+ --> $DIR/feature-gate-repr_transparent.rs:11:1
+ |
+11 | #[repr(transparent)] //~ error: the `#[repr(transparent)]` attribute is experimental
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(repr_transparent)] to the crate attributes to enable
+
+error: aborting due to previous error
+
25 | use a::foo as Otherfoo; //~ ERROR the name `foo` is defined multiple times
| ^^^^^^^^^^^^^^^^^^
-error: `foo` is ambiguous
+error[E0659]: `foo` is ambiguous
--> $DIR/duplicate.rs:56:9
|
56 | use self::foo::bar; //~ ERROR `foo` is ambiguous
| ^^^^^^^^^^^
= note: consider adding an explicit import of `foo` to disambiguate
-error: `foo` is ambiguous
+error[E0659]: `foo` is ambiguous
--> $DIR/duplicate.rs:45:5
|
45 | f::foo(); //~ ERROR `foo` is ambiguous
| ^^^^
= note: consider adding an explicit import of `foo` to disambiguate
-error: `foo` is ambiguous
+error[E0659]: `foo` is ambiguous
--> $DIR/duplicate.rs:46:5
|
46 | g::foo(); //~ ERROR `foo` is ambiguous
| ^^^^
= note: consider adding an explicit import of `foo` to disambiguate
-error: `foo` is ambiguous
+error[E0659]: `foo` is ambiguous
--> $DIR/duplicate.rs:59:9
|
59 | foo::bar(); //~ ERROR `foo` is ambiguous
-error: `bar` is ambiguous
+error[E0659]: `bar` is ambiguous
--> $DIR/macro-paths.rs:25:5
|
25 | bar::m! { //~ ERROR ambiguous
| ^^^^^^
= note: macro-expanded items do not shadow when used in a macro invocation path
-error: `baz` is ambiguous
+error[E0659]: `baz` is ambiguous
--> $DIR/macro-paths.rs:35:5
|
35 | baz::m! { //~ ERROR ambiguous
49 | use two_macros::m;
| ^^^^^^^^^^^^^
-error: `m` is ambiguous
+error[E0659]: `m` is ambiguous
--> $DIR/macros.rs:28:5
|
28 | m! { //~ ERROR ambiguous
| ^^^^^^^^^^^^^
= note: macro-expanded macro imports do not shadow
-error: `m` is ambiguous
+error[E0659]: `m` is ambiguous
--> $DIR/macros.rs:41:9
|
41 | m! { //~ ERROR ambiguous
|
= note: macro-expanded `macro_rules!`s may not shadow existing macros (see RFC 1560)
-error: `panic` is ambiguous
+error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:27:14
|
27 | fn f() { panic!(); } //~ ERROR ambiguous
= note: `panic` is also a builtin macro
= note: consider adding an explicit import of `panic` to disambiguate
-error: `panic` is ambiguous
+error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:32:14
|
32 | fn f() { panic!(); } //~ ERROR ambiguous
= note: `panic` is also a builtin macro
= note: macro-expanded macro imports do not shadow
-error: `n` is ambiguous
+error[E0659]: `n` is ambiguous
--> $DIR/shadow_builtin_macros.rs:61:5
|
61 | n!(); //~ ERROR ambiguous
error[E0618]: expected function, found `i32`
--> $DIR/issue-10969.rs:12:5
|
-12 | i(); //~ERROR expected function, found `i32`
- | ^^^
- |
-note: defined here
- --> $DIR/issue-10969.rs:11:9
- |
11 | fn func(i: i32) {
- | ^
+ | - `i32` defined here
+12 | i(); //~ERROR expected function, found `i32`
+ | ^^^ not a function
error[E0618]: expected function, found `i32`
--> $DIR/issue-10969.rs:16:5
|
-16 | i(); //~ERROR expected function, found `i32`
- | ^^^
- |
-note: defined here
- --> $DIR/issue-10969.rs:15:9
- |
15 | let i = 0i32;
- | ^
+ | - `i32` defined here
+16 | i(); //~ERROR expected function, found `i32`
+ | ^^^ not a function
error: aborting due to 2 previous errors
--- /dev/null
+// Copyright 2018 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.
+
+use self; //~ERROR `self` imports are only allowed within a { } list
+
+fn main() {}
--- /dev/null
+error[E0429]: `self` imports are only allowed within a { } list
+ --> $DIR/issue-47623.rs:11:5
+ |
+11 | use self; //~ERROR `self` imports are only allowed within a { } list
+ | ^^^^
+
+error: aborting due to previous error
+
//~^ ERROR closure is expected to take
[1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
//~^ ERROR closure is expected to take
+ [1, 2, 3].sort_by(|(tuple, tuple2): (usize, _)| panic!());
+ //~^ ERROR closure is expected to take
f(|| panic!());
//~^ ERROR closure is expected to take
let bar = |i, x, y| i;
let _it = vec![1, 2, 3].into_iter().enumerate().map(bar);
//~^ ERROR closure is expected to take
+ let _it = vec![1, 2, 3].into_iter().enumerate().map(qux);
+ //~^ ERROR function is expected to take
}
fn foo() {}
+fn qux(x: usize, y: usize) {}
| |
| expected closure that takes 2 arguments
-error[E0593]: closure is expected to take 2 arguments, but it takes 1 argument
+error[E0593]: closure is expected to take 2 distinct arguments, but it takes a single 2-tuple as argument
--> $DIR/closure-arg-count.rs:19:15
|
19 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!());
- | ^^^^^^^ ----------------- takes 1 argument
+ | ^^^^^^^ ----------------- takes a single 2-tuple as argument
| |
- | expected closure that takes 2 arguments
+ | expected closure that takes 2 distinct arguments
+help: change the closure to take multiple arguments instead of a single tuple
+ |
+19 | [1, 2, 3].sort_by(|tuple, tuple2| panic!());
+ | ^^^^^^^^^^^^^^^
+
+error[E0593]: closure is expected to take 2 distinct arguments, but it takes a single 2-tuple as argument
+ --> $DIR/closure-arg-count.rs:21:15
+ |
+21 | [1, 2, 3].sort_by(|(tuple, tuple2): (usize, _)| panic!());
+ | ^^^^^^^ ----------------------------- takes a single 2-tuple as argument
+ | |
+ | expected closure that takes 2 distinct arguments
+help: change the closure to take multiple arguments instead of a single tuple
+ |
+21 | [1, 2, 3].sort_by(|tuple, tuple2| panic!());
+ | ^^^^^^^^^^^^^^^
error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments
- --> $DIR/closure-arg-count.rs:21:5
+ --> $DIR/closure-arg-count.rs:23:5
|
-21 | f(|| panic!());
+23 | f(|| panic!());
| ^ -- takes 0 arguments
| |
| expected closure that takes 1 argument
13 | fn f<F: Fn<usize>>(_: F) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0593]: closure is expected to take a single tuple as argument, but it takes 2 distinct arguments
- --> $DIR/closure-arg-count.rs:24:53
+error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
+ --> $DIR/closure-arg-count.rs:26:53
|
-24 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
- | ^^^ ------ help: consider changing the closure to accept a tuple: `|(i, x)|`
+26 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i);
+ | ^^^ ------ takes 2 distinct arguments
| |
- | expected closure that takes a single tuple as argument
+ | expected closure that takes a single 2-tuple as argument
+help: change the closure to accept a tuple instead of individual arguments
+ |
+26 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|(i, x)| i);
+ | ^^^^^^^^
-error[E0593]: closure is expected to take a single tuple as argument, but it takes 2 distinct arguments
- --> $DIR/closure-arg-count.rs:26:53
+error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
+ --> $DIR/closure-arg-count.rs:28:53
|
-26 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i);
- | ^^^ ------------- help: consider changing the closure to accept a tuple: `|(i, x): (usize, _)|`
+28 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i: usize, x| i);
+ | ^^^ ------------- takes 2 distinct arguments
| |
- | expected closure that takes a single tuple as argument
+ | expected closure that takes a single 2-tuple as argument
+help: change the closure to accept a tuple instead of individual arguments
+ |
+28 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|(i, x)| i);
+ | ^^^^^^^^
error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 3 distinct arguments
- --> $DIR/closure-arg-count.rs:28:53
+ --> $DIR/closure-arg-count.rs:30:53
|
-28 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i);
+30 | let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x, y| i);
| ^^^ --------- takes 3 distinct arguments
| |
| expected closure that takes a single 2-tuple as argument
error[E0593]: function is expected to take a single 2-tuple as argument, but it takes 0 arguments
- --> $DIR/closure-arg-count.rs:30:53
+ --> $DIR/closure-arg-count.rs:32:53
|
-30 | let _it = vec![1, 2, 3].into_iter().enumerate().map(foo);
+32 | let _it = vec![1, 2, 3].into_iter().enumerate().map(foo);
| ^^^ expected function that takes a single 2-tuple as argument
...
-37 | fn foo() {}
+41 | fn foo() {}
| -------- takes 0 arguments
error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 3 distinct arguments
- --> $DIR/closure-arg-count.rs:33:53
+ --> $DIR/closure-arg-count.rs:35:53
|
-32 | let bar = |i, x, y| i;
+34 | let bar = |i, x, y| i;
| --------- takes 3 distinct arguments
-33 | let _it = vec![1, 2, 3].into_iter().enumerate().map(bar);
+35 | let _it = vec![1, 2, 3].into_iter().enumerate().map(bar);
| ^^^ expected closure that takes a single 2-tuple as argument
-error: aborting due to 9 previous errors
+error[E0593]: function is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments
+ --> $DIR/closure-arg-count.rs:37:53
+ |
+37 | let _it = vec![1, 2, 3].into_iter().enumerate().map(qux);
+ | ^^^ expected function that takes a single 2-tuple as argument
+...
+42 | fn qux(x: usize, y: usize) {}
+ | -------------------------- takes 2 distinct arguments
+
+error: aborting due to 11 previous errors
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators, nll)]
+
+// Test for issue #47189. Here, both `s` and `t` are live for the
+// generator's lifetime, but within the generator they have distinct
+// lifetimes. We accept this code -- even though the borrow extends
+// over a yield -- because the data that is borrowed (`*x`) is not
+// stored on the stack.
+
+// must-compile-successfully
+
+fn foo(x: &mut u32) {
+ move || {
+ let s = &mut *x;
+ yield;
+ *s += 1;
+
+ let t = &mut *x;
+ yield;
+ *t += 1;
+ };
+}
+
+fn main() {
+ foo(&mut 0);
+}
--- /dev/null
+// 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.
+
+mod m {
+ pub enum E {
+ Fn(u8),
+ Struct {
+ s: u8,
+ },
+ Unit,
+ }
+
+ pub mod n {
+ pub(in m) enum Z {
+ Fn(u8),
+ Struct {
+ s: u8,
+ },
+ Unit,
+ }
+ }
+
+ use m::n::Z; // OK, only the type is imported
+
+ fn f() {
+ n::Z;
+ //~^ ERROR expected value, found enum `n::Z`
+ Z;
+ //~^ ERROR expected value, found enum `Z`
+ let _: Z = Z::Fn;
+ //~^ ERROR mismatched types
+ let _: Z = Z::Struct;
+ //~^ ERROR expected value, found struct variant `Z::Struct`
+ let _ = Z::Unit();
+ //~^ ERROR expected function, found enum variant `Z::Unit`
+ let _ = Z::Unit {};
+ // This is ok, it is equivalent to not having braces
+ }
+}
+
+use m::E; // OK, only the type is imported
+
+fn main() {
+ let _: E = m::E;
+ //~^ ERROR expected value, found enum `m::E`
+ let _: E = m::E::Fn;
+ //~^ ERROR mismatched types
+ let _: E = m::E::Struct;
+ //~^ ERROR expected value, found struct variant `m::E::Struct`
+ let _: E = m::E::Unit();
+ //~^ ERROR expected function, found enum variant `m::E::Unit`
+ let _: E = E;
+ //~^ ERROR expected value, found enum `E`
+ let _: E = E::Fn;
+ //~^ ERROR mismatched types
+ let _: E = E::Struct;
+ //~^ ERROR expected value, found struct variant `E::Struct`
+ let _: E = E::Unit();
+ //~^ ERROR expected function, found enum variant `E::Unit`
+ let _: Z = m::n::Z;
+ //~^ ERROR cannot find type `Z` in this scope
+ //~| ERROR expected value, found enum `m::n::Z`
+ //~| ERROR enum `Z` is private
+ let _: Z = m::n::Z::Fn;
+ //~^ ERROR cannot find type `Z` in this scope
+ //~| ERROR enum `Z` is private
+ let _: Z = m::n::Z::Struct;
+ //~^ ERROR cannot find type `Z` in this scope
+ //~| ERROR expected value, found struct variant `m::n::Z::Struct`
+ //~| ERROR enum `Z` is private
+ let _: Z = m::n::Z::Unit {};
+ //~^ ERROR cannot find type `Z` in this scope
+ //~| ERROR enum `Z` is private
+}
--- /dev/null
+error[E0423]: expected value, found enum `n::Z`
+ --> $DIR/privacy-enum-ctor.rs:33:9
+ |
+33 | n::Z;
+ | ^^^^
+ |
+ = note: did you mean to use one of the following variants?
+ - `m::Z::Fn`
+ - `m::Z::Struct`
+ - `m::Z::Unit`
+
+error[E0423]: expected value, found enum `Z`
+ --> $DIR/privacy-enum-ctor.rs:35:9
+ |
+35 | Z;
+ | ^ did you mean `f`?
+ |
+ = note: did you mean to use one of the following variants?
+ - `m::Z::Fn`
+ - `m::Z::Struct`
+ - `m::Z::Unit`
+
+error[E0423]: expected value, found struct variant `Z::Struct`
+ --> $DIR/privacy-enum-ctor.rs:39:20
+ |
+39 | let _: Z = Z::Struct;
+ | ^^^^^^^^^ did you mean `Z::Struct { /* fields */ }`?
+
+error[E0423]: expected value, found enum `m::E`
+ --> $DIR/privacy-enum-ctor.rs:51:16
+ |
+51 | let _: E = m::E;
+ | ^^^-
+ | |
+ | did you mean `f`?
+ |
+ = note: did you mean to use one of the following variants?
+ - `E::Fn`
+ - `E::Struct`
+ - `E::Unit`
+help: possible better candidates are found in other modules, you can import them into scope
+ |
+48 | use std::f32::consts::E;
+ |
+48 | use std::f64::consts::E;
+ |
+
+error[E0423]: expected value, found struct variant `m::E::Struct`
+ --> $DIR/privacy-enum-ctor.rs:55:16
+ |
+55 | let _: E = m::E::Struct;
+ | ^^^^^^^^^^^^ did you mean `m::E::Struct { /* fields */ }`?
+
+error[E0423]: expected value, found enum `E`
+ --> $DIR/privacy-enum-ctor.rs:59:16
+ |
+59 | let _: E = E;
+ | ^
+ |
+ = note: did you mean to use one of the following variants?
+ - `E::Fn`
+ - `E::Struct`
+ - `E::Unit`
+help: possible better candidates are found in other modules, you can import them into scope
+ |
+48 | use std::f32::consts::E;
+ |
+48 | use std::f64::consts::E;
+ |
+
+error[E0423]: expected value, found struct variant `E::Struct`
+ --> $DIR/privacy-enum-ctor.rs:63:16
+ |
+63 | let _: E = E::Struct;
+ | ^^^^^^^^^ did you mean `E::Struct { /* fields */ }`?
+
+error[E0412]: cannot find type `Z` in this scope
+ --> $DIR/privacy-enum-ctor.rs:67:12
+ |
+67 | let _: Z = m::n::Z;
+ | ^ did you mean `E`?
+help: possible candidate is found in another module, you can import it into scope
+ |
+48 | use m::n::Z;
+ |
+
+error[E0423]: expected value, found enum `m::n::Z`
+ --> $DIR/privacy-enum-ctor.rs:67:16
+ |
+67 | let _: Z = m::n::Z;
+ | ^^^^^^^
+ |
+ = note: did you mean to use one of the following variants?
+ - `m::Z::Fn`
+ - `m::Z::Struct`
+ - `m::Z::Unit`
+
+error[E0412]: cannot find type `Z` in this scope
+ --> $DIR/privacy-enum-ctor.rs:71:12
+ |
+71 | let _: Z = m::n::Z::Fn;
+ | ^ did you mean `E`?
+help: possible candidate is found in another module, you can import it into scope
+ |
+48 | use m::n::Z;
+ |
+
+error[E0412]: cannot find type `Z` in this scope
+ --> $DIR/privacy-enum-ctor.rs:74:12
+ |
+74 | let _: Z = m::n::Z::Struct;
+ | ^ did you mean `E`?
+help: possible candidate is found in another module, you can import it into scope
+ |
+48 | use m::n::Z;
+ |
+
+error[E0423]: expected value, found struct variant `m::n::Z::Struct`
+ --> $DIR/privacy-enum-ctor.rs:74:16
+ |
+74 | let _: Z = m::n::Z::Struct;
+ | ^^^^^^^^^^^^^^^ did you mean `m::n::Z::Struct { /* fields */ }`?
+
+error[E0412]: cannot find type `Z` in this scope
+ --> $DIR/privacy-enum-ctor.rs:78:12
+ |
+78 | let _: Z = m::n::Z::Unit {};
+ | ^ did you mean `E`?
+help: possible candidate is found in another module, you can import it into scope
+ |
+48 | use m::n::Z;
+ |
+
+error[E0603]: enum `Z` is private
+ --> $DIR/privacy-enum-ctor.rs:67:16
+ |
+67 | let _: Z = m::n::Z;
+ | ^^^^^^^
+
+error[E0603]: enum `Z` is private
+ --> $DIR/privacy-enum-ctor.rs:71:16
+ |
+71 | let _: Z = m::n::Z::Fn;
+ | ^^^^^^^^^^^
+
+error[E0603]: enum `Z` is private
+ --> $DIR/privacy-enum-ctor.rs:74:16
+ |
+74 | let _: Z = m::n::Z::Struct;
+ | ^^^^^^^^^^^^^^^
+
+error[E0603]: enum `Z` is private
+ --> $DIR/privacy-enum-ctor.rs:78:16
+ |
+78 | let _: Z = m::n::Z::Unit {};
+ | ^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/privacy-enum-ctor.rs:37:20
+ |
+37 | let _: Z = Z::Fn;
+ | ^^^^^ expected enum `m::n::Z`, found fn item
+ |
+ = note: expected type `m::n::Z`
+ found type `fn(u8) -> m::n::Z {m::n::Z::Fn}`
+
+error[E0618]: expected function, found enum variant `Z::Unit`
+ --> $DIR/privacy-enum-ctor.rs:41:17
+ |
+26 | Unit,
+ | ---- `Z::Unit` defined here
+...
+41 | let _ = Z::Unit();
+ | ^^^^^^^^^ not a function
+help: `Z::Unit` is a unit variant, you need to write it without the parenthesis
+ |
+41 | let _ = Z::Unit;
+ | ^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/privacy-enum-ctor.rs:53:16
+ |
+53 | let _: E = m::E::Fn;
+ | ^^^^^^^^ expected enum `m::E`, found fn item
+ |
+ = note: expected type `m::E`
+ found type `fn(u8) -> m::E {m::E::Fn}`
+
+error[E0618]: expected function, found enum variant `m::E::Unit`
+ --> $DIR/privacy-enum-ctor.rs:57:16
+ |
+17 | Unit,
+ | ---- `m::E::Unit` defined here
+...
+57 | let _: E = m::E::Unit();
+ | ^^^^^^^^^^^^ not a function
+help: `m::E::Unit` is a unit variant, you need to write it without the parenthesis
+ |
+57 | let _: E = m::E::Unit;
+ | ^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/privacy-enum-ctor.rs:61:16
+ |
+61 | let _: E = E::Fn;
+ | ^^^^^ expected enum `m::E`, found fn item
+ |
+ = note: expected type `m::E`
+ found type `fn(u8) -> m::E {m::E::Fn}`
+
+error[E0618]: expected function, found enum variant `E::Unit`
+ --> $DIR/privacy-enum-ctor.rs:65:16
+ |
+17 | Unit,
+ | ---- `E::Unit` defined here
+...
+65 | let _: E = E::Unit();
+ | ^^^^^^^^^ not a function
+help: `E::Unit` is a unit variant, you need to write it without the parenthesis
+ |
+65 | let _: E = E::Unit;
+ | ^^^^^^^
+
+error: aborting due to 23 previous errors
+
mod m {
pub struct S(u8);
+ pub struct S2 {
+ s: u8
+ }
pub mod n {
pub(in m) struct Z(pub(in m::n) u8);
use m::n::Z; // OK, only the type is imported
fn f() {
- n::Z; //~ ERROR tuple struct `Z` is private
+ n::Z;
+ //~^ ERROR tuple struct `Z` is private
Z;
//~^ ERROR expected value, found struct `Z`
}
}
use m::S; // OK, only the type is imported
+use m::S2; // OK, only the type is imported
fn main() {
- m::S; //~ ERROR tuple struct `S` is private
+ m::S;
+ //~^ ERROR tuple struct `S` is private
+ let _: S = m::S(2);
+ //~^ ERROR tuple struct `S` is private
S;
//~^ ERROR expected value, found struct `S`
- m::n::Z; //~ ERROR tuple struct `Z` is private
+ m::n::Z;
+ //~^ ERROR tuple struct `Z` is private
+
+ S2;
+ //~^ ERROR expected value, found struct `S2`
- xcrate::m::S; //~ ERROR tuple struct `S` is private
+ xcrate::m::S;
+ //~^ ERROR tuple struct `S` is private
xcrate::S;
//~^ ERROR expected value, found struct `xcrate::S`
- xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private
+ xcrate::m::n::Z;
+ //~^ ERROR tuple struct `Z` is private
}
error[E0423]: expected value, found struct `Z`
- --> $DIR/privacy-struct-ctor.rs:26:9
+ --> $DIR/privacy-struct-ctor.rs:30:9
|
-26 | Z;
+30 | Z;
| ^
| |
| did you mean `S`?
| constructor is not visible here due to private fields
- | did you mean `Z { /* fields */ }`?
help: possible better candidate is found in another module, you can import it into scope
|
-22 | use m::n::Z;
+25 | use m::n::Z;
|
error[E0423]: expected value, found struct `S`
- --> $DIR/privacy-struct-ctor.rs:35:5
+ --> $DIR/privacy-struct-ctor.rs:43:5
|
-35 | S;
- | ^
- | |
- | constructor is not visible here due to private fields
- | did you mean `S { /* fields */ }`?
+43 | S;
+ | ^ constructor is not visible here due to private fields
help: possible better candidate is found in another module, you can import it into scope
|
-31 | use m::S;
+35 | use m::S;
|
+error[E0423]: expected value, found struct `S2`
+ --> $DIR/privacy-struct-ctor.rs:48:5
+ |
+48 | S2;
+ | ^^ did you mean `S2 { /* fields */ }`?
+
error[E0423]: expected value, found struct `xcrate::S`
- --> $DIR/privacy-struct-ctor.rs:40:5
+ --> $DIR/privacy-struct-ctor.rs:53:5
|
-40 | xcrate::S;
- | ^^^^^^^^^
- | |
- | constructor is not visible here due to private fields
- | did you mean `xcrate::S { /* fields */ }`?
+53 | xcrate::S;
+ | ^^^^^^^^^ constructor is not visible here due to private fields
help: possible better candidate is found in another module, you can import it into scope
|
-31 | use m::S;
+35 | use m::S;
|
error[E0603]: tuple struct `Z` is private
- --> $DIR/privacy-struct-ctor.rs:25:9
+ --> $DIR/privacy-struct-ctor.rs:28:9
|
-25 | n::Z; //~ ERROR tuple struct `Z` is private
+28 | n::Z;
| ^^^^
error[E0603]: tuple struct `S` is private
- --> $DIR/privacy-struct-ctor.rs:34:5
+ --> $DIR/privacy-struct-ctor.rs:39:5
|
-34 | m::S; //~ ERROR tuple struct `S` is private
+39 | m::S;
| ^^^^
+error[E0603]: tuple struct `S` is private
+ --> $DIR/privacy-struct-ctor.rs:41:16
+ |
+41 | let _: S = m::S(2);
+ | ^^^^
+
error[E0603]: tuple struct `Z` is private
- --> $DIR/privacy-struct-ctor.rs:37:5
+ --> $DIR/privacy-struct-ctor.rs:45:5
|
-37 | m::n::Z; //~ ERROR tuple struct `Z` is private
+45 | m::n::Z;
| ^^^^^^^
error[E0603]: tuple struct `S` is private
- --> $DIR/privacy-struct-ctor.rs:39:5
+ --> $DIR/privacy-struct-ctor.rs:51:5
|
-39 | xcrate::m::S; //~ ERROR tuple struct `S` is private
+51 | xcrate::m::S;
| ^^^^^^^^^^^^
error[E0603]: tuple struct `Z` is private
- --> $DIR/privacy-struct-ctor.rs:42:5
+ --> $DIR/privacy-struct-ctor.rs:55:5
|
-42 | xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private
+55 | xcrate::m::n::Z;
| ^^^^^^^^^^^^^^^
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
--> $DIR/tuple-struct-alias.rs:16:17
|
16 | let s = Self(0, 1); //~ ERROR expected function
- | ^^^^ did you mean `Self { /* fields */ }`?
+ | ^^^^ not a function
+ |
+ = note: can't use `Self` as a constructor, you must use the implemented struct
error[E0532]: expected tuple struct/variant, found self type `Self`
--> $DIR/tuple-struct-alias.rs:18:13
|
18 | Self(..) => {} //~ ERROR expected tuple struct/variant
- | ^^^^ did you mean `Self { /* fields */ }`?
+ | ^^^^ not a tuple struct/variant
+ |
+ = note: can't use `Self` as a constructor, you must use the implemented struct
error[E0423]: expected function, found type alias `A`
--> $DIR/tuple-struct-alias.rs:24:13
|
24 | let s = A(0, 1); //~ ERROR expected function
- | ^
- | |
- | did you mean `S`?
- | did you mean `A { /* fields */ }`?
+ | ^ did you mean `S`?
+ |
+ = note: can't use a type alias as a constructor
error[E0532]: expected tuple struct/variant, found type alias `A`
--> $DIR/tuple-struct-alias.rs:26:9
|
26 | A(..) => {} //~ ERROR expected tuple struct/variant
- | ^
- | |
- | did you mean `S`?
- | did you mean `A { /* fields */ }`?
+ | ^ did you mean `S`?
+ |
+ = note: can't use a type alias as a constructor
error: aborting due to 4 previous errors
--- /dev/null
+// Copyright 2018 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.
+
+fn foo() -> i32 {
+ 4
+}
+fn main() {
+ let x: u16 = foo();
+ //~^ ERROR mismatched types
+ let y: i64 = x + x;
+ //~^ ERROR mismatched types
+ let z: i32 = x + x;
+ //~^ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-2.rs:15:18
+ |
+15 | let x: u16 = foo();
+ | ^^^^^ expected u16, found i32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-2.rs:17:18
+ |
+17 | let y: i64 = x + x;
+ | ^^^^^ expected i64, found u16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast-2.rs:19:18
+ |
+19 | let z: i32 = x + x;
+ | ^^^^^ expected i32, found u16
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// Copyright 2018 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.
+
+
+fn foo<N>(_x: N) {}
+
+fn main() {
+ let x_usize: usize = 1;
+ let x_u64: u64 = 2;
+ let x_u32: u32 = 3;
+ let x_u16: u16 = 4;
+ let x_u8: u8 = 5;
+ let x_isize: isize = 6;
+ let x_i64: i64 = 7;
+ let x_i32: i32 = 8;
+ let x_i16: i16 = 9;
+ let x_i8: i8 = 10;
+ let x_f64: f64 = 11.0;
+ let x_f32: f32 = 12.0;
+
+ foo::<usize>(x_usize);
+ foo::<usize>(x_u64);
+ //~^ ERROR mismatched types
+ foo::<usize>(x_u32);
+ //~^ ERROR mismatched types
+ foo::<usize>(x_u16);
+ //~^ ERROR mismatched types
+ foo::<usize>(x_u8);
+ //~^ ERROR mismatched types
+ foo::<usize>(x_isize);
+ //~^ ERROR mismatched types
+ foo::<usize>(x_i64);
+ //~^ ERROR mismatched types
+ foo::<usize>(x_i32);
+ //~^ ERROR mismatched types
+ foo::<usize>(x_i16);
+ //~^ ERROR mismatched types
+ foo::<usize>(x_i8);
+ //~^ ERROR mismatched types
+ foo::<usize>(x_f64);
+ //~^ ERROR mismatched types
+ foo::<usize>(x_f32);
+ //~^ ERROR mismatched types
+
+ foo::<isize>(x_usize);
+ //~^ ERROR mismatched types
+ foo::<isize>(x_u64);
+ //~^ ERROR mismatched types
+ foo::<isize>(x_u32);
+ //~^ ERROR mismatched types
+ foo::<isize>(x_u16);
+ //~^ ERROR mismatched types
+ foo::<isize>(x_u8);
+ //~^ ERROR mismatched types
+ foo::<isize>(x_isize);
+ foo::<isize>(x_i64);
+ //~^ ERROR mismatched types
+ foo::<isize>(x_i32);
+ //~^ ERROR mismatched types
+ foo::<isize>(x_i16);
+ //~^ ERROR mismatched types
+ foo::<isize>(x_i8);
+ //~^ ERROR mismatched types
+ foo::<isize>(x_f64);
+ //~^ ERROR mismatched types
+ foo::<isize>(x_f32);
+ //~^ ERROR mismatched types
+
+ foo::<u64>(x_usize);
+ //~^ ERROR mismatched types
+ foo::<u64>(x_u64);
+ foo::<u64>(x_u32);
+ //~^ ERROR mismatched types
+ foo::<u64>(x_u16);
+ //~^ ERROR mismatched types
+ foo::<u64>(x_u8);
+ //~^ ERROR mismatched types
+ foo::<u64>(x_isize);
+ //~^ ERROR mismatched types
+ foo::<u64>(x_i64);
+ //~^ ERROR mismatched types
+ foo::<u64>(x_i32);
+ //~^ ERROR mismatched types
+ foo::<u64>(x_i16);
+ //~^ ERROR mismatched types
+ foo::<u64>(x_i8);
+ //~^ ERROR mismatched types
+ foo::<u64>(x_f64);
+ //~^ ERROR mismatched types
+ foo::<u64>(x_f32);
+ //~^ ERROR mismatched types
+
+ foo::<i64>(x_usize);
+ //~^ ERROR mismatched types
+ foo::<i64>(x_u64);
+ //~^ ERROR mismatched types
+ foo::<i64>(x_u32);
+ //~^ ERROR mismatched types
+ foo::<i64>(x_u16);
+ //~^ ERROR mismatched types
+ foo::<i64>(x_u8);
+ //~^ ERROR mismatched types
+ foo::<i64>(x_isize);
+ //~^ ERROR mismatched types
+ foo::<i64>(x_i64);
+ foo::<i64>(x_i32);
+ //~^ ERROR mismatched types
+ foo::<i64>(x_i16);
+ //~^ ERROR mismatched types
+ foo::<i64>(x_i8);
+ //~^ ERROR mismatched types
+ foo::<i64>(x_f64);
+ //~^ ERROR mismatched types
+ foo::<i64>(x_f32);
+ //~^ ERROR mismatched types
+
+ foo::<u32>(x_usize);
+ //~^ ERROR mismatched types
+ foo::<u32>(x_u64);
+ //~^ ERROR mismatched types
+ foo::<u32>(x_u32);
+ foo::<u32>(x_u16);
+ //~^ ERROR mismatched types
+ foo::<u32>(x_u8);
+ //~^ ERROR mismatched types
+ foo::<u32>(x_isize);
+ //~^ ERROR mismatched types
+ foo::<u32>(x_i64);
+ //~^ ERROR mismatched types
+ foo::<u32>(x_i32);
+ //~^ ERROR mismatched types
+ foo::<u32>(x_i16);
+ //~^ ERROR mismatched types
+ foo::<u32>(x_i8);
+ //~^ ERROR mismatched types
+ foo::<u32>(x_f64);
+ //~^ ERROR mismatched types
+ foo::<u32>(x_f32);
+ //~^ ERROR mismatched types
+
+ foo::<i32>(x_usize);
+ //~^ ERROR mismatched types
+ foo::<i32>(x_u64);
+ //~^ ERROR mismatched types
+ foo::<i32>(x_u32);
+ //~^ ERROR mismatched types
+ foo::<i32>(x_u16);
+ //~^ ERROR mismatched types
+ foo::<i32>(x_u8);
+ //~^ ERROR mismatched types
+ foo::<i32>(x_isize);
+ //~^ ERROR mismatched types
+ foo::<i32>(x_i64);
+ //~^ ERROR mismatched types
+ foo::<i32>(x_i32);
+ foo::<i32>(x_i16);
+ //~^ ERROR mismatched types
+ foo::<i32>(x_i8);
+ //~^ ERROR mismatched types
+ foo::<i32>(x_f64);
+ //~^ ERROR mismatched types
+ foo::<i32>(x_f32);
+ //~^ ERROR mismatched types
+
+ foo::<u16>(x_usize);
+ //~^ ERROR mismatched types
+ foo::<u16>(x_u64);
+ //~^ ERROR mismatched types
+ foo::<u16>(x_u32);
+ //~^ ERROR mismatched types
+ foo::<u16>(x_u16);
+ foo::<u16>(x_u8);
+ //~^ ERROR mismatched types
+ foo::<u16>(x_isize);
+ //~^ ERROR mismatched types
+ foo::<u16>(x_i64);
+ //~^ ERROR mismatched types
+ foo::<u16>(x_i32);
+ //~^ ERROR mismatched types
+ foo::<u16>(x_i16);
+ //~^ ERROR mismatched types
+ foo::<u16>(x_i8);
+ //~^ ERROR mismatched types
+ foo::<u16>(x_f64);
+ //~^ ERROR mismatched types
+ foo::<u16>(x_f32);
+ //~^ ERROR mismatched types
+
+ foo::<i16>(x_usize);
+ //~^ ERROR mismatched types
+ foo::<i16>(x_u64);
+ //~^ ERROR mismatched types
+ foo::<i16>(x_u32);
+ //~^ ERROR mismatched types
+ foo::<i16>(x_u16);
+ //~^ ERROR mismatched types
+ foo::<i16>(x_u8);
+ //~^ ERROR mismatched types
+ foo::<i16>(x_isize);
+ //~^ ERROR mismatched types
+ foo::<i16>(x_i64);
+ //~^ ERROR mismatched types
+ foo::<i16>(x_i32);
+ //~^ ERROR mismatched types
+ foo::<i16>(x_i16);
+ foo::<i16>(x_i8);
+ //~^ ERROR mismatched types
+ foo::<i16>(x_f64);
+ //~^ ERROR mismatched types
+ foo::<i16>(x_f32);
+ //~^ ERROR mismatched types
+
+ foo::<u8>(x_usize);
+ //~^ ERROR mismatched types
+ foo::<u8>(x_u64);
+ //~^ ERROR mismatched types
+ foo::<u8>(x_u32);
+ //~^ ERROR mismatched types
+ foo::<u8>(x_u16);
+ //~^ ERROR mismatched types
+ foo::<u8>(x_u8);
+ foo::<u8>(x_isize);
+ //~^ ERROR mismatched types
+ foo::<u8>(x_i64);
+ //~^ ERROR mismatched types
+ foo::<u8>(x_i32);
+ //~^ ERROR mismatched types
+ foo::<u8>(x_i16);
+ //~^ ERROR mismatched types
+ foo::<u8>(x_i8);
+ //~^ ERROR mismatched types
+ foo::<u8>(x_f64);
+ //~^ ERROR mismatched types
+ foo::<u8>(x_f32);
+ //~^ ERROR mismatched types
+
+ foo::<i8>(x_usize);
+ //~^ ERROR mismatched types
+ foo::<i8>(x_u64);
+ //~^ ERROR mismatched types
+ foo::<i8>(x_u32);
+ //~^ ERROR mismatched types
+ foo::<i8>(x_u16);
+ //~^ ERROR mismatched types
+ foo::<i8>(x_u8);
+ //~^ ERROR mismatched types
+ foo::<i8>(x_isize);
+ //~^ ERROR mismatched types
+ foo::<i8>(x_i64);
+ //~^ ERROR mismatched types
+ foo::<i8>(x_i32);
+ //~^ ERROR mismatched types
+ foo::<i8>(x_i16);
+ //~^ ERROR mismatched types
+ foo::<i8>(x_i8);
+ foo::<i8>(x_f64);
+ //~^ ERROR mismatched types
+ foo::<i8>(x_f32);
+ //~^ ERROR mismatched types
+
+ foo::<f64>(x_usize);
+ //~^ ERROR mismatched types
+ foo::<f64>(x_u64);
+ //~^ ERROR mismatched types
+ foo::<f64>(x_u32);
+ //~^ ERROR mismatched types
+ foo::<f64>(x_u16);
+ //~^ ERROR mismatched types
+ foo::<f64>(x_u8);
+ //~^ ERROR mismatched types
+ foo::<f64>(x_isize);
+ //~^ ERROR mismatched types
+ foo::<f64>(x_i64);
+ //~^ ERROR mismatched types
+ foo::<f64>(x_i32);
+ //~^ ERROR mismatched types
+ foo::<f64>(x_i16);
+ //~^ ERROR mismatched types
+ foo::<f64>(x_i8);
+ //~^ ERROR mismatched types
+ foo::<f64>(x_f64);
+ foo::<f64>(x_f32);
+ //~^ ERROR mismatched types
+
+ foo::<f32>(x_usize);
+ //~^ ERROR mismatched types
+ foo::<f32>(x_u64);
+ //~^ ERROR mismatched types
+ foo::<f32>(x_u32);
+ //~^ ERROR mismatched types
+ foo::<f32>(x_u16);
+ //~^ ERROR mismatched types
+ foo::<f32>(x_u8);
+ //~^ ERROR mismatched types
+ foo::<f32>(x_isize);
+ //~^ ERROR mismatched types
+ foo::<f32>(x_i64);
+ //~^ ERROR mismatched types
+ foo::<f32>(x_i32);
+ //~^ ERROR mismatched types
+ foo::<f32>(x_i16);
+ //~^ ERROR mismatched types
+ foo::<f32>(x_i8);
+ //~^ ERROR mismatched types
+ foo::<f32>(x_f64);
+ //~^ ERROR mismatched types
+ foo::<f32>(x_f32);
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:29:18
+ |
+29 | foo::<usize>(x_u64);
+ | ^^^^^ expected usize, found u64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:31:18
+ |
+31 | foo::<usize>(x_u32);
+ | ^^^^^ expected usize, found u32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:33:18
+ |
+33 | foo::<usize>(x_u16);
+ | ^^^^^ expected usize, found u16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:35:18
+ |
+35 | foo::<usize>(x_u8);
+ | ^^^^ expected usize, found u8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:37:18
+ |
+37 | foo::<usize>(x_isize);
+ | ^^^^^^^ expected usize, found isize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:39:18
+ |
+39 | foo::<usize>(x_i64);
+ | ^^^^^ expected usize, found i64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:41:18
+ |
+41 | foo::<usize>(x_i32);
+ | ^^^^^ expected usize, found i32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:43:18
+ |
+43 | foo::<usize>(x_i16);
+ | ^^^^^ expected usize, found i16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:45:18
+ |
+45 | foo::<usize>(x_i8);
+ | ^^^^ expected usize, found i8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:47:18
+ |
+47 | foo::<usize>(x_f64);
+ | ^^^^^ expected usize, found f64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:49:18
+ |
+49 | foo::<usize>(x_f32);
+ | ^^^^^ expected usize, found f32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:52:18
+ |
+52 | foo::<isize>(x_usize);
+ | ^^^^^^^ expected isize, found usize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:54:18
+ |
+54 | foo::<isize>(x_u64);
+ | ^^^^^ expected isize, found u64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:56:18
+ |
+56 | foo::<isize>(x_u32);
+ | ^^^^^ expected isize, found u32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:58:18
+ |
+58 | foo::<isize>(x_u16);
+ | ^^^^^ expected isize, found u16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:60:18
+ |
+60 | foo::<isize>(x_u8);
+ | ^^^^ expected isize, found u8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:63:18
+ |
+63 | foo::<isize>(x_i64);
+ | ^^^^^ expected isize, found i64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:65:18
+ |
+65 | foo::<isize>(x_i32);
+ | ^^^^^ expected isize, found i32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:67:18
+ |
+67 | foo::<isize>(x_i16);
+ | ^^^^^ expected isize, found i16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:69:18
+ |
+69 | foo::<isize>(x_i8);
+ | ^^^^ expected isize, found i8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:71:18
+ |
+71 | foo::<isize>(x_f64);
+ | ^^^^^ expected isize, found f64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:73:18
+ |
+73 | foo::<isize>(x_f32);
+ | ^^^^^ expected isize, found f32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:76:16
+ |
+76 | foo::<u64>(x_usize);
+ | ^^^^^^^ expected u64, found usize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:79:16
+ |
+79 | foo::<u64>(x_u32);
+ | ^^^^^ expected u64, found u32
+help: you can cast an `u32` to `u64`, which will zero-extend the source value
+ |
+79 | foo::<u64>(x_u32.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:81:16
+ |
+81 | foo::<u64>(x_u16);
+ | ^^^^^ expected u64, found u16
+help: you can cast an `u16` to `u64`, which will zero-extend the source value
+ |
+81 | foo::<u64>(x_u16.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:83:16
+ |
+83 | foo::<u64>(x_u8);
+ | ^^^^ expected u64, found u8
+help: you can cast an `u8` to `u64`, which will zero-extend the source value
+ |
+83 | foo::<u64>(x_u8.into());
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:85:16
+ |
+85 | foo::<u64>(x_isize);
+ | ^^^^^^^ expected u64, found isize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:87:16
+ |
+87 | foo::<u64>(x_i64);
+ | ^^^^^ expected u64, found i64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:89:16
+ |
+89 | foo::<u64>(x_i32);
+ | ^^^^^ expected u64, found i32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:91:16
+ |
+91 | foo::<u64>(x_i16);
+ | ^^^^^ expected u64, found i16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:93:16
+ |
+93 | foo::<u64>(x_i8);
+ | ^^^^ expected u64, found i8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:95:16
+ |
+95 | foo::<u64>(x_f64);
+ | ^^^^^ expected u64, found f64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:97:16
+ |
+97 | foo::<u64>(x_f32);
+ | ^^^^^ expected u64, found f32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:100:16
+ |
+100 | foo::<i64>(x_usize);
+ | ^^^^^^^ expected i64, found usize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:102:16
+ |
+102 | foo::<i64>(x_u64);
+ | ^^^^^ expected i64, found u64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:104:16
+ |
+104 | foo::<i64>(x_u32);
+ | ^^^^^ expected i64, found u32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:106:16
+ |
+106 | foo::<i64>(x_u16);
+ | ^^^^^ expected i64, found u16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:108:16
+ |
+108 | foo::<i64>(x_u8);
+ | ^^^^ expected i64, found u8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:110:16
+ |
+110 | foo::<i64>(x_isize);
+ | ^^^^^^^ expected i64, found isize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:113:16
+ |
+113 | foo::<i64>(x_i32);
+ | ^^^^^ expected i64, found i32
+help: you can cast an `i32` to `i64`, which will sign-extend the source value
+ |
+113 | foo::<i64>(x_i32.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:115:16
+ |
+115 | foo::<i64>(x_i16);
+ | ^^^^^ expected i64, found i16
+help: you can cast an `i16` to `i64`, which will sign-extend the source value
+ |
+115 | foo::<i64>(x_i16.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:117:16
+ |
+117 | foo::<i64>(x_i8);
+ | ^^^^ expected i64, found i8
+help: you can cast an `i8` to `i64`, which will sign-extend the source value
+ |
+117 | foo::<i64>(x_i8.into());
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:119:16
+ |
+119 | foo::<i64>(x_f64);
+ | ^^^^^ expected i64, found f64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:121:16
+ |
+121 | foo::<i64>(x_f32);
+ | ^^^^^ expected i64, found f32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:124:16
+ |
+124 | foo::<u32>(x_usize);
+ | ^^^^^^^ expected u32, found usize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:126:16
+ |
+126 | foo::<u32>(x_u64);
+ | ^^^^^ expected u32, found u64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:129:16
+ |
+129 | foo::<u32>(x_u16);
+ | ^^^^^ expected u32, found u16
+help: you can cast an `u16` to `u32`, which will zero-extend the source value
+ |
+129 | foo::<u32>(x_u16.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:131:16
+ |
+131 | foo::<u32>(x_u8);
+ | ^^^^ expected u32, found u8
+help: you can cast an `u8` to `u32`, which will zero-extend the source value
+ |
+131 | foo::<u32>(x_u8.into());
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:133:16
+ |
+133 | foo::<u32>(x_isize);
+ | ^^^^^^^ expected u32, found isize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:135:16
+ |
+135 | foo::<u32>(x_i64);
+ | ^^^^^ expected u32, found i64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:137:16
+ |
+137 | foo::<u32>(x_i32);
+ | ^^^^^ expected u32, found i32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:139:16
+ |
+139 | foo::<u32>(x_i16);
+ | ^^^^^ expected u32, found i16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:141:16
+ |
+141 | foo::<u32>(x_i8);
+ | ^^^^ expected u32, found i8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:143:16
+ |
+143 | foo::<u32>(x_f64);
+ | ^^^^^ expected u32, found f64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:145:16
+ |
+145 | foo::<u32>(x_f32);
+ | ^^^^^ expected u32, found f32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:148:16
+ |
+148 | foo::<i32>(x_usize);
+ | ^^^^^^^ expected i32, found usize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:150:16
+ |
+150 | foo::<i32>(x_u64);
+ | ^^^^^ expected i32, found u64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:152:16
+ |
+152 | foo::<i32>(x_u32);
+ | ^^^^^ expected i32, found u32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:154:16
+ |
+154 | foo::<i32>(x_u16);
+ | ^^^^^ expected i32, found u16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:156:16
+ |
+156 | foo::<i32>(x_u8);
+ | ^^^^ expected i32, found u8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:158:16
+ |
+158 | foo::<i32>(x_isize);
+ | ^^^^^^^ expected i32, found isize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:160:16
+ |
+160 | foo::<i32>(x_i64);
+ | ^^^^^ expected i32, found i64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:163:16
+ |
+163 | foo::<i32>(x_i16);
+ | ^^^^^ expected i32, found i16
+help: you can cast an `i16` to `i32`, which will sign-extend the source value
+ |
+163 | foo::<i32>(x_i16.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:165:16
+ |
+165 | foo::<i32>(x_i8);
+ | ^^^^ expected i32, found i8
+help: you can cast an `i8` to `i32`, which will sign-extend the source value
+ |
+165 | foo::<i32>(x_i8.into());
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:167:16
+ |
+167 | foo::<i32>(x_f64);
+ | ^^^^^ expected i32, found f64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:169:16
+ |
+169 | foo::<i32>(x_f32);
+ | ^^^^^ expected i32, found f32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:172:16
+ |
+172 | foo::<u16>(x_usize);
+ | ^^^^^^^ expected u16, found usize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:174:16
+ |
+174 | foo::<u16>(x_u64);
+ | ^^^^^ expected u16, found u64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:176:16
+ |
+176 | foo::<u16>(x_u32);
+ | ^^^^^ expected u16, found u32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:179:16
+ |
+179 | foo::<u16>(x_u8);
+ | ^^^^ expected u16, found u8
+help: you can cast an `u8` to `u16`, which will zero-extend the source value
+ |
+179 | foo::<u16>(x_u8.into());
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:181:16
+ |
+181 | foo::<u16>(x_isize);
+ | ^^^^^^^ expected u16, found isize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:183:16
+ |
+183 | foo::<u16>(x_i64);
+ | ^^^^^ expected u16, found i64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:185:16
+ |
+185 | foo::<u16>(x_i32);
+ | ^^^^^ expected u16, found i32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:187:16
+ |
+187 | foo::<u16>(x_i16);
+ | ^^^^^ expected u16, found i16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:189:16
+ |
+189 | foo::<u16>(x_i8);
+ | ^^^^ expected u16, found i8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:191:16
+ |
+191 | foo::<u16>(x_f64);
+ | ^^^^^ expected u16, found f64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:193:16
+ |
+193 | foo::<u16>(x_f32);
+ | ^^^^^ expected u16, found f32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:196:16
+ |
+196 | foo::<i16>(x_usize);
+ | ^^^^^^^ expected i16, found usize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:198:16
+ |
+198 | foo::<i16>(x_u64);
+ | ^^^^^ expected i16, found u64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:200:16
+ |
+200 | foo::<i16>(x_u32);
+ | ^^^^^ expected i16, found u32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:202:16
+ |
+202 | foo::<i16>(x_u16);
+ | ^^^^^ expected i16, found u16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:204:16
+ |
+204 | foo::<i16>(x_u8);
+ | ^^^^ expected i16, found u8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:206:16
+ |
+206 | foo::<i16>(x_isize);
+ | ^^^^^^^ expected i16, found isize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:208:16
+ |
+208 | foo::<i16>(x_i64);
+ | ^^^^^ expected i16, found i64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:210:16
+ |
+210 | foo::<i16>(x_i32);
+ | ^^^^^ expected i16, found i32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:213:16
+ |
+213 | foo::<i16>(x_i8);
+ | ^^^^ expected i16, found i8
+help: you can cast an `i8` to `i16`, which will sign-extend the source value
+ |
+213 | foo::<i16>(x_i8.into());
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:215:16
+ |
+215 | foo::<i16>(x_f64);
+ | ^^^^^ expected i16, found f64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:217:16
+ |
+217 | foo::<i16>(x_f32);
+ | ^^^^^ expected i16, found f32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:220:15
+ |
+220 | foo::<u8>(x_usize);
+ | ^^^^^^^ expected u8, found usize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:222:15
+ |
+222 | foo::<u8>(x_u64);
+ | ^^^^^ expected u8, found u64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:224:15
+ |
+224 | foo::<u8>(x_u32);
+ | ^^^^^ expected u8, found u32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:226:15
+ |
+226 | foo::<u8>(x_u16);
+ | ^^^^^ expected u8, found u16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:229:15
+ |
+229 | foo::<u8>(x_isize);
+ | ^^^^^^^ expected u8, found isize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:231:15
+ |
+231 | foo::<u8>(x_i64);
+ | ^^^^^ expected u8, found i64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:233:15
+ |
+233 | foo::<u8>(x_i32);
+ | ^^^^^ expected u8, found i32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:235:15
+ |
+235 | foo::<u8>(x_i16);
+ | ^^^^^ expected u8, found i16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:237:15
+ |
+237 | foo::<u8>(x_i8);
+ | ^^^^ expected u8, found i8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:239:15
+ |
+239 | foo::<u8>(x_f64);
+ | ^^^^^ expected u8, found f64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:241:15
+ |
+241 | foo::<u8>(x_f32);
+ | ^^^^^ expected u8, found f32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:244:15
+ |
+244 | foo::<i8>(x_usize);
+ | ^^^^^^^ expected i8, found usize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:246:15
+ |
+246 | foo::<i8>(x_u64);
+ | ^^^^^ expected i8, found u64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:248:15
+ |
+248 | foo::<i8>(x_u32);
+ | ^^^^^ expected i8, found u32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:250:15
+ |
+250 | foo::<i8>(x_u16);
+ | ^^^^^ expected i8, found u16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:252:15
+ |
+252 | foo::<i8>(x_u8);
+ | ^^^^ expected i8, found u8
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:254:15
+ |
+254 | foo::<i8>(x_isize);
+ | ^^^^^^^ expected i8, found isize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:256:15
+ |
+256 | foo::<i8>(x_i64);
+ | ^^^^^ expected i8, found i64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:258:15
+ |
+258 | foo::<i8>(x_i32);
+ | ^^^^^ expected i8, found i32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:260:15
+ |
+260 | foo::<i8>(x_i16);
+ | ^^^^^ expected i8, found i16
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:263:15
+ |
+263 | foo::<i8>(x_f64);
+ | ^^^^^ expected i8, found f64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:265:15
+ |
+265 | foo::<i8>(x_f32);
+ | ^^^^^ expected i8, found f32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:268:16
+ |
+268 | foo::<f64>(x_usize);
+ | ^^^^^^^ expected f64, found usize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:270:16
+ |
+270 | foo::<f64>(x_u64);
+ | ^^^^^ expected f64, found u64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:272:16
+ |
+272 | foo::<f64>(x_u32);
+ | ^^^^^ expected f64, found u32
+help: you can cast an `u32` to `f64`, producing the floating point representation of the integer
+ |
+272 | foo::<f64>(x_u32.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:274:16
+ |
+274 | foo::<f64>(x_u16);
+ | ^^^^^ expected f64, found u16
+help: you can cast an `u16` to `f64`, producing the floating point representation of the integer
+ |
+274 | foo::<f64>(x_u16.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:276:16
+ |
+276 | foo::<f64>(x_u8);
+ | ^^^^ expected f64, found u8
+help: you can cast an `u8` to `f64`, producing the floating point representation of the integer
+ |
+276 | foo::<f64>(x_u8.into());
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:278:16
+ |
+278 | foo::<f64>(x_isize);
+ | ^^^^^^^ expected f64, found isize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:280:16
+ |
+280 | foo::<f64>(x_i64);
+ | ^^^^^ expected f64, found i64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:282:16
+ |
+282 | foo::<f64>(x_i32);
+ | ^^^^^ expected f64, found i32
+help: you can cast an `i32` to `f64`, producing the floating point representation of the integer
+ |
+282 | foo::<f64>(x_i32.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:284:16
+ |
+284 | foo::<f64>(x_i16);
+ | ^^^^^ expected f64, found i16
+help: you can cast an `i16` to `f64`, producing the floating point representation of the integer
+ |
+284 | foo::<f64>(x_i16.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:286:16
+ |
+286 | foo::<f64>(x_i8);
+ | ^^^^ expected f64, found i8
+help: you can cast an `i8` to `f64`, producing the floating point representation of the integer
+ |
+286 | foo::<f64>(x_i8.into());
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:289:16
+ |
+289 | foo::<f64>(x_f32);
+ | ^^^^^ expected f64, found f32
+help: you can cast an `f32` to `f64` in a lossless way
+ |
+289 | foo::<f64>(x_f32.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:292:16
+ |
+292 | foo::<f32>(x_usize);
+ | ^^^^^^^ expected f32, found usize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:294:16
+ |
+294 | foo::<f32>(x_u64);
+ | ^^^^^ expected f32, found u64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:296:16
+ |
+296 | foo::<f32>(x_u32);
+ | ^^^^^ expected f32, found u32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:298:16
+ |
+298 | foo::<f32>(x_u16);
+ | ^^^^^ expected f32, found u16
+help: you can cast an `u16` to `f32`, producing the floating point representation of the integer
+ |
+298 | foo::<f32>(x_u16.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:300:16
+ |
+300 | foo::<f32>(x_u8);
+ | ^^^^ expected f32, found u8
+help: you can cast an `u8` to `f32`, producing the floating point representation of the integer
+ |
+300 | foo::<f32>(x_u8.into());
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:302:16
+ |
+302 | foo::<f32>(x_isize);
+ | ^^^^^^^ expected f32, found isize
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:304:16
+ |
+304 | foo::<f32>(x_i64);
+ | ^^^^^ expected f32, found i64
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:306:16
+ |
+306 | foo::<f32>(x_i32);
+ | ^^^^^ expected f32, found i32
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:308:16
+ |
+308 | foo::<f32>(x_i16);
+ | ^^^^^ expected f32, found i16
+help: you can cast an `i16` to `f32`, producing the floating point representation of the integer
+ |
+308 | foo::<f32>(x_i16.into());
+ | ^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:310:16
+ |
+310 | foo::<f32>(x_i8);
+ | ^^^^ expected f32, found i8
+help: you can cast an `i8` to `f32`, producing the floating point representation of the integer
+ |
+310 | foo::<f32>(x_i8.into());
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-cast.rs:312:16
+ |
+312 | foo::<f32>(x_f64);
+ | ^^^^^ expected f32, found f64
+
+error: aborting due to 132 previous errors
+
clap = "2.25.0"
[dependencies.mdbook]
-version = "0.0.26"
+version = "0.0.28"
default-features = false
// Build command implementation
pub fn build(args: &ArgMatches) -> Result<()> {
let book_dir = get_book_dir(args);
- let book = MDBook::new(&book_dir).read_config()?;
+ let mut book = MDBook::new(&book_dir).read_config()?;
- let mut book = match args.value_of("dest-dir") {
- Some(dest_dir) => book.with_destination(dest_dir),
- None => book,
- };
+ // Set this to allow us to catch bugs in advance.
+ book.config.build.create_missing = false;
+
+ if let Some(dest_dir) = args.value_of("dest-dir") {
+ book.config.build.build_dir = PathBuf::from(dest_dir);
+ }
book.build()?;
-Subproject commit 6714a447d063b079de8fb2884ded2c8c3e96bc1d
+Subproject commit e0e3e22248cd14ebbe0253e9720261a0328bfc59
"src/tools/miri",
"src/librustc/mir/interpret",
"src/librustc_mir/interpret",
+ "src/target",
];
skip.iter().any(|p| path.ends_with(p))
}