echo '{"ipv6":true,"fixed-cidr-v6":"fd9a:8454:6789:13f7::/64"}' | sudo tee /etc/docker/daemon.json;
sudo service docker restart;
fi
+ - date
+ - sudo atq || true
+ - sudo grep -rE 'shutdown|poweroff|halt' /var/spool/cron || true
+ - sudo grep -E 'google-clock-skew|ntpd|startup-script' /var/log/syslog || true
install:
- case "$TRAVIS_OS_NAME" in
copyright assignment is required to contribute to the Rust project.
Some files include explicit copyright notices and/or license notices.
-For full authorship information, see AUTHORS.txt and the version control
-history.
+For full authorship information, see the version control history or
+https://thanks.rust-lang.org
Except as otherwise noted (below and/or in individual files), Rust is
licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or
Compatibility Notes
-------------------
-- [Rust will no longer consider trait objects with duplicated constraints to
- have implementations.][51276] For example the below code will now fail
- to compile.
+- [Rust will consider trait objects with duplicated constraints to be the same
+ type as without the duplicated constraint.][51276] For example the below code will
+ now fail to compile.
```rust
trait Trait {}
[`alloc::handle_alloc_error`]: https://doc.rust-lang.org/std/alloc/fn.handle_alloc_error.html
[`btree_map::Entry::or_default`]: https://doc.rust-lang.org/std/collections/btree_map/enum.Entry.html#method.or_default
[`fmt::Alignment`]: https://doc.rust-lang.org/std/fmt/enum.Alignment.html
-[`hash_map::Entry::or_default`]: https://doc.rust-lang.org/std/collections/btree_map/enum.Entry.html#method.or_default
+[`hash_map::Entry::or_default`]: https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.or_default
[`iter::repeat_with`]: https://doc.rust-lang.org/std/iter/fn.repeat_with.html
[`num::NonZeroUsize`]: https://doc.rust-lang.org/std/num/struct.NonZeroUsize.html
[`num::NonZeroU128`]: https://doc.rust-lang.org/std/num/struct.NonZeroU128.html
[`{Any + Send + Sync}::downcast_ref`]: https://doc.rust-lang.org/std/any/trait.Any.html#method.downcast_ref-2
[`{Any + Send + Sync}::is`]: https://doc.rust-lang.org/std/any/trait.Any.html#method.is-2
+Version 1.27.2 (2018-07-20)
+===========================
+
+Compatibility Notes
+-------------------
+
+- The borrow checker was fixed to avoid potential unsoundness when using
+ match ergonomics: [#52213][52213].
+
+[52213]: https://github.com/rust-lang/rust/issues/52213
+
Version 1.27.1 (2018-07-10)
===========================
Language
--------
- [Removed 'proc' from the reserved keywords list.][49699] This allows `proc` to
- be used as an identifer.
+ be used as an identifier.
- [The dyn syntax is now available.][49968] This syntax is equivalent to the
bare `Trait` syntax, and should make it clearer when being used in tandem with
`impl Trait`. Since it is equivalent to the following syntax:
Compiler
--------
-- [Added the `armv5te-unknown-linux-musl` target.][50423]
+- [Added the `armv5te-unknown-linux-musleabi` target.][50423]
Libraries
---------
--------
* Patterns with `ref mut` now correctly invoke [`DerefMut`] when
- matching against dereferencable values.
+ matching against dereferenceable values.
Libraries
---------
# the same format as above, but since these targets are experimental, they are
# not built by default and the experimental Rust compilation targets that depend
# on them will not work unless the user opts in to building them. By default the
-# `WebAssembly` target is enabled when compiling LLVM from scratch.
-#experimental-targets = "WebAssembly"
+# `WebAssembly` and `RISCV` targets are enabled when compiling LLVM from scratch.
+#experimental-targets = "WebAssembly;RISCV"
# Cap the number of parallel linker invocations when compiling LLVM.
# This can be useful when building LLVM with debug info, which significantly
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
"crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crates-io 0.18.0",
- "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libgit2-sys 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfix 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-workspace-hack 1.0.0",
+ "rustfix 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.0.212"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy-mini-macro-test 0.2.0",
"clippy_lints 0.0.212",
"compiletest_rs 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-workspace-hack 1.0.0",
"rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfix 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustfix 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.18.0"
dependencies = [
"curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "crossbeam-utils"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "crypto-hash"
version = "0.3.1"
[[package]]
name = "failure"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure_derive"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "rls"
-version = "0.129.0"
+version = "0.130.2"
dependencies = [
"cargo 0.30.0",
"cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy_lints 0.0.212",
"crossbeam-channel 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"languageserver-types 0.45.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-analysis 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-rustc 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-rustc 0.5.0 (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.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfmt-nightly 0.9.0",
+ "rustc-workspace-hack 1.0.0",
+ "rustfmt-nightly 0.99.1",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rls-rustc"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "racer 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
"rustc-ap-rustc_data_structures 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-arena"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc-ap-rustc_data_structures 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-rustc_cratesio_shim"
version = "209.0.0"
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-rustc_cratesio_shim"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-rustc_data_structures"
version = "209.0.0"
"stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-rustc_data_structures"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-rustc_errors"
version = "209.0.0"
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-rustc_errors"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-rustc_target"
version = "209.0.0"
"rustc-ap-serialize 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-rustc_target"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-serialize"
version = "209.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "rustc-ap-serialize"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "rustc-ap-syntax"
version = "209.0.0"
"scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-syntax"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-syntax_pos"
version = "209.0.0"
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-syntax_pos"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-arena 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-demangle"
version = "0.1.8"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "rustc-workspace-hack"
+version = "1.0.0"
+dependencies = [
+ "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc_allocator"
version = "0.0.0"
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_incremental 0.0.0",
+ "rustc_metadata_utils 0.0.0",
"rustc_mir 0.0.0",
"rustc_target 0.0.0",
"syntax 0.0.0",
name = "rustc_llvm"
version = "0.0.0"
dependencies = [
- "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"build_helper 0.1.0",
"cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc_cratesio_shim 0.0.0",
]
[[package]]
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
+ "rustc_metadata_utils 0.0.0",
"rustc_target 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
+[[package]]
+name = "rustc_metadata_utils"
+version = "0.0.0"
+dependencies = [
+ "rustc 0.0.0",
+ "syntax 0.0.0",
+ "syntax_pos 0.0.0",
+]
+
[[package]]
name = "rustc_mir"
version = "0.0.0"
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
+ "rustc_metadata 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustfix"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rustfmt-nightly"
-version = "0.9.0"
+version = "0.99.1"
dependencies = [
"assert_cli 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"isatty 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_target 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_lsan 0.0.0",
"rustc_msan 0.0.0",
"rustc_tsan 0.0.0",
- "std_unicode 0.0.0",
"unwind 0.0.0",
]
-[[package]]
-name = "std_unicode"
-version = "0.0.0"
-dependencies = [
- "compiler_builtins 0.0.0",
- "core 0.0.0",
-]
-
[[package]]
name = "string_cache"
version = "0.7.3"
[[package]]
name = "synstructure"
-version = "0.6.1"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"checksum crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "285987a59c4d91388e749850e3cb7b3a92299668528caaacd08005b8f238c0ea"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
"checksum crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ea52fab26a99d96cdff39d0ca75c9716125937f5dba2ab83923aaaf5928f684a"
+"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
"checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4"
"checksum curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "893713db705eab9847e050268507b0e2a2aad64e90a831874bd4e8e0d67f9523"
"checksum curl-sys 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "de9cf174efdf90b5887c4e2e900769373c89c5e18152e8f3ed75b501a6f1c0fb"
"checksum environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee"
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02"
-"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82"
-"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b"
+"checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9"
+"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
"checksum filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da4b9849e77b13195302c174324b5ba73eec9b236b24c221a61000daefb95c5f"
"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
"checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909"
"checksum rls-analysis 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96f84d303dcbe1c1bdd41b10867d3399c38fbdac32c4e3645cdb6dbd7f82db1d"
"checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2"
"checksum rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd20763e1c60ae8945384c8a8fa4ac44f8afa7b0a817511f5e8927e5d24f988"
-"checksum rls-rustc 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c8c09117ae2887baaa4b17fe1cb572f9b22e4d2c6a5cda04093d8b366b0be99"
+"checksum rls-rustc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9dba7390427aefa953608429701e3665192ca810ba8ae09301e001b7c7bed0"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rls-vfs 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ecbc8541b4c341d6271eae10f869dd9d36db871afe184f5b6f9bffbd6ed0373f"
"checksum rustc-ap-arena 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b098827864368459cbc7a79fbc54eafb92df7e00a46c0cda352b5a21583ee436"
+"checksum rustc-ap-arena 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eec75ed880706dd9a05bc770c327ed142fa7d4b648d9757fbc71d821d68448a5"
"checksum rustc-ap-rustc_cratesio_shim 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4d923dea14fb085bca743fb982f6a3bc11c0d5d30b822bcf6fa16e9464a56c"
+"checksum rustc-ap-rustc_cratesio_shim 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f5d54615bedbae65a976e0835edf0de90dd962ec818c0149fe181d5cd81da9e"
"checksum rustc-ap-rustc_data_structures 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c6a5c9edc6b4ae035cdc03af7d8662d39fad7879c5501d103e7087dfaebc80"
+"checksum rustc-ap-rustc_data_structures 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7c51cc6e79eab25c7ea84a7e104e81e6f44cca32709df54c2cdb4e7059d7843"
"checksum rustc-ap-rustc_errors 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a1e9bdc597abd95cebce0c14c1da58943a9e5b8255530a0fec30659d144eb0b"
+"checksum rustc-ap-rustc_errors 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff050095b7afb254506591ee7d3a5d0fb9c03c16f8c2741b588178085e563d49"
"checksum rustc-ap-rustc_target 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "142ddef3dc12dda2bcd3412f0d96d3745413a8fbc2f224f0cc97afa04c071d89"
+"checksum rustc-ap-rustc_target 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53c7a8c21c3b05f24998fa6ab9ded6269810a2f3ae12ff301c432c1e9fa8e111"
"checksum rustc-ap-serialize 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b08f8f175b038a82caa7e51fc52b72ff96cfe8c1429755da30380dbd4199c7f"
+"checksum rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4713c2c0c26a45ead8fb16fee88e16fecf999588ae6920847cbaeb19565b7f"
"checksum rustc-ap-syntax 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c802e0e1fbc64eddc21e0798527eb1f5fdbd5781d119bd2c44b6130afdc81cc"
+"checksum rustc-ap-syntax 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "768e2698f912913be2ccd355b2dea62c978efc356f75db1400605f3642905d53"
"checksum rustc-ap-syntax_pos 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "008d47cc54ed12a2784217b9e6630a7fa1c8dc3591a283f65ad4b7fa307d49d5"
+"checksum rustc-ap-syntax_pos 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a280dc8919aa7f684832ba3eeab2f6c96dbe2e2e4f6a922f7f0bdb3a9dd9e641"
"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649"
"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
"checksum rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c6d5a683c6ba4ed37959097e88d71c9e8e26659a3cb5be8b389078e7ad45306"
"checksum rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40f06724db71e18d68b3b946fdf890ca8c921d9edccc1404fdfdb537b0d12649"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a54aa04a10c68c1c4eacb4337fd883b435997ede17a9385784b990777686b09a"
-"checksum rustfix 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86f77b09d42bae4adfbcd105a8914e2d9fb46b63612c1a765b824a2b4a4bb814"
+"checksum rustfix 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "756567f00f7d89c9f89a5c401b8b1caaa122e27240b9eaadd0bb52ee0b680b1b"
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
"checksum schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "dc1fabf2a7b6483a141426e1afd09ad543520a77ac49bd03c286e7696ccfd77f"
"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28"
"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b"
"checksum syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2beff8ebc3658f07512a413866875adddd20f4fd47b2a4e6c9da65cd281baaea"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
-"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
+"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
"checksum tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)" = "e8f41ca4a5689f06998f0247fcb60da6c760f1950cc9df2a10d71575ad0b062a"
"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b"
"checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508"
[patch."https://github.com/rust-lang/cargo"]
cargo = { path = "tools/cargo" }
-[patch."https://github.com/rust-lang-nursery/rustfmt"]
+[patch.crates-io]
# Similar to Cargo above we want the RLS to use a vendored version of `rustfmt`
# that we're shipping as well (to ensure that the rustfmt in RLS and the
# `rustfmt` executable are the same exact version).
rustfmt-nightly = { path = "tools/rustfmt" }
+# See comments in `tools/rustc-workspace-hack/README.md` for what's going on
+# here
+rustc-workspace-hack = { path = 'tools/rustc-workspace-hack' }
+
[patch."https://github.com/rust-lang-nursery/rust-clippy"]
clippy_lints = { path = "tools/clippy/clippy_lints" }
option = "-#"
else:
option = "-s"
- run(["curl", option, "--retry", "3", "-Sf", "-o", path, url],
+ run(["curl", option,
+ "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds
+ "--connect-timeout", "30", # timeout if cannot connect within 30 seconds
+ "--retry", "3", "-Sf", "-o", path, url],
verbose=verbose,
exception=exception)
// compiler, but for tools we just use the precompiled libraries that
// we've downloaded
let use_snapshot = mode == Mode::ToolBootstrap;
- assert!(!use_snapshot || stage == 0);
+ assert!(!use_snapshot || stage == 0 || self.local_rebuild);
let maybe_sysroot = self.sysroot(compiler);
let sysroot = if use_snapshot {
use config::Config;
// The version number
-pub const CFG_RELEASE_NUM: &str = "1.29.0";
+pub const CFG_RELEASE_NUM: &str = "1.30.0";
pub struct GitInfo {
inner: Option<Info>,
cargo.arg("--features").arg("c mem")
.args(&["-p", "alloc"])
.args(&["-p", "compiler_builtins"])
- .args(&["-p", "std_unicode"])
.arg("--manifest-path")
.arg(builder.src.join("src/rustc/compiler_builtins_shim/Cargo.toml"));
} else {
set(&mut config.llvm_link_shared, llvm.link_shared);
config.llvm_targets = llvm.targets.clone();
config.llvm_experimental_targets = llvm.experimental_targets.clone()
- .unwrap_or("WebAssembly".to_string());
+ .unwrap_or("WebAssembly;RISCV".to_string());
config.llvm_link_jobs = llvm.link_jobs;
config.llvm_clang_cl = llvm.clang_cl.clone();
}
"src/librustc_msan",
"src/librustc_tsan",
"src/libstd",
- "src/libstd_unicode",
"src/libunwind",
"src/rustc/compiler_builtins_shim",
"src/rustc/libc_shim",
// Keep a whitelist so we do not build internal stdlib crates, these will be
// build by the rustc step later if enabled.
cargo.arg("--no-deps");
- for krate in &["alloc", "core", "std", "std_unicode"] {
+ for krate in &["alloc", "core", "std"] {
cargo.arg("-p").arg(krate);
// Create all crate output directories first to make sure rustdoc uses
// relative links.
opts.optmulti("", "exclude", "build paths to exclude", "PATH");
opts.optopt("", "on-fail", "command to run on failure", "CMD");
opts.optflag("", "dry-run", "dry run; don't build anything");
- opts.optopt("", "stage", "stage to build", "N");
+ opts.optopt("", "stage",
+ "stage to build (indicates compiler to use/test, e.g. stage 0 uses the \
+ bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)",
+ "N");
opts.optmulti("", "keep-stage", "stage(s) to keep without recompiling", "N");
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
./x.py build --stage 1 src/libtest
- This will first build everything once (like --stage 0 without further
+ This will first build everything once (like `--stage 0` without further
arguments would), and then use the compiler built in stage 0 to build
src/libtest and its dependencies.
Once this is done, build/$ARCH/stage1 contains a usable compiler.",
./x.py test src/test/run-pass
./x.py test src/libstd --test-args hash_map
- ./x.py test src/libstd --stage 0
+ ./x.py test src/libstd --stage 0 --no-doc
./x.py test src/test/ui --bless
./x.py test src/test/ui --compare-mode nll
+ Note that `test src/test/* --stage N` does NOT depend on `build src/rustc --stage N`;
+ just like `build src/libstd --stage N` it tests the compiler produced by the previous
+ stage.
+
If no arguments are passed then the complete artifacts for that stage are
compiled and tested.
cargo.env("RLS_TEST_WORKSPACE_DIR", test_workspace_path);
builder.add_rustc_lib_path(compiler, &mut cargo);
+ cargo.arg("--")
+ .args(builder.config.cmd.test_args());
if try_run(builder, &mut cargo) {
builder.save_toolstate("rls", ToolState::TestPass);
prev.0, &prev_features - &cur_features, prev.1);
}
println!("");
+ println!("to fix this you will probably want to edit the local \
+ src/tools/rustc-workspace-hack/Cargo.toml crate, as \
+ that will update the dependency graph to ensure that \
+ these crates all share the same feature set");
panic!("tools should not compile multiple copies of the same crate");
}
ENV TARGETS=$TARGETS,thumbv7m-none-eabi
ENV TARGETS=$TARGETS,thumbv7em-none-eabi
ENV TARGETS=$TARGETS,thumbv7em-none-eabihf
+ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf
ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \
OS="$3"
COMMIT="$(git rev-parse HEAD)"
CHANGED_FILES="$(git diff --name-status HEAD HEAD^)"
-SIX_WEEK_CYCLE="$(( ($(date +%s) / 604800 - 3) % 6 ))"
-# ^ 1970 Jan 1st is a Thursday, and our release dates are also on Thursdays,
-# thus we could divide by 604800 (7 days in seconds) directly.
+SIX_WEEK_CYCLE="$(( ($(date +%s) / 86400 - 20) % 42 ))"
+# ^ Number of days after the last promotion of beta.
+# Its value is 41 on the Tuesday where "Promote master to beta (T-2)" happens.
+# The Wednesday after this has value 0.
+# We track this value to prevent regressing tools in the last week of the 6-week cycle.
touch "$TOOLSTATE_FILE"
if python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" changed; then
echo 'Toolstate is not changed. Not updating.'
else
- if [ $SIX_WEEK_CYCLE -eq 5 ]; then
+ if [ $SIX_WEEK_CYCLE -ge 35 ]; then
python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" regressed
fi
sed -i "1 a\\
for issues.
.SH "AUTHOR"
-See \fIAUTHORS.txt\fR in the Rust source distribution.
+See the version control history or <\fBhttps://thanks.rust\-lang.org\fR>
.SH "COPYRIGHT"
This work is dual\[hy]licensed under Apache\ 2.0 and MIT terms.
TYPE_KIND_FIXED_SIZE_VEC = 16
TYPE_KIND_REGULAR_UNION = 17
TYPE_KIND_OS_STRING = 18
+TYPE_KIND_STD_VECDEQUE = 19
ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$"
ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR"
STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_BUF,
STD_VEC_FIELD_NAME_LENGTH]
+# std::collections::VecDeque<> related constants
+STD_VECDEQUE_FIELD_NAME_TAIL = "tail"
+STD_VECDEQUE_FIELD_NAME_HEAD = "head"
+STD_VECDEQUE_FIELD_NAME_BUF = "buf"
+STD_VECDEQUE_FIELD_NAMES = [STD_VECDEQUE_FIELD_NAME_TAIL,
+ STD_VECDEQUE_FIELD_NAME_HEAD,
+ STD_VECDEQUE_FIELD_NAME_BUF]
+
# std::String related constants
STD_STRING_FIELD_NAMES = ["vec"]
self.__conforms_to_field_layout(STD_VEC_FIELD_NAMES)):
return TYPE_KIND_STD_VEC
+ # STD COLLECTION VECDEQUE
+ if (unqualified_type_name.startswith("VecDeque<") and
+ self.__conforms_to_field_layout(STD_VECDEQUE_FIELD_NAMES)):
+ return TYPE_KIND_STD_VECDEQUE
+
# STD STRING
if (unqualified_type_name.startswith("String") and
self.__conforms_to_field_layout(STD_STRING_FIELD_NAMES)):
assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
return (length, data_ptr, capacity)
+
+def extract_tail_head_ptr_and_cap_from_std_vecdeque(vec_val):
+ assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VECDEQUE
+ tail_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_TAIL)
+ head_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_HEAD)
+ buf_field_index = STD_VECDEQUE_FIELD_NAMES.index(STD_VECDEQUE_FIELD_NAME_BUF)
+
+ tail = vec_val.get_child_at_index(tail_field_index).as_integer()
+ head = vec_val.get_child_at_index(head_field_index).as_integer()
+ buf = vec_val.get_child_at_index(buf_field_index)
+
+ vec_ptr_val = buf.get_child_at_index(0)
+ capacity = buf.get_child_at_index(1).as_integer()
+ unique_ptr_val = vec_ptr_val.get_child_at_index(0)
+ data_ptr = unique_ptr_val.get_child_at_index(0)
+ assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
+ return (tail, head, data_ptr, capacity)
+
+
def extract_length_and_ptr_from_slice(slice_val):
assert (slice_val.type.get_type_kind() == TYPE_KIND_SLICE or
slice_val.type.get_type_kind() == TYPE_KIND_STR_SLICE)
if type_kind == rustpp.TYPE_KIND_STD_VEC:
return RustStdVecPrinter(val)
+ if type_kind == rustpp.TYPE_KIND_STD_VECDEQUE:
+ return RustStdVecDequePrinter(val)
+
if type_kind == rustpp.TYPE_KIND_STD_STRING:
return RustStdStringPrinter(val)
yield (str(index), (gdb_ptr + index).dereference())
+class RustStdVecDequePrinter(object):
+ def __init__(self, val):
+ self.__val = val
+
+ @staticmethod
+ def display_hint():
+ return "array"
+
+ def to_string(self):
+ (tail, head, data_ptr, cap) = \
+ rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val)
+ return (self.__val.type.get_unqualified_type_name() +
+ ("(len: %i, cap: %i)" % (head - tail, cap)))
+
+ def children(self):
+ (tail, head, data_ptr, cap) = \
+ rustpp.extract_tail_head_ptr_and_cap_from_std_vecdeque(self.__val)
+ gdb_ptr = data_ptr.get_wrapped_value()
+ for index in xrange(tail, head):
+ yield (str(index), (gdb_ptr + index).dereference())
+
+
class RustStdStringPrinter(object):
def __init__(self, val):
self.__val = val
#[cfg(test)]
mod boxed_test;
pub mod collections;
-#[cfg(any(
- all(stage0, target_has_atomic = "ptr"),
- all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
-))]
+#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
pub mod sync;
pub mod rc;
pub mod raw_vec;
pub use core::task::*;
-#[cfg(any(
- all(stage0, target_has_atomic = "ptr"),
- all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
-))]
+#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
pub use self::if_arc::*;
-#[cfg(any(
- all(stage0, target_has_atomic = "ptr"),
- all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
-))]
+#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
mod if_arc {
use super::*;
use core::marker::PhantomData;
}
}
- #[cfg(any(
- all(stage0, target_has_atomic = "ptr"),
- all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
- ))]
+ #[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
struct ArcWrapped<T>(PhantomData<T>);
unsafe impl<T: Wake + 'static> UnsafeWake for ArcWrapped<T> {
/// [`drain`]: #method.drain
#[stable(feature = "rust1", since = "1.0.0")]
pub fn truncate(&mut self, len: usize) {
+ let current_len = self.len;
unsafe {
+ let mut ptr = self.as_mut_ptr().offset(self.len as isize);
+ // Set the final length at the end, keeping in mind that
+ // dropping an element might panic. Works around a missed
+ // optimization, as seen in the following issue:
+ // https://github.com/rust-lang/rust/issues/51802
+ let mut local_len = SetLenOnDrop::new(&mut self.len);
+
// drop any extra elements
- while len < self.len {
- // decrement len before the drop_in_place(), so a panic on Drop
- // doesn't re-drop the just-failed value.
- self.len -= 1;
- let len = self.len;
- ptr::drop_in_place(self.get_unchecked_mut(len));
+ for _ in len..current_len {
+ local_len.decrement_len(1);
+ ptr = ptr.offset(-1);
+ ptr::drop_in_place(ptr);
}
}
}
fn increment_len(&mut self, increment: usize) {
self.local_len += increment;
}
+
+ #[inline]
+ fn decrement_len(&mut self, decrement: usize) {
+ self.local_len -= decrement;
+ }
}
impl<'a> Drop for SetLenOnDrop<'a> {
cmd.arg("--with-jemalloc-prefix=je_");
}
- // FIXME: building with jemalloc assertions is currently broken.
- // See <https://github.com/rust-lang/rust/issues/44152>.
- //if cfg!(feature = "debug") {
- // cmd.arg("--enable-debug");
- //}
+ if cfg!(feature = "debug") {
+ // Enable jemalloc assertions.
+ cmd.arg("--enable-debug");
+ }
cmd.arg(format!("--host={}", build_helper::gnu_target(&target)));
cmd.arg(format!("--build={}", build_helper::gnu_target(&host)));
}
}
- #[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))]
+ #[cfg(any(target_os = "android",
+ target_os = "hermit",
+ target_os = "redox",
+ target_os = "solaris"))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
// On android we currently target API level 9 which unfortunately
libc::memalign(layout.align(), layout.size()) as *mut u8
}
- #[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))]
+ #[cfg(not(any(target_os = "android",
+ target_os = "hermit",
+ target_os = "redox",
+ target_os = "solaris")))]
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
let mut out = ptr::null_mut();
-Subproject commit 52a6a4d7087d14a35d44a11c39c77fa79d71378d
+Subproject commit d549d85b1735dc5066b2973f8549557a813bb9c8
use ptr::{self, NonNull};
use num::NonZeroUsize;
-#[unstable(feature = "alloc_internals", issue = "0")]
-#[cfg(stage0)]
-pub type Opaque = u8;
-
/// Represents the combination of a starting address and
/// a total capacity of the returned block.
#[unstable(feature = "allocator_api", issue = "32838")]
/// use specific allocators with looser requirements.)
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[cfg_attr(not(stage0), lang = "alloc_layout")]
+#[lang = "alloc_layout"]
pub struct Layout {
// size of the requested block of memory, measured in bytes.
size_: usize,
let RefMut { value, borrow } = orig;
RefMut {
value: f(value),
- borrow: borrow,
+ borrow,
}
}
match borrow.get() {
UNUSED => {
borrow.set(UNUSED - 1);
- Some(BorrowRefMut { borrow: borrow })
+ Some(BorrowRefMut { borrow })
},
_ => None,
}
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub const fn new(value: T) -> UnsafeCell<T> {
- UnsafeCell { value: value }
+ UnsafeCell { value }
}
/// Unwraps the value.
//! UTF-8 and UTF-16 decoding iterators
use fmt;
-use iter::FusedIterator;
use super::from_u32_unchecked;
-/// An iterator over an iterator of bytes of the characters the bytes represent
-/// as UTF-8
-#[unstable(feature = "decode_utf8", issue = "33906")]
-#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
-#[derive(Clone, Debug)]
-#[allow(deprecated)]
-pub struct DecodeUtf8<I: Iterator<Item = u8>>(::iter::Peekable<I>);
-
-/// Decodes an `Iterator` of bytes as UTF-8.
-#[unstable(feature = "decode_utf8", issue = "33906")]
-#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
-#[allow(deprecated)]
-#[inline]
-pub fn decode_utf8<I: IntoIterator<Item = u8>>(i: I) -> DecodeUtf8<I::IntoIter> {
- DecodeUtf8(i.into_iter().peekable())
-}
-
-/// `<DecodeUtf8 as Iterator>::next` returns this for an invalid input sequence.
-#[unstable(feature = "decode_utf8", issue = "33906")]
-#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
-#[derive(PartialEq, Eq, Debug)]
-#[allow(deprecated)]
-pub struct InvalidSequence(());
-
-#[unstable(feature = "decode_utf8", issue = "33906")]
-#[allow(deprecated)]
-impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> {
- type Item = Result<char, InvalidSequence>;
- #[inline]
-
- fn next(&mut self) -> Option<Result<char, InvalidSequence>> {
- self.0.next().map(|first_byte| {
- // Emit InvalidSequence according to
- // Unicode §5.22 Best Practice for U+FFFD Substitution
- // http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630
-
- // Roughly: consume at least one byte,
- // then validate one byte at a time and stop before the first unexpected byte
- // (which might be the valid start of the next byte sequence).
-
- let mut code_point;
- macro_rules! first_byte {
- ($mask: expr) => {
- code_point = u32::from(first_byte & $mask)
- }
- }
- macro_rules! continuation_byte {
- () => { continuation_byte!(0x80..=0xBF) };
- ($range: pat) => {
- match self.0.peek() {
- Some(&byte @ $range) => {
- code_point = (code_point << 6) | u32::from(byte & 0b0011_1111);
- self.0.next();
- }
- _ => return Err(InvalidSequence(()))
- }
- }
- }
-
- match first_byte {
- 0x00..=0x7F => {
- first_byte!(0b1111_1111);
- }
- 0xC2..=0xDF => {
- first_byte!(0b0001_1111);
- continuation_byte!();
- }
- 0xE0 => {
- first_byte!(0b0000_1111);
- continuation_byte!(0xA0..=0xBF); // 0x80..=0x9F here are overlong
- continuation_byte!();
- }
- 0xE1..=0xEC | 0xEE..=0xEF => {
- first_byte!(0b0000_1111);
- continuation_byte!();
- continuation_byte!();
- }
- 0xED => {
- first_byte!(0b0000_1111);
- continuation_byte!(0x80..=0x9F); // 0xA0..0xBF here are surrogates
- continuation_byte!();
- }
- 0xF0 => {
- first_byte!(0b0000_0111);
- continuation_byte!(0x90..=0xBF); // 0x80..0x8F here are overlong
- continuation_byte!();
- continuation_byte!();
- }
- 0xF1..=0xF3 => {
- first_byte!(0b0000_0111);
- continuation_byte!();
- continuation_byte!();
- continuation_byte!();
- }
- 0xF4 => {
- first_byte!(0b0000_0111);
- continuation_byte!(0x80..=0x8F); // 0x90..0xBF here are beyond char::MAX
- continuation_byte!();
- continuation_byte!();
- }
- _ => return Err(InvalidSequence(())) // Illegal first byte, overlong, or beyond MAX
- }
- unsafe {
- Ok(from_u32_unchecked(code_point))
- }
- })
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (lower, upper) = self.0.size_hint();
-
- // A code point is at most 4 bytes long.
- let min_code_points = lower / 4;
-
- (min_code_points, upper)
- }
-}
-
-#[unstable(feature = "decode_utf8", issue = "33906")]
-#[allow(deprecated)]
-impl<I: FusedIterator<Item = u8>> FusedIterator for DecodeUtf8<I> {}
-
/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s.
#[stable(feature = "decode_utf16", since = "1.9.0")]
#[derive(Clone, Debug)]
/// assert!('٣'.is_alphanumeric());
/// assert!('7'.is_alphanumeric());
/// assert!('৬'.is_alphanumeric());
+ /// assert!('¾'.is_alphanumeric());
+ /// assert!('①'.is_alphanumeric());
/// assert!('K'.is_alphanumeric());
/// assert!('و'.is_alphanumeric());
/// assert!('藏'.is_alphanumeric());
- /// assert!(!'¾'.is_alphanumeric());
- /// assert!(!'①'.is_alphanumeric());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
/// assert!('٣'.is_numeric());
/// assert!('7'.is_numeric());
/// assert!('৬'.is_numeric());
+ /// assert!('¾'.is_numeric());
+ /// assert!('①'.is_numeric());
/// assert!(!'K'.is_numeric());
/// assert!(!'و'.is_numeric());
/// assert!(!'藏'.is_numeric());
- /// assert!(!'¾'.is_numeric());
- /// assert!(!'①'.is_numeric());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub use unicode::tables::UNICODE_VERSION;
#[unstable(feature = "unicode_version", issue = "49726")]
pub use unicode::version::UnicodeVersion;
-#[unstable(feature = "decode_utf8", issue = "33906")]
-#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
-#[allow(deprecated)]
-pub use self::decode::{decode_utf8, DecodeUtf8, InvalidSequence};
use fmt::{self, Write};
use iter::FusedIterator;
_marker: PhantomData<&'a ()>,
}
+impl<'a, T> Unpin for LocalFutureObj<'a, T> {}
+
impl<'a, T> LocalFutureObj<'a, T> {
/// Create a `LocalFutureObj` from a custom trait object representation.
#[inline]
/// information #44874)
pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>);
+impl<'a, T> Unpin for FutureObj<'a, T> {}
unsafe impl<'a, T> Send for FutureObj<'a, T> {}
impl<'a, T> FutureObj<'a, T> {
/// Perform a volatile load from the `src` pointer
/// The pointer is not required to be aligned.
- #[cfg(not(stage0))]
pub fn unaligned_volatile_load<T>(src: *const T) -> T;
/// Perform a volatile store to the `dst` pointer.
/// The pointer is not required to be aligned.
- #[cfg(not(stage0))]
pub fn unaligned_volatile_store<T>(dst: *mut T, val: T);
/// Returns the square root of an `f32`
fn map<B, F>(self, f: F) -> Map<Self, F> where
Self: Sized, F: FnMut(Self::Item) -> B,
{
- Map{iter: self, f: f}
+ Map { iter: self, f }
}
/// Calls a closure on each element of an iterator.
fn filter<P>(self, predicate: P) -> Filter<Self, P> where
Self: Sized, P: FnMut(&Self::Item) -> bool,
{
- Filter{iter: self, predicate: predicate}
+ Filter {iter: self, predicate }
}
/// Creates an iterator that both filters and maps.
fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F> where
Self: Sized, F: FnMut(Self::Item) -> Option<B>,
{
- FilterMap { iter: self, f: f }
+ FilterMap { iter: self, f }
}
/// Creates an iterator which gives the current iteration count as well as
fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P> where
Self: Sized, P: FnMut(&Self::Item) -> bool,
{
- SkipWhile{iter: self, flag: false, predicate: predicate}
+ SkipWhile { iter: self, flag: false, predicate }
}
/// Creates an iterator that yields elements based on a predicate.
fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P> where
Self: Sized, P: FnMut(&Self::Item) -> bool,
{
- TakeWhile{iter: self, flag: false, predicate: predicate}
+ TakeWhile { iter: self, flag: false, predicate }
}
/// Creates an iterator that skips the first `n` elements.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn skip(self, n: usize) -> Skip<Self> where Self: Sized {
- Skip{iter: self, n: n}
+ Skip { iter: self, n }
}
/// Creates an iterator that yields its first `n` elements.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn take(self, n: usize) -> Take<Self> where Self: Sized, {
- Take{iter: self, n: n}
+ Take { iter: self, n }
}
/// An iterator adaptor similar to [`fold`] that holds internal state and
fn scan<St, B, F>(self, initial_state: St, f: F) -> Scan<Self, St, F>
where Self: Sized, F: FnMut(&mut St, Self::Item) -> Option<B>,
{
- Scan{iter: self, f: f, state: initial_state}
+ Scan { iter: self, f, state: initial_state }
}
/// Creates an iterator that works like map, but flattens nested structure.
fn inspect<F>(self, f: F) -> Inspect<Self, F> where
Self: Sized, F: FnMut(&Self::Item),
{
- Inspect{iter: self, f: f}
+ Inspect { iter: self, f }
}
/// Borrows an iterator, rather than consuming it.
+++ /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.
-
-/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
-///
-/// This wrapper is 0-cost.
-///
-/// # Examples
-///
-/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
-/// the type:
-///
-/// ```rust
-/// use std::mem::ManuallyDrop;
-/// struct Peach;
-/// struct Banana;
-/// struct Melon;
-/// struct FruitBox {
-/// // Immediately clear there’s something non-trivial going on with these fields.
-/// peach: ManuallyDrop<Peach>,
-/// melon: Melon, // Field that’s independent of the other two.
-/// banana: ManuallyDrop<Banana>,
-/// }
-///
-/// impl Drop for FruitBox {
-/// fn drop(&mut self) {
-/// unsafe {
-/// // Explicit ordering in which field destructors are run specified in the intuitive
-/// // location – the destructor of the structure containing the fields.
-/// // Moreover, one can now reorder fields within the struct however much they want.
-/// ManuallyDrop::drop(&mut self.peach);
-/// ManuallyDrop::drop(&mut self.banana);
-/// }
-/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
-/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
-/// }
-/// }
-/// ```
-#[stable(feature = "manually_drop", since = "1.20.0")]
-#[allow(unions_with_drop_fields)]
-#[derive(Copy)]
-pub union ManuallyDrop<T>{ value: T }
-
-impl<T> ManuallyDrop<T> {
- /// Wrap a value to be manually dropped.
- ///
- /// # Examples
- ///
- /// ```rust
- /// use std::mem::ManuallyDrop;
- /// ManuallyDrop::new(Box::new(()));
- /// ```
- #[stable(feature = "manually_drop", since = "1.20.0")]
- #[rustc_const_unstable(feature = "const_manually_drop_new")]
- #[inline]
- pub const fn new(value: T) -> ManuallyDrop<T> {
- ManuallyDrop { value: value }
- }
-
- /// Extract the value from the ManuallyDrop container.
- ///
- /// # Examples
- ///
- /// ```rust
- /// use std::mem::ManuallyDrop;
- /// let x = ManuallyDrop::new(Box::new(()));
- /// let _: Box<()> = ManuallyDrop::into_inner(x);
- /// ```
- #[stable(feature = "manually_drop", since = "1.20.0")]
- #[inline]
- pub fn into_inner(slot: ManuallyDrop<T>) -> T {
- unsafe {
- slot.value
- }
- }
-
- /// Manually drops the contained value.
- ///
- /// # Safety
- ///
- /// This function runs the destructor of the contained value and thus the wrapped value
- /// now represents uninitialized data. It is up to the user of this method to ensure the
- /// uninitialized data is not actually used.
- #[stable(feature = "manually_drop", since = "1.20.0")]
- #[inline]
- pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
- ptr::drop_in_place(&mut slot.value)
- }
-}
-
-#[stable(feature = "manually_drop", since = "1.20.0")]
-impl<T> Deref for ManuallyDrop<T> {
- type Target = T;
- #[inline]
- fn deref(&self) -> &Self::Target {
- unsafe {
- &self.value
- }
- }
-}
-
-#[stable(feature = "manually_drop", since = "1.20.0")]
-impl<T> DerefMut for ManuallyDrop<T> {
- #[inline]
- fn deref_mut(&mut self) -> &mut Self::Target {
- unsafe {
- &mut self.value
- }
- }
-}
-
-#[stable(feature = "manually_drop", since = "1.20.0")]
-impl<T: ::fmt::Debug> ::fmt::Debug for ManuallyDrop<T> {
- fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result {
- unsafe {
- fmt.debug_tuple("ManuallyDrop").field(&self.value).finish()
- }
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: Clone> Clone for ManuallyDrop<T> {
- fn clone(&self) -> Self {
- ManuallyDrop::new(self.deref().clone())
- }
-
- fn clone_from(&mut self, source: &Self) {
- self.deref_mut().clone_from(source);
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: Default> Default for ManuallyDrop<T> {
- fn default() -> Self {
- ManuallyDrop::new(Default::default())
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: PartialEq> PartialEq for ManuallyDrop<T> {
- fn eq(&self, other: &Self) -> bool {
- self.deref().eq(other)
- }
-
- fn ne(&self, other: &Self) -> bool {
- self.deref().ne(other)
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: Eq> Eq for ManuallyDrop<T> {}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: PartialOrd> PartialOrd for ManuallyDrop<T> {
- fn partial_cmp(&self, other: &Self) -> Option<::cmp::Ordering> {
- self.deref().partial_cmp(other)
- }
-
- fn lt(&self, other: &Self) -> bool {
- self.deref().lt(other)
- }
-
- fn le(&self, other: &Self) -> bool {
- self.deref().le(other)
- }
-
- fn gt(&self, other: &Self) -> bool {
- self.deref().gt(other)
- }
-
- fn ge(&self, other: &Self) -> bool {
- self.deref().ge(other)
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: Ord> Ord for ManuallyDrop<T> {
- fn cmp(&self, other: &Self) -> ::cmp::Ordering {
- self.deref().cmp(other)
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: ::hash::Hash> ::hash::Hash for ManuallyDrop<T> {
- fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
- self.deref().hash(state);
- }
-}
/// }
/// }
/// ```
-#[cfg(not(stage0))]
#[stable(feature = "manually_drop", since = "1.20.0")]
#[lang = "manually_drop"]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
value: T,
}
-#[cfg(stage0)]
-include!("manually_drop_stage0.rs");
-
-#[cfg(not(stage0))]
impl<T> ManuallyDrop<T> {
/// Wrap a value to be manually dropped.
///
}
}
-#[cfg(not(stage0))]
#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T> Deref for ManuallyDrop<T> {
type Target = T;
}
}
-#[cfg(not(stage0))]
#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T> DerefMut for ManuallyDrop<T> {
#[inline]
impl<'a> Decimal<'a> {
pub fn new(integral: &'a [u8], fractional: &'a [u8], exp: i64) -> Decimal<'a> {
- Decimal { integral: integral, fractional: fractional, exp: exp }
+ Decimal { integral, fractional, exp }
}
}
impl Unpacked {
pub fn new(sig: u64, k: i16) -> Self {
- Unpacked { sig: sig, k: k }
+ Unpacked { sig, k }
}
}
// We cut off all bits prior to the index `start`, i.e., we effectively right-shift by
// an amount of `start`, so this is also the exponent we need.
let e = start as i16;
- let rounded_down = Fp { f: leading, e: e }.normalize();
+ let rounded_down = Fp { f: leading, e }.normalize();
// Round (half-to-even) depending on the truncated bits.
match num::compare_with_half_ulp(f, start) {
Less => rounded_down,
Equal if leading % 2 == 0 => rounded_down,
Equal | Greater => match leading.checked_add(1) {
- Some(f) => Fp { f: f, e: e }.normalize(),
+ Some(f) => Fp { f, e }.normalize(),
None => Fp { f: 1 << 63, e: e + 1 },
}
}
let tmp = (bd >> 32) + (ad & MASK) + (bc & MASK) + (1 << 31) /* round */;
let f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
let e = self.e + other.e + 64;
- Fp { f: f, e: e }
+ Fp { f, e }
}
/// Normalizes itself so that the resulting mantissa is at least `2^63`.
e -= 1;
}
debug_assert!(f >= (1 >> 63));
- Fp { f: f, e: e }
+ Fp { f, e }
}
/// Normalizes itself to have the shared exponent.
// neighbors: (mant - 2, exp) -- (mant, exp) -- (mant + 2, exp)
// Float::integer_decode always preserves the exponent,
// so the mantissa is scaled for subnormals.
- FullDecoded::Finite(Decoded { mant: mant, minus: 1, plus: 1,
- exp: exp, inclusive: even })
+ FullDecoded::Finite(Decoded { mant, minus: 1, plus: 1,
+ exp, inclusive: even })
}
FpCategory::Normal => {
let minnorm = <T as DecodableFloat>::min_pos_norm_value().integer_decode();
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(b"NaN");
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(b"inf");
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
if frac_digits > 0 { // [0.][0000]
parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(frac_digits);
- Formatted { sign: sign, parts: &parts[..2] }
+ Formatted { sign, parts: &parts[..2] }
} else {
parts[0] = Part::Copy(b"0");
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
}
FullDecoded::Finite(ref decoded) => {
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(b"NaN");
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(b"inf");
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
parts[0] = if dec_bounds.0 <= 0 && 0 < dec_bounds.1 {
} else {
Part::Copy(if upper { b"0E0" } else { b"0e0" })
};
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
FullDecoded::Finite(ref decoded) => {
let (len, exp) = format_shortest(decoded, buf);
} else {
digits_to_exp_str(&buf[..len], exp, 0, upper, parts)
};
- Formatted { sign: sign, parts: parts }
+ Formatted { sign, parts }
}
}
}
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(b"NaN");
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(b"inf");
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
if ndigits > 1 { // [0.][0000][e0]
parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(ndigits - 1);
parts[2] = Part::Copy(if upper { b"E0" } else { b"e0" });
- Formatted { sign: sign, parts: &parts[..3] }
+ Formatted { sign, parts: &parts[..3] }
} else {
parts[0] = Part::Copy(if upper { b"0E0" } else { b"0e0" });
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
}
FullDecoded::Finite(ref decoded) => {
match full_decoded {
FullDecoded::Nan => {
parts[0] = Part::Copy(b"NaN");
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
FullDecoded::Infinite => {
parts[0] = Part::Copy(b"inf");
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
FullDecoded::Zero => {
if frac_digits > 0 { // [0.][0000]
parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(frac_digits);
- Formatted { sign: sign, parts: &parts[..2] }
+ Formatted { sign, parts: &parts[..2] }
} else {
parts[0] = Part::Copy(b"0");
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
}
FullDecoded::Finite(ref decoded) => {
if frac_digits > 0 { // [0.][0000]
parts[0] = Part::Copy(b"0.");
parts[1] = Part::Zero(frac_digits);
- Formatted { sign: sign, parts: &parts[..2] }
+ Formatted { sign, parts: &parts[..2] }
} else {
parts[0] = Part::Copy(b"0");
- Formatted { sign: sign, parts: &parts[..1] }
+ Formatted { sign, parts: &parts[..1] }
}
} else {
Formatted { sign,
let idx = ((gamma as i32) - offset) * range / domain;
let (f, e, k) = CACHED_POW10[idx as usize];
debug_assert!(alpha <= e && e <= gamma);
- (k, Fp { f: f, e: e })
+ (k, Fp { f, e })
}
/// Given `x > 0`, returns `(k, 10^k)` such that `10^k <= x < 10^(k+1)`.
pub fn is_negative(self) -> bool { self < 0 }
}
- /// Return the memory representation of this integer as a byte array.
+ /// Return the memory representation of this integer as a byte array in
+ /// big-endian (network) byte order.
///
- /// The target platform’s native endianness is used.
- /// Portable code likely wants to use this after [`to_be`] or [`to_le`].
+ /// # Examples
///
- /// [`to_be`]: #method.to_be
- /// [`to_le`]: #method.to_le
+ /// ```
+ /// #![feature(int_to_from_bytes)]
+ ///
+ /// let bytes = 0x12345678i32.to_be_bytes();
+ /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]);
+ /// ```
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ pub fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_be().to_ne_bytes()
+ }
+
+ /// Return the memory representation of this integer as a byte array in
+ /// little-endian byte order.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(int_to_from_bytes)]
+ ///
+ /// let bytes = 0x12345678i32.to_le_bytes();
+ /// assert_eq!(bytes, [0x78, 0x56, 0x34, 0x12]);
+ /// ```
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ pub fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ self.to_le().to_ne_bytes()
+ }
+
+ /// Return the memory representation of this integer as a byte array in
+ /// native byte order.
+ ///
+ /// As the target platform's native endianness is used, portable code
+ /// should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate,
+ /// instead.
+ ///
+ /// [`to_be_bytes`]: #method.to_be_bytes
+ /// [`to_le_bytes`]: #method.to_le_bytes
///
/// # Examples
///
/// ```
/// #![feature(int_to_from_bytes)]
///
- /// let bytes = i32::min_value().to_be().to_bytes();
+ /// let bytes = i32::min_value().to_be().to_ne_bytes();
/// assert_eq!(bytes, [0x80, 0, 0, 0]);
/// ```
- #[unstable(feature = "int_to_from_bytes", issue = "49792")]
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
#[inline]
- pub fn to_bytes(self) -> [u8; mem::size_of::<Self>()] {
+ pub fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
unsafe { mem::transmute(self) }
}
- /// Create an integer value from its memory representation as a byte array.
+ /// Create an integer value from its representation as a byte array in
+ /// big endian.
///
- /// The target platform’s native endianness is used.
- /// Portable code likely wants to use [`from_be`] or [`from_le`] after this.
+ /// # Examples
///
- /// [`from_be`]: #method.from_be
- /// [`from_le`]: #method.from_le
+ /// ```
+ /// #![feature(int_to_from_bytes)]
+ ///
+ /// let int = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]);
+ /// assert_eq!(int, 0x12_34_56_78);
+ /// ```
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ pub fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_be(Self::from_ne_bytes(bytes))
+ }
+
+ /// Create an integer value from its representation as a byte array in
+ /// little endian.
///
/// # Examples
///
/// ```
/// #![feature(int_to_from_bytes)]
///
- /// let int = i32::from_be(i32::from_bytes([0x80, 0, 0, 0]));
+ /// let int = i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]);
+ /// assert_eq!(int, 0x78_56_34_12);
+ /// ```
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
+ #[inline]
+ pub fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ Self::from_le(Self::from_ne_bytes(bytes))
+ }
+
+ /// Create an integer value from its memory representation as a byte
+ /// array in native endianness.
+ ///
+ /// As the target platform's native endianness is used, portable code
+ /// likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
+ /// appropriate instead.
+ ///
+ /// [`from_be_bytes`]: #method.from_be_bytes
+ /// [`from_le_bytes`]: #method.from_le_bytes
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(int_to_from_bytes)]
+ ///
+ /// let int = i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0]));
/// assert_eq!(int, i32::min_value());
/// ```
- #[unstable(feature = "int_to_from_bytes", issue = "49792")]
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
#[inline]
- pub fn from_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
+ pub fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
unsafe { mem::transmute(bytes) }
}
}
/// let bytes = 0x1234_5678_u32.to_be().to_bytes();
/// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]);
/// ```
- #[unstable(feature = "int_to_from_bytes", issue = "49792")]
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
#[inline]
pub fn to_bytes(self) -> [u8; mem::size_of::<Self>()] {
unsafe { mem::transmute(self) }
/// let int = u32::from_be(u32::from_bytes([0x12, 0x34, 0x56, 0x78]));
/// assert_eq!(int, 0x1234_5678_u32);
/// ```
- #[unstable(feature = "int_to_from_bytes", issue = "49792")]
+ #[unstable(feature = "int_to_from_bytes", issue = "52963")]
#[inline]
pub fn from_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
unsafe { mem::transmute(bytes) }
/// Trait that indicates that this is a pointer or a wrapper for one,
/// where unsizing can be performed on the pointee.
///
-/// See the [DST coercion RfC][dst-coerce] and [the nomicon entry on coercion][nomicon-coerce]
+/// See the [DST coercion RFC][dst-coerce] and [the nomicon entry on coercion][nomicon-coerce]
/// for more details.
///
/// For builtin pointer types, pointers to `T` will coerce to pointers to `U` if `T: Unsize<U>`
/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
/// because it will attempt to drop the value previously at `*src`.
///
+/// Just like in C, whether an operation is volatile has no bearing whatsoever
+/// on questions involving concurrent access from multiple threads. Volatile
+/// accesses behave exactly like non-atomic accesses in that regard. In particular,
+/// a race between a `read_volatile` and any write operation to the same location
+/// is undefined behavior.
+///
/// # Examples
///
/// Basic usage:
/// This is appropriate for initializing uninitialized memory, or overwriting
/// memory that has previously been `read` from.
///
+/// Just like in C, whether an operation is volatile has no bearing whatsoever
+/// on questions involving concurrent access from multiple threads. Volatile
+/// accesses behave exactly like non-atomic accesses in that regard. In particular,
+/// a race between a `write_volatile` and any other operation (reading or writing)
+/// on the same location is undefined behavior.
+///
/// # Examples
///
/// Basic usage:
}
}
- /// Calculates the distance between two pointers. The returned value is in
- /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
- ///
- /// If the address different between the two pointers ia not a multiple of
- /// `mem::size_of::<T>()` then the result of the division is rounded towards
- /// zero.
- ///
- /// This function returns `None` if `T` is a zero-sized type.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// #![feature(offset_to)]
- /// #![allow(deprecated)]
- ///
- /// fn main() {
- /// let a = [0; 5];
- /// let ptr1: *const i32 = &a[1];
- /// let ptr2: *const i32 = &a[3];
- /// assert_eq!(ptr1.offset_to(ptr2), Some(2));
- /// assert_eq!(ptr2.offset_to(ptr1), Some(-2));
- /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2);
- /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1);
- /// }
- /// ```
- #[unstable(feature = "offset_to", issue = "41079")]
- #[rustc_deprecated(since = "1.27.0", reason = "Replaced by `wrapping_offset_from`, with the \
- opposite argument order. If you're writing unsafe code, consider `offset_from`.")]
- #[inline]
- pub fn offset_to(self, other: *const T) -> Option<isize> where T: Sized {
- let size = mem::size_of::<T>();
- if size == 0 {
- None
- } else {
- Some(other.wrapping_offset_from(self))
- }
- }
-
/// Calculates the distance between two pointers. The returned value is in
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
///
/// `write_bytes`, or `copy`). Note that `*self = foo` counts as a use
/// because it will attempt to drop the value previously at `*self`.
///
+ /// Just like in C, whether an operation is volatile has no bearing whatsoever
+ /// on questions involving concurrent access from multiple threads. Volatile
+ /// accesses behave exactly like non-atomic accesses in that regard. In particular,
+ /// a race between a `read_volatile` and any write operation to the same location
+ /// is undefined behavior.
+ ///
/// # Examples
///
/// Basic usage:
}
}
- /// Calculates the distance between two pointers. The returned value is in
- /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
- ///
- /// If the address different between the two pointers ia not a multiple of
- /// `mem::size_of::<T>()` then the result of the division is rounded towards
- /// zero.
- ///
- /// This function returns `None` if `T` is a zero-sized type.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// #![feature(offset_to)]
- /// #![allow(deprecated)]
- ///
- /// fn main() {
- /// let mut a = [0; 5];
- /// let ptr1: *mut i32 = &mut a[1];
- /// let ptr2: *mut i32 = &mut a[3];
- /// assert_eq!(ptr1.offset_to(ptr2), Some(2));
- /// assert_eq!(ptr2.offset_to(ptr1), Some(-2));
- /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2);
- /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1);
- /// }
- /// ```
- #[unstable(feature = "offset_to", issue = "41079")]
- #[rustc_deprecated(since = "1.27.0", reason = "Replaced by `wrapping_offset_from`, with the \
- opposite argument order. If you're writing unsafe code, consider `offset_from`.")]
- #[inline]
- pub fn offset_to(self, other: *const T) -> Option<isize> where T: Sized {
- let size = mem::size_of::<T>();
- if size == 0 {
- None
- } else {
- Some(other.wrapping_offset_from(self))
- }
- }
-
/// Calculates the distance between two pointers. The returned value is in
/// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
///
/// `write_bytes`, or `copy`). Note that `*self = foo` counts as a use
/// because it will attempt to drop the value previously at `*self`.
///
+ /// Just like in C, whether an operation is volatile has no bearing whatsoever
+ /// on questions involving concurrent access from multiple threads. Volatile
+ /// accesses behave exactly like non-atomic accesses in that regard. In particular,
+ /// a race between a `read_volatile` and any write operation to the same location
+ /// is undefined behavior.
+ ///
/// # Examples
///
/// Basic usage:
/// This is appropriate for initializing uninitialized memory, or overwriting
/// memory that has previously been `read` from.
///
+ /// Just like in C, whether an operation is volatile has no bearing whatsoever
+ /// on questions involving concurrent access from multiple threads. Volatile
+ /// accesses behave exactly like non-atomic accesses in that regard. In particular,
+ /// a race between a `write_volatile` and any other operation (reading or writing)
+ /// on the same location is undefined behavior.
+ ///
/// # Examples
///
/// Basic usage:
// - the first remaining bytes, < 2 word size
let len = text.len();
let ptr = text.as_ptr();
- let usize_bytes = mem::size_of::<usize>();
+ type Chunk = usize;
- let mut offset = {
- // We call this just to obtain the length of the suffix
- let (_, _, suffix) = unsafe { text.align_to::<usize>() };
- len - suffix.len()
+ let (min_aligned_offset, max_aligned_offset) = {
+ // We call this just to obtain the length of the prefix and suffix.
+ // In the middle we always process two chunks at once.
+ let (prefix, _, suffix) = unsafe { text.align_to::<(Chunk, Chunk)>() };
+ (prefix.len(), len - suffix.len())
};
+
+ let mut offset = max_aligned_offset;
if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
return Some(offset + index);
}
- // search the body of the text
+ // search the body of the text, make sure we don't cross min_aligned_offset.
+ // offset is always aligned, so just testing `>` is sufficient and avoids possible
+ // overflow.
let repeated_x = repeat_byte(x);
+ let chunk_bytes = mem::size_of::<Chunk>();
- while offset >= 2 * usize_bytes {
+ while offset > min_aligned_offset {
unsafe {
- let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
- let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);
+ let u = *(ptr.offset(offset as isize - 2 * chunk_bytes as isize) as *const Chunk);
+ let v = *(ptr.offset(offset as isize - chunk_bytes as isize) as *const Chunk);
// break if there is a matching byte
let zu = contains_zero_byte(u ^ repeated_x);
break;
}
}
- offset -= 2 * usize_bytes;
+ offset -= 2 * chunk_bytes;
}
// find the byte before the point the body loop stopped
// Extension traits
//
-// Use macros to be generic over const/mut
-macro_rules! slice_offset {
- ($ptr:expr, $by:expr) => {{
- let ptr = $ptr;
- if size_from_ptr(ptr) == 0 {
- (ptr as *mut i8).wrapping_offset($by) as _
- } else {
- ptr.offset($by)
- }
- }};
-}
-
-// make a &T from a *const T
-macro_rules! make_ref {
- ($ptr:expr) => {{
- let ptr = $ptr;
- if size_from_ptr(ptr) == 0 {
- // Use a non-null pointer value
- &*(1 as *mut _)
- } else {
- &*ptr
- }
- }};
-}
-
-// make a &mut T from a *mut T
-macro_rules! make_ref_mut {
- ($ptr:expr) => {{
- let ptr = $ptr;
- if size_from_ptr(ptr) == 0 {
- // Use a non-null pointer value
- &mut *(1 as *mut _)
- } else {
- &mut *ptr
- }
- }};
-}
-
#[lang = "slice"]
#[cfg(not(test))]
impl<T> [T] {
#[inline]
pub fn iter(&self) -> Iter<T> {
unsafe {
- let p = if mem::size_of::<T>() == 0 {
- 1 as *const _
+ let ptr = self.as_ptr();
+ assume(!ptr.is_null());
+
+ let end = if mem::size_of::<T>() == 0 {
+ (ptr as *const u8).wrapping_offset(self.len() as isize) as *const T
} else {
- let p = self.as_ptr();
- assume(!p.is_null());
- p
+ ptr.offset(self.len() as isize)
};
Iter {
- ptr: p,
- end: slice_offset!(p, self.len() as isize),
+ ptr,
+ end,
_marker: marker::PhantomData
}
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<T> {
unsafe {
- let p = if mem::size_of::<T>() == 0 {
- 1 as *mut _
+ let ptr = self.as_mut_ptr();
+ assume(!ptr.is_null());
+
+ let end = if mem::size_of::<T>() == 0 {
+ (ptr as *mut u8).wrapping_offset(self.len() as isize) as *mut T
} else {
- let p = self.as_mut_ptr();
- assume(!p.is_null());
- p
+ ptr.offset(self.len() as isize)
};
IterMut {
- ptr: p,
- end: slice_offset!(p, self.len() as isize),
+ ptr,
+ end,
_marker: marker::PhantomData
}
}
#[inline]
pub fn windows(&self, size: usize) -> Windows<T> {
assert!(size != 0);
- Windows { v: self, size: size }
+ Windows { v: self, size }
}
/// Returns an iterator over `chunk_size` elements of the slice at a
#[inline]
pub fn chunks(&self, chunk_size: usize) -> Chunks<T> {
assert!(chunk_size != 0);
- Chunks { v: self, chunk_size: chunk_size }
+ Chunks { v: self, chunk_size }
}
/// Returns an iterator over `chunk_size` elements of the slice at a time.
#[inline]
pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
assert!(chunk_size != 0);
- ChunksMut { v: self, chunk_size: chunk_size }
+ ChunksMut { v: self, chunk_size }
}
/// Returns an iterator over `chunk_size` elements of the slice at a
let rem = self.len() % chunk_size;
let len = self.len() - rem;
let (fst, snd) = self.split_at(len);
- ExactChunks { v: fst, rem: snd, chunk_size: chunk_size}
+ ExactChunks { v: fst, rem: snd, chunk_size }
}
/// Returns an iterator over `chunk_size` elements of the slice at a time.
let rem = self.len() % chunk_size;
let len = self.len() - rem;
let (fst, snd) = self.split_at_mut(len);
- ExactChunksMut { v: fst, rem: snd, chunk_size: chunk_size}
+ ExactChunksMut { v: fst, rem: snd, chunk_size }
}
/// Divides one slice into two at an index.
pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
where F: FnMut(&T) -> bool
{
- SplitMut { v: self, pred: pred, finished: false }
+ SplitMut { v: self, pred, finished: false }
}
/// Returns an iterator over subslices separated by elements that match
}
}
-#[inline]
+// Macro helper functions
+#[inline(always)]
fn size_from_ptr<T>(_: *const T) -> usize {
mem::size_of::<T>()
}
+// Inlining is_empty and len makes a huge performance difference
+macro_rules! is_empty {
+ // The way we encode the length of a ZST iterator, this works both for ZST
+ // and non-ZST.
+ ($self: ident) => {$self.ptr == $self.end}
+}
+// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
+// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
+macro_rules! len {
+ ($self: ident) => {{
+ let start = $self.ptr;
+ let diff = ($self.end as usize).wrapping_sub(start as usize);
+ let size = size_from_ptr(start);
+ if size == 0 {
+ diff
+ } else {
+ // Using division instead of `offset_from` helps LLVM remove bounds checks
+ diff / size
+ }
+ }}
+}
+
// The shared definition of the `Iter` and `IterMut` iterators
macro_rules! iterator {
- (struct $name:ident -> $ptr:ty, $elem:ty, $mkref:ident) => {
+ (struct $name:ident -> $ptr:ty, $elem:ty, $raw_mut:tt, $( $mut_:tt )*) => {
+ impl<'a, T> $name<'a, T> {
+ // Helper function for creating a slice from the iterator.
+ #[inline(always)]
+ fn make_slice(&self) -> &'a [T] {
+ unsafe { from_raw_parts(self.ptr, len!(self)) }
+ }
+
+ // Helper function for moving the start of the iterator forwards by `offset` elements,
+ // returning the old start.
+ // Unsafe because the offset must be in-bounds or one-past-the-end.
+ #[inline(always)]
+ unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T {
+ if mem::size_of::<T>() == 0 {
+ // This is *reducing* the length. `ptr` never changes with ZST.
+ self.end = (self.end as * $raw_mut u8).wrapping_offset(-offset) as * $raw_mut T;
+ self.ptr
+ } else {
+ let old = self.ptr;
+ self.ptr = self.ptr.offset(offset);
+ old
+ }
+ }
+
+ // Helper function for moving the end of the iterator backwards by `offset` elements,
+ // returning the new end.
+ // Unsafe because the offset must be in-bounds or one-past-the-end.
+ #[inline(always)]
+ unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T {
+ if mem::size_of::<T>() == 0 {
+ self.end = (self.end as * $raw_mut u8).wrapping_offset(-offset) as * $raw_mut T;
+ self.ptr
+ } else {
+ self.end = self.end.offset(-offset);
+ self.end
+ }
+ }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl<'a, T> ExactSizeIterator for $name<'a, T> {
+ #[inline(always)]
+ fn len(&self) -> usize {
+ len!(self)
+ }
+
+ #[inline(always)]
+ fn is_empty(&self) -> bool {
+ is_empty!(self)
+ }
+ }
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Iterator for $name<'a, T> {
type Item = $elem;
fn next(&mut self) -> Option<$elem> {
// could be implemented with slices, but this avoids bounds checks
unsafe {
+ assume(!self.ptr.is_null());
if mem::size_of::<T>() != 0 {
- assume(!self.ptr.is_null());
assume(!self.end.is_null());
}
- if self.ptr == self.end {
+ if is_empty!(self) {
None
} else {
- Some($mkref!(self.ptr.post_inc()))
+ Some(& $( $mut_ )* *self.post_inc_start(1))
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- let exact = unsafe { ptrdistance(self.ptr, self.end) };
+ let exact = len!(self);
(exact, Some(exact))
}
#[inline]
fn count(self) -> usize {
- self.len()
+ len!(self)
}
#[inline]
fn nth(&mut self, n: usize) -> Option<$elem> {
- // Call helper method. Can't put the definition here because mut versus const.
- self.iter_nth(n)
+ if n >= len!(self) {
+ // This iterator is now empty.
+ if mem::size_of::<T>() == 0 {
+ // We have to do it this way as `ptr` may never be 0, but `end`
+ // could be (due to wrapping).
+ self.end = self.ptr;
+ } else {
+ self.ptr = self.end;
+ }
+ return None;
+ }
+ // We are in bounds. `offset` does the right thing even for ZSTs.
+ unsafe {
+ let elem = Some(& $( $mut_ )* *self.ptr.offset(n as isize));
+ self.post_inc_start((n as isize).wrapping_add(1));
+ elem
+ }
}
#[inline]
// manual unrolling is needed when there are conditional exits from the loop
let mut accum = init;
unsafe {
- while ptrdistance(self.ptr, self.end) >= 4 {
- accum = f(accum, $mkref!(self.ptr.post_inc()))?;
- accum = f(accum, $mkref!(self.ptr.post_inc()))?;
- accum = f(accum, $mkref!(self.ptr.post_inc()))?;
- accum = f(accum, $mkref!(self.ptr.post_inc()))?;
+ while len!(self) >= 4 {
+ accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?;
+ accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?;
+ accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?;
+ accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?;
}
- while self.ptr != self.end {
- accum = f(accum, $mkref!(self.ptr.post_inc()))?;
+ while !is_empty!(self) {
+ accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?;
}
}
Try::from_ok(accum)
Self: Sized,
P: FnMut(Self::Item) -> bool,
{
- // The addition might panic on overflow
- // Use the len of the slice to hint optimizer to remove result index bounds check.
- let n = make_slice!(self.ptr, self.end).len();
+ // The addition might panic on overflow.
+ let n = len!(self);
self.try_fold(0, move |i, x| {
if predicate(x) { Err(i) }
else { Ok(i + 1) }
Self: Sized + ExactSizeIterator + DoubleEndedIterator
{
// No need for an overflow check here, because `ExactSizeIterator`
- // implies that the number of elements fits into a `usize`.
- // Use the len of the slice to hint optimizer to remove result index bounds check.
- let n = make_slice!(self.ptr, self.end).len();
+ let n = len!(self);
self.try_rfold(n, move |i, x| {
let i = i - 1;
if predicate(x) { Err(i) }
fn next_back(&mut self) -> Option<$elem> {
// could be implemented with slices, but this avoids bounds checks
unsafe {
+ assume(!self.ptr.is_null());
if mem::size_of::<T>() != 0 {
- assume(!self.ptr.is_null());
assume(!self.end.is_null());
}
- if self.end == self.ptr {
+ if is_empty!(self) {
None
} else {
- Some($mkref!(self.end.pre_dec()))
+ Some(& $( $mut_ )* *self.pre_dec_end(1))
}
}
}
// manual unrolling is needed when there are conditional exits from the loop
let mut accum = init;
unsafe {
- while ptrdistance(self.ptr, self.end) >= 4 {
- accum = f(accum, $mkref!(self.end.pre_dec()))?;
- accum = f(accum, $mkref!(self.end.pre_dec()))?;
- accum = f(accum, $mkref!(self.end.pre_dec()))?;
- accum = f(accum, $mkref!(self.end.pre_dec()))?;
+ while len!(self) >= 4 {
+ accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?;
+ accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?;
+ accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?;
+ accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?;
}
- while self.ptr != self.end {
- accum = f(accum, $mkref!(self.end.pre_dec()))?;
+ // inlining is_empty everywhere makes a huge performance difference
+ while !is_empty!(self) {
+ accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?;
}
}
Try::from_ok(accum)
}
}
-macro_rules! make_slice {
- ($start: expr, $end: expr) => {{
- let start = $start;
- let diff = ($end as usize).wrapping_sub(start as usize);
- if size_from_ptr(start) == 0 {
- // use a non-null pointer value
- unsafe { from_raw_parts(1 as *const _, diff) }
- } else {
- let len = diff / size_from_ptr(start);
- unsafe { from_raw_parts(start, len) }
- }
- }}
-}
-
-macro_rules! make_mut_slice {
- ($start: expr, $end: expr) => {{
- let start = $start;
- let diff = ($end as usize).wrapping_sub(start as usize);
- if size_from_ptr(start) == 0 {
- // use a non-null pointer value
- unsafe { from_raw_parts_mut(1 as *mut _, diff) }
- } else {
- let len = diff / size_from_ptr(start);
- unsafe { from_raw_parts_mut(start, len) }
- }
- }}
-}
-
/// Immutable slice iterator
///
/// This struct is created by the [`iter`] method on [slices].
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
ptr: *const T,
- end: *const T,
+ end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
+ // ptr == end is a quick test for the Iterator being empty, that works
+ // for both ZST and non-ZST.
_marker: marker::PhantomData<&'a T>,
}
/// ```
#[stable(feature = "iter_to_slice", since = "1.4.0")]
pub fn as_slice(&self) -> &'a [T] {
- make_slice!(self.ptr, self.end)
- }
-
- // Helper function for Iter::nth
- fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
- match self.as_slice().get(n) {
- Some(elem_ref) => unsafe {
- self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
- Some(elem_ref)
- },
- None => {
- self.ptr = self.end;
- None
- }
- }
+ self.make_slice()
}
}
-iterator!{struct Iter -> *const T, &'a T, make_ref}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> ExactSizeIterator for Iter<'a, T> {
- fn is_empty(&self) -> bool {
- self.ptr == self.end
- }
-}
+iterator!{struct Iter -> *const T, &'a T, const, /* no mut */}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Clone for Iter<'a, T> {
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T: 'a> {
ptr: *mut T,
- end: *mut T,
+ end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
+ // ptr == end is a quick test for the Iterator being empty, that works
+ // for both ZST and non-ZST.
_marker: marker::PhantomData<&'a mut T>,
}
impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("IterMut")
- .field(&make_slice!(self.ptr, self.end))
+ .field(&self.make_slice())
.finish()
}
}
/// ```
#[stable(feature = "iter_to_slice", since = "1.4.0")]
pub fn into_slice(self) -> &'a mut [T] {
- make_mut_slice!(self.ptr, self.end)
- }
-
- // Helper function for IterMut::nth
- fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
- match make_mut_slice!(self.ptr, self.end).get_mut(n) {
- Some(elem_ref) => unsafe {
- self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
- Some(elem_ref)
- },
- None => {
- self.ptr = self.end;
- None
- }
- }
- }
-}
-
-iterator!{struct IterMut -> *mut T, &'a mut T, make_ref_mut}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> ExactSizeIterator for IterMut<'a, T> {
- fn is_empty(&self) -> bool {
- self.ptr == self.end
+ unsafe { from_raw_parts_mut(self.ptr, len!(self)) }
}
}
-// Return the number of elements of `T` from `start` to `end`.
-// Return the arithmetic difference if `T` is zero size.
-#[inline(always)]
-unsafe fn ptrdistance<T>(start: *const T, end: *const T) -> usize {
- if mem::size_of::<T>() == 0 {
- (end as usize).wrapping_sub(start as usize)
- } else {
- end.offset_from(start) as usize
- }
-}
-
-// Extension methods for raw pointers, used by the iterators
-trait PointerExt : Copy {
- unsafe fn slice_offset(self, i: isize) -> Self;
-
- /// Increments `self` by 1, but returns the old value.
- #[inline(always)]
- unsafe fn post_inc(&mut self) -> Self {
- let current = *self;
- *self = self.slice_offset(1);
- current
- }
-
- /// Decrements `self` by 1, and returns the new value.
- #[inline(always)]
- unsafe fn pre_dec(&mut self) -> Self {
- *self = self.slice_offset(-1);
- *self
- }
-}
-
-impl<T> PointerExt for *const T {
- #[inline(always)]
- unsafe fn slice_offset(self, i: isize) -> Self {
- slice_offset!(self, i)
- }
-}
-
-impl<T> PointerExt for *mut T {
- #[inline(always)]
- unsafe fn slice_offset(self, i: isize) -> Self {
- slice_offset!(self, i)
- }
-}
+iterator!{struct IterMut -> *mut T, &'a mut T, mut, mut}
/// An internal abstraction over the splitting iterators, so that
/// splitn, splitn_mut etc can be implemented once.
/// ```
/// use std::slice;
///
-/// // manifest a slice out of thin air!
-/// let ptr = 0x1234 as *const usize;
-/// let amt = 10;
-/// unsafe {
-/// let slice = slice::from_raw_parts(ptr, amt);
-/// }
+/// // manifest a slice for a single element
+/// let x = 42;
+/// let ptr = &x as *const _;
+/// let slice = unsafe { slice::from_raw_parts(ptr, 1) };
+/// assert_eq!(slice[0], 42);
/// ```
///
/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn swap(&self, val: bool, order: Ordering) -> bool {
unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
Ok(x) => x,
/// ```
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_exchange(&self,
current: bool,
new: bool,
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
unsafe { atomic_and(self.v.get(), val as u8, order) != 0 }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
// We can't use atomic_nand here because it can result in a bool with
// an invalid value. This happens because the atomic operation is done
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
unsafe { atomic_or(self.v.get(), val as u8, order) != 0 }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
Ok(x) => x,
/// ```
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_exchange(&self,
current: *mut T,
new: *mut T,
```"),
#[inline]
#[$stable]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
unsafe { atomic_swap(self.v.get(), val, order) }
}
```"),
#[inline]
#[$stable]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_and_swap(&self,
current: $int_type,
new: $int_type,
```"),
#[inline]
#[$stable_cxchg]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_exchange(&self,
current: $int_type,
new: $int_type,
}
#[inline]
-#[cfg(any(stage0, target_has_atomic = "cas"))]
+#[cfg(target_has_atomic = "cas")]
fn strongest_failure_ordering(order: Ordering) -> Ordering {
match order {
Release => Relaxed,
}
#[inline]
-#[cfg(any(stage0, target_has_atomic = "cas"))]
+#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_xchg_acq(dst, val),
}
#[inline]
-#[cfg(any(stage0, target_has_atomic = "cas"))]
+#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_compare_exchange<T>(dst: *mut T,
old: T,
new: T,
{
Context {
local_waker: self.local_waker,
- executor: executor,
+ executor,
}
}
}
/// `Arc` type and the safe `Wake` trait.
#[inline]
pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
- Waker { inner: inner }
+ Waker { inner }
}
/// Wake up the task associated with this `Waker`.
/// on the current thread.
#[inline]
pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
- LocalWaker { inner: inner }
+ LocalWaker { inner }
}
/// Wake up the task associated with this `LocalWaker`.
impl From<LocalWaker> for Waker {
#[inline]
fn from(local_waker: LocalWaker) -> Self {
- Waker { inner: local_waker.inner }
+ let inner = local_waker.inner;
+ mem::forget(local_waker);
+ Waker { inner }
}
}
}
#[test]
-fn test_is_digit() {
+fn test_is_numeric() {
assert!('2'.is_numeric());
assert!('7'.is_numeric());
+ assert!('¾'.is_numeric());
assert!(!'c'.is_numeric());
assert!(!'i'.is_numeric());
assert!(!'z'.is_numeric());
check('\u{12340}');
check('\u{10FFFF}');
}
-
-#[test]
-#[allow(deprecated)]
-fn test_decode_utf8() {
- macro_rules! assert_decode_utf8 {
- ($input_bytes: expr, $expected_str: expr) => {
- let input_bytes: &[u8] = &$input_bytes;
- let s = char::decode_utf8(input_bytes.iter().cloned())
- .map(|r_b| r_b.unwrap_or('\u{FFFD}'))
- .collect::<String>();
- assert_eq!(s, $expected_str,
- "input bytes: {:?}, expected str: {:?}, result: {:?}",
- input_bytes, $expected_str, s);
- assert_eq!(String::from_utf8_lossy(&$input_bytes), $expected_str);
- }
- }
-
- assert_decode_utf8!([], "");
- assert_decode_utf8!([0x41], "A");
- assert_decode_utf8!([0xC1, 0x81], "��");
- assert_decode_utf8!([0xE2, 0x99, 0xA5], "♥");
- assert_decode_utf8!([0xE2, 0x99, 0xA5, 0x41], "♥A");
- assert_decode_utf8!([0xE2, 0x99], "�");
- assert_decode_utf8!([0xE2, 0x99, 0x41], "�A");
- assert_decode_utf8!([0xC0], "�");
- assert_decode_utf8!([0xC0, 0x41], "�A");
- assert_decode_utf8!([0x80], "�");
- assert_decode_utf8!([0x80, 0x41], "�A");
- assert_decode_utf8!([0xFE], "�");
- assert_decode_utf8!([0xFE, 0x41], "�A");
- assert_decode_utf8!([0xFF], "�");
- assert_decode_utf8!([0xFF, 0x41], "�A");
- assert_decode_utf8!([0xC0, 0x80], "��");
-
- // Surrogates
- assert_decode_utf8!([0xED, 0x9F, 0xBF], "\u{D7FF}");
- assert_decode_utf8!([0xED, 0xA0, 0x80], "���");
- assert_decode_utf8!([0xED, 0xBF, 0x80], "���");
- assert_decode_utf8!([0xEE, 0x80, 0x80], "\u{E000}");
-
- // char::MAX
- assert_decode_utf8!([0xF4, 0x8F, 0xBF, 0xBF], "\u{10FFFF}");
- assert_decode_utf8!([0xF4, 0x8F, 0xBF, 0x41], "�A");
- assert_decode_utf8!([0xF4, 0x90, 0x80, 0x80], "����");
-
- // 5 and 6 bytes sequence
- // Part of the original design of UTF-8,
- // but invalid now that UTF-8 is artificially restricted to match the range of UTF-16.
- assert_decode_utf8!([0xF8, 0x80, 0x80, 0x80, 0x80], "�����");
- assert_decode_utf8!([0xFC, 0x80, 0x80, 0x80, 0x80, 0x80], "������");
-}
assert_eq!(res, [14, 18, 22, 26]);
}
+#[test]
+#[allow(const_err)]
+fn test_iter_ref_consistency() {
+ use std::fmt::Debug;
+
+ fn test<T : Copy + Debug + PartialEq>(x : T) {
+ let v : &[T] = &[x, x, x];
+ let v_ptrs : [*const T; 3] = match v {
+ [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _],
+ _ => unreachable!()
+ };
+ let len = v.len();
+
+ // nth(i)
+ for i in 0..len {
+ assert_eq!(&v[i] as *const _, v_ptrs[i]); // check the v_ptrs array, just to be sure
+ let nth = v.iter().nth(i).unwrap();
+ assert_eq!(nth as *const _, v_ptrs[i]);
+ }
+ assert_eq!(v.iter().nth(len), None, "nth(len) should return None");
+
+ // stepping through with nth(0)
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let next = it.nth(0).unwrap();
+ assert_eq!(next as *const _, v_ptrs[i]);
+ }
+ assert_eq!(it.nth(0), None);
+ }
+
+ // next()
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let next = it.next().unwrap();
+ assert_eq!(next as *const _, v_ptrs[i]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next(), None, "The final call to next() should return None");
+ }
+
+ // next_back()
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let prev = it.next_back().unwrap();
+ assert_eq!(prev as *const _, v_ptrs[remaining-1]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next_back(), None, "The final call to next_back() should return None");
+ }
+ }
+
+ fn test_mut<T : Copy + Debug + PartialEq>(x : T) {
+ let v : &mut [T] = &mut [x, x, x];
+ let v_ptrs : [*mut T; 3] = match v {
+ [ref v1, ref v2, ref v3] =>
+ [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _],
+ _ => unreachable!()
+ };
+ let len = v.len();
+
+ // nth(i)
+ for i in 0..len {
+ assert_eq!(&mut v[i] as *mut _, v_ptrs[i]); // check the v_ptrs array, just to be sure
+ let nth = v.iter_mut().nth(i).unwrap();
+ assert_eq!(nth as *mut _, v_ptrs[i]);
+ }
+ assert_eq!(v.iter().nth(len), None, "nth(len) should return None");
+
+ // stepping through with nth(0)
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let next = it.nth(0).unwrap();
+ assert_eq!(next as *const _, v_ptrs[i]);
+ }
+ assert_eq!(it.nth(0), None);
+ }
+
+ // next()
+ {
+ let mut it = v.iter_mut();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let next = it.next().unwrap();
+ assert_eq!(next as *mut _, v_ptrs[i]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next(), None, "The final call to next() should return None");
+ }
+
+ // next_back()
+ {
+ let mut it = v.iter_mut();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let prev = it.next_back().unwrap();
+ assert_eq!(prev as *mut _, v_ptrs[remaining-1]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next_back(), None, "The final call to next_back() should return None");
+ }
+ }
+
+ // Make sure iterators and slice patterns yield consistent addresses for various types,
+ // including ZSTs.
+ test(0u32);
+ test(());
+ test([0u32; 0]); // ZST with alignment > 0
+ test_mut(0u32);
+ test_mut(());
+ test_mut([0u32; 0]); // ZST with alignment > 0
+}
+
// The current implementation of SliceIndex fails to handle methods
// orthogonally from range types; therefore, it is worth testing
// all of the indexing operations on each input.
let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64)
.expect("overflow in Duration::new");
let nanos = nanos % NANOS_PER_SEC;
- Duration { secs: secs, nanos: nanos }
+ Duration { secs, nanos }
}
/// Creates a new `Duration` from the specified number of whole seconds.
#[stable(feature = "duration", since = "1.3.0")]
#[inline]
pub const fn from_secs(secs: u64) -> Duration {
- Duration { secs: secs, nanos: 0 }
+ Duration { secs, nanos: 0 }
}
/// Creates a new `Duration` from the specified number of milliseconds.
}
};
debug_assert!(nanos < NANOS_PER_SEC);
- Some(Duration { secs: secs, nanos: nanos })
+ Some(Duration { secs, nanos })
} else {
None
}
let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
let nanos = self.nanos / rhs + (extra_nanos as u32);
debug_assert!(nanos < NANOS_PER_SEC);
- Some(Duration { secs: secs, nanos: nanos })
+ Some(Duration { secs, nanos })
} else {
None
}
pub const N_table: &super::BoolTrie = &super::BoolTrie {
r1: [
- 0x03ff000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
+ 0x03ff000000000000, 0x0000000000000000, 0x720c000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x00000000000003ff
],
r2: [
- 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 3,
- 0, 0, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 5, 0, 0, 0, 3, 2, 0, 0, 0, 0, 6, 0, 2, 0, 0, 7, 0, 0, 2, 8, 0, 0, 7, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 2, 0, 1, 0, 1, 0, 3, 0, 4, 0, 5, 0, 1, 0, 6, 0, 1, 0, 7, 0, 7, 8,
+ 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 11, 0, 0, 0, 12, 7, 0, 0, 0, 0, 13, 0, 14, 0, 0, 15, 0, 0, 7, 16, 0, 0, 15, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 9, 0, 0, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 27, 0, 28,
+ 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28,
+ 0, 0, 1, 0, 0, 0, 0, 31, 0, 0, 7, 9, 0, 0, 32, 0, 7, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 2, 4, 0, 0, 12, 0, 2, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 2, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0
],
r3: &[
- 0x0000000000000000, 0x0000ffc000000000, 0x0000000003ff0000, 0x000003ff00000000,
- 0x00000000000003ff, 0x0001c00000000000, 0x000000000000ffc0, 0x0000000003ff03ff,
- 0x03ff000000000000, 0xffffffff00000000, 0x00000000000001e7, 0x070003fe00000080,
+ 0x0000000000000000, 0x0000ffc000000000, 0x03f0ffc000000000, 0x00fcffc000000000,
+ 0x0007ffc000000000, 0x7f00ffc000000000, 0x01ffffc07f000000, 0x0000000003ff0000,
+ 0x000fffff00000000, 0x00000000000003ff, 0x1ffffe0000000000, 0x0001c00000000000,
+ 0x03ff03ff00000000, 0x000000000000ffc0, 0x0000000007ff0000, 0x0000000003ff03ff,
+ 0x03ff000000000000, 0x03f1000000000000, 0xffffffffffff0000, 0x00000000000003e7,
+ 0xffffffff00000000, 0x000000000fffffff, 0xfffffc0000000000, 0xffc0000000000000,
+ 0x00000000000fffff, 0x2000000000000000, 0x070003fe00000080, 0x00000000003c0000,
+ 0x000003ff00000000, 0x00000000fffeff00, 0xfffe0000000003ff, 0x003f000000000000,
0x03ff000003ff0000
],
r4: [
- 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 6, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
],
r5: &[
- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 6, 0, 5, 7, 0, 0, 8, 0, 0, 0, 5, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0,
- 0, 0, 8, 0, 9, 5, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0,
- 0, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
- 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 7, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 10, 11, 12, 0, 13, 14, 0, 15, 16, 17, 0, 18, 19, 0, 0, 0, 0, 20, 21, 0,
+ 0, 0, 0, 22, 0, 0, 23, 24, 0, 0, 0, 25, 0, 21, 26, 0, 0, 27, 0, 0, 0, 21, 0, 0, 0, 0, 0,
+ 28, 0, 28, 0, 0, 0, 0, 0, 28, 0, 29, 30, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 32, 0, 0, 0, 28, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 38, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 28, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
],
r6: &[
- 0x0000000000000000, 0x001fffffffffffff, 0x0000000000000402, 0x00000000003e0000,
- 0x000003ff00000000, 0x03ff000000000000, 0x0000ffc000000000, 0xffc0000000000000,
- 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff,
- 0xffffffffffffc000
+ 0x0000000000000000, 0x000fffffffffff80, 0x01ffffffffffffff, 0x0000000000000c00,
+ 0x0ffffffe00000000, 0x0000000f00000000, 0x0000000000000402, 0x00000000003e0000,
+ 0x000003ff00000000, 0xfe000000ff000000, 0x0000ff8000000000, 0xf800000000000000,
+ 0x000000000fc00000, 0x3000000000000000, 0xfffffffffffcffff, 0x60000000000001ff,
+ 0x00000000e0000000, 0x0000f80000000000, 0xff000000ff000000, 0x0000fe0000000000,
+ 0xfc00000000000000, 0x03ff000000000000, 0x7fffffff00000000, 0x0000007fe0000000,
+ 0x00000000001e0000, 0x0000fffffffc0000, 0xffc0000000000000, 0x001ffffe03ff0000,
+ 0x0000000003ff0000, 0x00000000000003ff, 0x0fff000000000000, 0x0007ffff00000000,
+ 0x00001fffffff0000, 0xffffffffffffffff, 0x00007fffffffffff, 0x00000003fbff0000,
+ 0x00000000007fffff, 0x000fffff00000000, 0x01ffffff00000000, 0xffffffffffffc000,
+ 0x000000000000ff80, 0xfffe000000000000, 0x001eefffffffffff, 0x0000000000001fff
],
};
'Lu': ['LC', 'L'], 'Ll': ['LC', 'L'], 'Lt': ['LC', 'L'],
'Lm': ['L'], 'Lo': ['L'],
'Mn': ['M'], 'Mc': ['M'], 'Me': ['M'],
- 'Nd': ['N'], 'Nl': ['N'], 'No': ['No'],
+ 'Nd': ['N'], 'Nl': ['N'], 'No': ['N'],
'Pc': ['P'], 'Pd': ['P'], 'Ps': ['P'], 'Pe': ['P'],
'Pi': ['P'], 'Pf': ['P'], 'Po': ['P'],
'Sm': ['S'], 'Sc': ['S'], 'Sk': ['S'], 'So': ['S'],
PrimTy(hir::PrimTy),
TyParam(DefId),
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
+ ToolMod, // e.g. `rustfmt` in `#[rustfmt::skip]`
// Value namespace
Fn(DefId),
// Macro namespace
Macro(DefId, MacroKind),
+ NonMacroAttr, // e.g. `#[inline]` or `#[rustfmt::skip]`
GlobalAsm(DefId),
Def::Label(..) |
Def::PrimTy(..) |
Def::SelfTy(..) |
+ Def::ToolMod |
+ Def::NonMacroAttr |
Def::Err => {
bug!("attempted .def_id() on invalid def: {:?}", self)
}
Def::SelfTy(..) => "self type",
Def::Macro(.., macro_kind) => macro_kind.descr(),
Def::GlobalAsm(..) => "global asm",
+ Def::ToolMod => "tool module",
+ Def::NonMacroAttr => "non-macro attribute",
Def::Err => "unresolved item",
}
}
}
// Desugar `<start>..=<end>` to `std::ops::RangeInclusive::new(<start>, <end>)`
ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
- // FIXME: Use e.span directly after RangeInclusive::new() is stabilized in stage0.
- let span = self.allow_internal_unstable(CompilerDesugaringKind::DotFill, e.span);
let id = self.next_id();
let e1 = self.lower_expr(e1);
let e2 = self.lower_expr(e2);
- let ty_path = P(self.std_path(span, &["ops", "RangeInclusive"], None, false));
- let ty = P(self.ty_path(id, span, hir::QPath::Resolved(None, ty_path)));
+ let ty_path = P(self.std_path(e.span, &["ops", "RangeInclusive"], None, false));
+ let ty = P(self.ty_path(id, e.span, hir::QPath::Resolved(None, ty_path)));
let new_seg = P(hir::PathSegment::from_ident(Ident::from_str("new")));
let new_path = hir::QPath::TypeRelative(ty, new_seg);
- let new = P(self.expr(span, hir::ExprKind::Path(new_path), ThinVec::new()));
+ let new = P(self.expr(e.span, hir::ExprKind::Path(new_path), ThinVec::new()));
hir::ExprKind::Call(new, hir_vec![e1, e2])
}
ExprKind::Range(ref e1, ref e2, lims) => {
.chain(e2.iter().map(|e| ("end", e)))
.map(|(s, e)| {
let expr = P(self.lower_expr(&e));
- let unstable_span =
- self.allow_internal_unstable(CompilerDesugaringKind::DotFill, e.span);
- let ident = Ident::new(Symbol::intern(s), unstable_span);
- self.field(ident, expr, unstable_span)
+ let ident = Ident::new(Symbol::intern(s), e.span);
+ self.field(ident, expr, e.span)
})
.collect::<P<[hir::Field]>>();
let is_unit = fields.is_empty();
- let unstable_span =
- self.allow_internal_unstable(CompilerDesugaringKind::DotFill, e.span);
let struct_path = iter::once("ops")
.chain(iter::once(path))
.collect::<Vec<_>>();
- let struct_path = self.std_path(unstable_span, &struct_path, None, is_unit);
+ let struct_path = self.std_path(e.span, &struct_path, None, is_unit);
let struct_path = hir::QPath::Resolved(None, P(struct_path));
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
} else {
hir::ExprKind::Struct(struct_path, fields, None)
},
- span: unstable_span,
+ span: e.span,
attrs: e.attrs.clone(),
};
}
Label(node_id),
Macro(def_id, macro_kind),
GlobalAsm(def_id),
+ ToolMod,
+ NonMacroAttr,
Err
});
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
Async,
- DotFill,
QuestionMark,
ExistentialReturnType,
ForLoop,
}
}
+impl_stable_hash_for!(enum mir::interpret::ScalarMaybeUndef {
+ Scalar(v),
+ Undef
+});
+
impl_stable_hash_for!(enum mir::interpret::Value {
Scalar(v),
ScalarPair(a, b),
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
- Bits { bits, defined } => {
+ Bits { bits, size } => {
bits.hash_stable(hcx, hasher);
- defined.hash_stable(hcx, hasher);
+ size.hash_stable(hcx, hasher);
},
Ptr(ptr) => ptr.hash_stable(hcx, hasher),
}
pub mod nodemap;
pub mod fs;
pub mod time_graph;
+ pub mod profiling;
}
// A private module so that macro-expanded idents like
use std::default::Default as StdDefault;
use syntax::ast;
use syntax::edition;
-use syntax_pos::{MultiSpan, Span};
+use syntax_pos::{MultiSpan, Span, symbol::LocalInternedString};
use errors::DiagnosticBuilder;
use hir;
use hir::def_id::LOCAL_CRATE;
/// The lint is either renamed or removed. This is the warning
/// message, and an optional new name (`None` if removed).
Warning(String, Option<String>),
+ /// The lint is from a tool. If the Option is None, then either
+ /// the lint does not exist in the tool or the code was not
+ /// compiled with the tool and therefore the lint was never
+ /// added to the `LintStore`. Otherwise the `LintId` will be
+ /// returned as if it where a rustc lint.
+ Tool(Option<&'a [LintId]>),
}
impl LintStore {
sess: &Session,
lint_name: &str,
level: Level) {
- let db = match self.check_lint_name(lint_name) {
+ let db = match self.check_lint_name(lint_name, None) {
CheckLintNameResult::Ok(_) => None,
CheckLintNameResult::Warning(ref msg, _) => {
Some(sess.struct_warn(msg))
CheckLintNameResult::NoLint => {
Some(struct_err!(sess, E0602, "unknown lint: `{}`", lint_name))
}
+ CheckLintNameResult::Tool(_) => unreachable!(),
};
if let Some(mut db) = db {
/// it emits non-fatal warnings and there are *two* lint passes that
/// inspect attributes, this is only run from the late pass to avoid
/// printing duplicate warnings.
- pub fn check_lint_name(&self, lint_name: &str) -> CheckLintNameResult {
- match self.by_name.get(lint_name) {
- Some(&Renamed(ref new_name, _)) => {
- CheckLintNameResult::Warning(
- format!("lint `{}` has been renamed to `{}`", lint_name, new_name),
- Some(new_name.to_owned())
- )
- },
- Some(&Removed(ref reason)) => {
- CheckLintNameResult::Warning(
- format!("lint `{}` has been removed: `{}`", lint_name, reason),
- None
- )
- },
- None => {
- match self.lint_groups.get(lint_name) {
- None => CheckLintNameResult::NoLint,
- Some(ids) => CheckLintNameResult::Ok(&ids.0),
- }
+ pub fn check_lint_name(
+ &self,
+ lint_name: &str,
+ tool_name: Option<LocalInternedString>,
+ ) -> CheckLintNameResult {
+ let complete_name = if let Some(tool_name) = tool_name {
+ format!("{}::{}", tool_name, lint_name)
+ } else {
+ lint_name.to_string()
+ };
+ if let Some(_) = tool_name {
+ match self.by_name.get(&complete_name) {
+ None => match self.lint_groups.get(&*complete_name) {
+ None => return CheckLintNameResult::Tool(None),
+ Some(ids) => return CheckLintNameResult::Tool(Some(&ids.0)),
+ },
+ Some(&Id(ref id)) => return CheckLintNameResult::Tool(Some(slice::from_ref(id))),
+ // If the lint was registered as removed or renamed by the lint tool, we don't need
+ // to treat tool_lints and rustc lints different and can use the code below.
+ _ => {}
}
+ }
+ match self.by_name.get(&complete_name) {
+ Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning(
+ format!("lint `{}` has been renamed to `{}`", lint_name, new_name),
+ Some(new_name.to_owned()),
+ ),
+ Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
+ format!("lint `{}` has been removed: `{}`", lint_name, reason),
+ None,
+ ),
+ None => match self.lint_groups.get(&*complete_name) {
+ None => CheckLintNameResult::NoLint,
+ Some(ids) => CheckLintNameResult::Ok(&ids.0),
+ },
Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
}
}
continue
}
};
- if let Some(lint_tool) = word.is_scoped() {
- if !self.sess.features_untracked().tool_lints {
+ let tool_name = if let Some(lint_tool) = word.is_scoped() {
+ let gate_feature = !self.sess.features_untracked().tool_lints;
+ let known_tool = attr::is_known_lint_tool(lint_tool);
+ if gate_feature {
feature_gate::emit_feature_err(&sess.parse_sess,
"tool_lints",
word.span,
&format!("scoped lint `{}` is experimental",
word.ident));
}
-
- if !attr::is_known_lint_tool(lint_tool) {
+ if !known_tool {
span_err!(
sess,
lint_tool.span,
);
}
- continue
- }
+ if gate_feature || !known_tool {
+ continue
+ }
+
+ Some(lint_tool.as_str())
+ } else {
+ None
+ };
let name = word.name();
- match store.check_lint_name(&name.as_str()) {
+ match store.check_lint_name(&name.as_str(), tool_name) {
CheckLintNameResult::Ok(ids) => {
let src = LintSource::Node(name, li.span);
for id in ids {
}
}
+ CheckLintNameResult::Tool(result) => {
+ if let Some(ids) = result {
+ let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
+ let src = LintSource::Node(Symbol::intern(complete_name), li.span);
+ for id in ids {
+ specs.insert(*id, (level, src));
+ }
+ }
+ // If Tool(None) is returned, then either the lint does not exist in the
+ // tool or the code was not compiled with the tool and therefore the lint
+ // was never added to the `LintStore`. To detect this is the responsibility
+ // of the lint tool.
+ }
+
_ if !self.warn_about_weird_lints => {}
CheckLintNameResult::Warning(msg, renamed) => {
if name.as_str().chars().any(|c| c.is_uppercase()) {
let name_lower = name.as_str().to_lowercase().to_string();
if let CheckLintNameResult::NoLint =
- store.check_lint_name(&name_lower) {
+ store.check_lint_name(&name_lower, tool_name) {
db.emit();
} else {
db.span_suggestion_with_applicability(
);
}
+#[macro_export]
+macro_rules! declare_tool_lint {
+ ($vis: vis $tool: ident ::$NAME: ident, $Level: ident, $desc: expr) => (
+ declare_tool_lint!{$vis $tool::$NAME, $Level, $desc, false}
+ );
+ ($vis: vis $tool: ident ::$NAME: ident, $Level: ident, $desc: expr,
+ report_in_external_macro: $rep: expr) => (
+ declare_tool_lint!{$vis $tool::$NAME, $Level, $desc, $rep}
+ );
+ ($vis: vis $tool: ident ::$NAME: ident, $Level: ident, $desc: expr, $external: expr) => (
+ $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
+ name: &concat!(stringify!($tool), "::", stringify!($NAME)),
+ default_level: $crate::lint::$Level,
+ desc: $desc,
+ edition_lint_opts: None,
+ report_in_external_macro: $external,
+ };
+ );
+}
+
/// Declare a static `LintArray` and return it as an expression.
#[macro_export]
macro_rules! lint_array {
// Check for future incompatibility lints and issue a stronger warning.
let lints = sess.lint_store.borrow();
let lint_id = LintId::of(lint);
- if let Some(future_incompatible) = lints.future_incompatible(lint_id) {
+ let future_incompatible = lints.future_incompatible(lint_id);
+ if let Some(future_incompatible) = future_incompatible {
const STANDARD_MESSAGE: &str =
"this was previously accepted by the compiler but is being phased out; \
it will become a hard error";
future_incompatible.reference);
err.warn(&explanation);
err.note(&citation);
+ }
- // If this lint is *not* a future incompatibility warning then we want to be
- // sure to not be too noisy in some situations. If this code originates in a
- // foreign macro, aka something that this crate did not itself author, then
- // it's likely that there's nothing this crate can do about it. We probably
- // want to skip the lint entirely.
- //
- // For some lints though (like unreachable code) there's clear actionable
- // items to take care of (delete the macro invocation). As a result we have
- // a few lints we whitelist here for allowing a lint even though it's in a
- // foreign macro invocation.
- } else if !lint.report_in_external_macro {
- if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
- err.cancel();
+ // If this code originates in a foreign macro, aka something that this crate
+ // did not itself author, then it's likely that there's nothing this crate
+ // can do about it. We probably want to skip the lint entirely.
+ if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
+ // Any suggestions made here are likely to be incorrect, so anything we
+ // emit shouldn't be automatically fixed by rustfix.
+ err.allow_suggestions(false);
+
+ // If this is a future incompatible lint it'll become a hard error, so
+ // we have to emit *something*. Also allow lints to whitelist themselves
+ // on a case-by-case basis for emission in a foreign macro.
+ if future_incompatible.is_none() && !lint.report_in_external_macro {
+ err.cancel()
}
}
//! are *mostly* used as a part of that interface, but these should
//! probably get a better home if someone can find one.
-use hir::def;
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use hir::map as hir_map;
-use hir::map::definitions::{Definitions, DefKey, DefPathTable};
+use hir::map::definitions::{DefKey, DefPathTable};
use hir::svh::Svh;
use ty::{self, TyCtxt};
use session::{Session, CrateDisambiguator};
use std::any::Any;
use std::path::{Path, PathBuf};
use syntax::ast;
-use syntax::edition::Edition;
-use syntax::ext::base::SyntaxExtension;
use syntax::symbol::Symbol;
use syntax_pos::Span;
use rustc_target::spec::Target;
pub def_id: DefId,
}
-pub enum LoadedMacro {
- MacroDef(ast::Item),
- ProcMacro(Lrc<SyntaxExtension>),
-}
-
#[derive(Copy, Clone, Debug)]
pub struct ExternCrate {
pub src: ExternCrateSource,
pub trait CrateStore {
fn crate_data_as_rc_any(&self, krate: CrateNum) -> Lrc<dyn Any>;
- // access to the metadata loader
- fn metadata_loader(&self) -> &dyn MetadataLoader;
-
// resolve
fn def_key(&self, def: DefId) -> DefKey;
fn def_path(&self, def: DefId) -> hir_map::DefPath;
fn def_path_table(&self, cnum: CrateNum) -> Lrc<DefPathTable>;
// "queries" used in resolve that aren't tracked for incremental compilation
- fn visibility_untracked(&self, def: DefId) -> ty::Visibility;
- fn export_macros_untracked(&self, cnum: CrateNum);
- fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind;
fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;
fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
- fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition;
- fn struct_field_names_untracked(&self, def: DefId) -> Vec<ast::Name>;
- fn item_children_untracked(&self, did: DefId, sess: &Session) -> Vec<def::Export>;
- fn load_macro_untracked(&self, did: DefId, sess: &Session) -> LoadedMacro;
fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics;
- fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem;
fn postorder_cnums_untracked(&self) -> Vec<CrateNum>;
// This is basically a 1-based range of ints, which is a little
pub type CrateStoreDyn = dyn CrateStore + sync::Sync;
-// FIXME: find a better place for this?
-pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
- let mut err_count = 0;
- {
- let mut say = |s: &str| {
- match (sp, sess) {
- (_, None) => bug!("{}", s),
- (Some(sp), Some(sess)) => sess.span_err(sp, s),
- (None, Some(sess)) => sess.err(s),
- }
- err_count += 1;
- };
- if s.is_empty() {
- say("crate name must not be empty");
- }
- for c in s.chars() {
- if c.is_alphanumeric() { continue }
- if c == '_' { continue }
- say(&format!("invalid character `{}` in crate name: `{}`", c, s));
- }
- }
-
- if err_count > 0 {
- sess.unwrap().abort_if_errors();
- }
-}
-
-/// A dummy crate store that does not support any non-local crates,
-/// for test purposes.
-pub struct DummyCrateStore;
-
-#[allow(unused_variables)]
-impl CrateStore for DummyCrateStore {
- fn crate_data_as_rc_any(&self, krate: CrateNum) -> Lrc<dyn Any>
- { bug!("crate_data_as_rc_any") }
- // item info
- fn visibility_untracked(&self, def: DefId) -> ty::Visibility { bug!("visibility") }
- fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics
- { bug!("item_generics_cloned") }
-
- // trait/impl-item info
- fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem
- { bug!("associated_item_cloned") }
-
- // crate metadata
- fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind { bug!("is_explicitly_linked") }
- fn export_macros_untracked(&self, cnum: CrateNum) { bug!("export_macros") }
- fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol { bug!("crate_name") }
- fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator {
- bug!("crate_disambiguator")
- }
- fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh { bug!("crate_hash") }
- fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition { bug!("crate_edition_untracked") }
-
- // resolve
- fn def_key(&self, def: DefId) -> DefKey { bug!("def_key") }
- fn def_path(&self, def: DefId) -> hir_map::DefPath {
- bug!("relative_def_path")
- }
- fn def_path_hash(&self, def: DefId) -> hir_map::DefPathHash {
- bug!("def_path_hash")
- }
- fn def_path_table(&self, cnum: CrateNum) -> Lrc<DefPathTable> {
- bug!("def_path_table")
- }
- fn struct_field_names_untracked(&self, def: DefId) -> Vec<ast::Name> {
- bug!("struct_field_names")
- }
- fn item_children_untracked(&self, did: DefId, sess: &Session) -> Vec<def::Export> {
- bug!("item_children")
- }
- fn load_macro_untracked(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
-
- fn crates_untracked(&self) -> Vec<CrateNum> { vec![] }
-
- // utility functions
- fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum> { None }
- fn encode_metadata<'a, 'tcx>(&self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- link_meta: &LinkMeta)
- -> EncodedMetadata {
- bug!("encode_metadata")
- }
- fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") }
- fn postorder_cnums_untracked(&self) -> Vec<CrateNum> { bug!("postorder_cnums_untracked") }
-
- // access to the metadata loader
- fn metadata_loader(&self) -> &dyn MetadataLoader { bug!("metadata_loader") }
-}
-
-pub trait CrateLoader {
- fn process_extern_crate(&mut self, item: &ast::Item, defs: &Definitions) -> CrateNum;
-
- fn process_path_extern(
- &mut self,
- name: Symbol,
- span: Span,
- ) -> CrateNum;
-
- fn process_use_extern(
- &mut self,
- name: Symbol,
- span: Span,
- id: ast::NodeId,
- defs: &Definitions,
- ) -> CrateNum;
-
- fn postprocess(&mut self, krate: &ast::Crate);
-}
-
// This method is used when generating the command line to pass through to
// system linker. The linker expects undefined symbols on the left of the
// command line to be defined in libraries on the right, not the other way
let preferred_linkage = match ty {
// cdylibs must have all static dependencies.
- config::CrateTypeCdylib => Linkage::Static,
+ config::CrateType::Cdylib => Linkage::Static,
// Generating a dylib without `-C prefer-dynamic` means that we're going
// to try to eagerly statically link all dependencies. This is normally
// done for end-product dylibs, not intermediate products.
- config::CrateTypeDylib if !sess.opts.cg.prefer_dynamic => Linkage::Static,
- config::CrateTypeDylib => Linkage::Dynamic,
+ config::CrateType::Dylib if !sess.opts.cg.prefer_dynamic => Linkage::Static,
+ config::CrateType::Dylib => Linkage::Dynamic,
// If the global prefer_dynamic switch is turned off, or the final
// executable will be statically linked, prefer static crate linkage.
- config::CrateTypeExecutable if !sess.opts.cg.prefer_dynamic ||
+ config::CrateType::Executable if !sess.opts.cg.prefer_dynamic ||
sess.crt_static() => Linkage::Static,
- config::CrateTypeExecutable => Linkage::Dynamic,
+ config::CrateType::Executable => Linkage::Dynamic,
// proc-macro crates are required to be dylibs, and they're currently
// required to link to libsyntax as well.
- config::CrateTypeProcMacro => Linkage::Dynamic,
+ config::CrateType::ProcMacro => Linkage::Dynamic,
// No linkage happens with rlibs, we just needed the metadata (which we
// got long ago), so don't bother with anything.
- config::CrateTypeRlib => Linkage::NotLinked,
+ config::CrateType::Rlib => Linkage::NotLinked,
// staticlibs must have all static dependencies.
- config::CrateTypeStaticlib => Linkage::Static,
+ config::CrateType::Staticlib => Linkage::Static,
};
if preferred_linkage == Linkage::NotLinked {
// Staticlibs, cdylibs, and static executables must have all static
// dependencies. If any are not found, generate some nice pretty errors.
- if ty == config::CrateTypeCdylib || ty == config::CrateTypeStaticlib ||
- (ty == config::CrateTypeExecutable && sess.crt_static() &&
+ if ty == config::CrateType::Cdylib || ty == config::CrateType::Staticlib ||
+ (ty == config::CrateType::Executable && sess.crt_static() &&
!sess.target.target.options.crt_static_allows_dylibs) {
for &cnum in tcx.crates().iter() {
if tcx.dep_kind(cnum).macros_only() { continue }
use hir::map as hir_map;
use hir::def_id::{CRATE_DEF_INDEX};
use session::{config, Session};
+use session::config::EntryFnType;
use syntax::ast::NodeId;
use syntax::attr;
use syntax::entry::EntryPointType;
hir_map: &hir_map::Map,
crate_name: &str) {
let any_exe = session.crate_types.borrow().iter().any(|ty| {
- *ty == config::CrateTypeExecutable
+ *ty == config::CrateType::Executable
});
if !any_exe {
// No need to find a main function
fn configure_main(this: &mut EntryContext, crate_name: &str) {
if let Some((node_id, span)) = this.start_fn {
- this.session.entry_fn.set(Some((node_id, span, config::EntryStart)));
+ this.session.entry_fn.set(Some((node_id, span, EntryFnType::Start)));
} else if let Some((node_id, span)) = this.attr_main_fn {
- this.session.entry_fn.set(Some((node_id, span, config::EntryMain)));
+ this.session.entry_fn.set(Some((node_id, span, EntryFnType::Main)));
} else if let Some((node_id, span)) = this.main_fn {
- this.session.entry_fn.set(Some((node_id, span, config::EntryMain)));
+ this.session.entry_fn.set(Some((node_id, span, EntryFnType::Main)));
} else {
// No main function
this.session.entry_fn.set(None);
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
- *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib ||
- *ty == config::CrateTypeProcMacro
+ *ty == config::CrateType::Rlib || *ty == config::CrateType::Dylib ||
+ *ty == config::CrateType::ProcMacro
});
let mut reachable_context = ReachableContext {
tcx,
// emitting something that's not an rlib.
let needs_check = tcx.sess.crate_types.borrow().iter().any(|kind| {
match *kind {
- config::CrateTypeDylib |
- config::CrateTypeProcMacro |
- config::CrateTypeCdylib |
- config::CrateTypeExecutable |
- config::CrateTypeStaticlib => true,
- config::CrateTypeRlib => false,
+ config::CrateType::Dylib |
+ config::CrateType::ProcMacro |
+ config::CrateType::Cdylib |
+ config::CrateType::Executable |
+ config::CrateType::Staticlib => true,
+ config::CrateType::Rlib => false,
}
});
if !needs_check {
FrameInfo, ConstEvalResult,
};
-pub use self::value::{Scalar, Value, ConstValue};
+pub use self::value::{Scalar, Value, ConstValue, ScalarMaybeUndef};
use std::fmt;
use mir;
/// to allow HIR creation to happen for everything before needing to be able to run constant
/// evaluation
Unevaluated(DefId, &'tcx Substs<'tcx>),
- /// Used only for types with layout::abi::Scalar ABI and ZSTs which use Scalar::undef()
+ /// Used only for types with layout::abi::Scalar ABI and ZSTs
Scalar(Scalar),
/// Used only for types with layout::abi::ScalarPair
- ScalarPair(Scalar, Scalar),
+ ///
+ /// The second field may be undef in case of `Option<usize>::None`
+ ScalarPair(Scalar, ScalarMaybeUndef),
/// Used only for the remaining cases. An allocation + offset into the allocation
ByRef(&'tcx Allocation, Size),
}
impl<'tcx> ConstValue<'tcx> {
#[inline]
- pub fn from_byval_value(val: Value) -> Self {
- match val {
+ pub fn from_byval_value(val: Value) -> EvalResult<'static, Self> {
+ Ok(match val {
Value::ByRef(..) => bug!(),
- Value::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
- Value::Scalar(val) => ConstValue::Scalar(val),
- }
+ Value::ScalarPair(a, b) => ConstValue::ScalarPair(a.unwrap_or_err()?, b),
+ Value::Scalar(val) => ConstValue::Scalar(val.unwrap_or_err()?),
+ })
}
#[inline]
match *self {
ConstValue::Unevaluated(..) |
ConstValue::ByRef(..) => None,
- ConstValue::ScalarPair(a, b) => Some(Value::ScalarPair(a, b)),
- ConstValue::Scalar(val) => Some(Value::Scalar(val)),
+ ConstValue::ScalarPair(a, b) => Some(Value::ScalarPair(a.into(), b)),
+ ConstValue::Scalar(val) => Some(Value::Scalar(val.into())),
}
}
#[inline]
- pub fn from_scalar(val: Scalar) -> Self {
- ConstValue::Scalar(val)
- }
-
- #[inline]
- pub fn to_scalar(&self) -> Option<Scalar> {
+ pub fn try_to_scalar(&self) -> Option<Scalar> {
match *self {
ConstValue::Unevaluated(..) |
ConstValue::ByRef(..) |
#[inline]
pub fn to_bits(&self, size: Size) -> Option<u128> {
- self.to_scalar()?.to_bits(size).ok()
+ self.try_to_scalar()?.to_bits(size).ok()
}
#[inline]
pub fn to_ptr(&self) -> Option<Pointer> {
- self.to_scalar()?.to_ptr().ok()
+ self.try_to_scalar()?.to_ptr().ok()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Value {
ByRef(Scalar, Align),
- Scalar(Scalar),
- ScalarPair(Scalar, Scalar),
+ Scalar(ScalarMaybeUndef),
+ ScalarPair(ScalarMaybeUndef, ScalarMaybeUndef),
}
impl<'tcx> ty::TypeFoldable<'tcx> for Value {
pub fn ptr_null<C: HasDataLayout>(cx: C) -> Self {
Scalar::Bits {
bits: 0,
- defined: cx.data_layout().pointer_size.bits() as u8,
+ size: cx.data_layout().pointer_size.bytes() as u8,
}
}
+ pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
+ ScalarMaybeUndef::Scalar(self).to_value_with_len(len, cx)
+ }
+
+ pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
+ ScalarMaybeUndef::Scalar(self).to_value_with_vtable(vtable)
+ }
+
pub fn ptr_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
let layout = cx.data_layout();
match self {
- Scalar::Bits { bits, defined } => {
- let pointer_size = layout.pointer_size.bits() as u8;
- if defined < pointer_size {
- err!(ReadUndefBytes)
- } else {
- Ok(Scalar::Bits {
- bits: layout.signed_offset(bits as u64, i)? as u128,
- defined: pointer_size,
- })
- }
+ Scalar::Bits { bits, size } => {
+ assert_eq!(size as u64, layout.pointer_size.bytes());
+ Ok(Scalar::Bits {
+ bits: layout.signed_offset(bits as u64, i)? as u128,
+ size,
+ })
}
Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
}
pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
let layout = cx.data_layout();
match self {
- Scalar::Bits { bits, defined } => {
- let pointer_size = layout.pointer_size.bits() as u8;
- if defined < pointer_size {
- err!(ReadUndefBytes)
- } else {
- Ok(Scalar::Bits {
- bits: layout.offset(bits as u64, i.bytes())? as u128,
- defined: pointer_size,
- })
- }
+ Scalar::Bits { bits, size } => {
+ assert_eq!(size as u64, layout.pointer_size.bytes());
+ Ok(Scalar::Bits {
+ bits: layout.offset(bits as u64, i.bytes())? as u128,
+ size,
+ })
}
Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
}
}
- pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
+ pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
let layout = cx.data_layout();
match self {
- Scalar::Bits { bits, defined } => {
- let pointer_size = layout.pointer_size.bits() as u8;
- if defined < pointer_size {
- err!(ReadUndefBytes)
- } else {
- Ok(Scalar::Bits {
- bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
- defined: pointer_size,
- })
- }
+ Scalar::Bits { bits, size } => {
+ assert_eq!(size as u64, layout.pointer_size.bytes());
+ Scalar::Bits {
+ bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
+ size,
+ }
}
- Scalar::Ptr(ptr) => Ok(Scalar::Ptr(ptr.wrapping_signed_offset(i, layout))),
+ Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, layout)),
}
}
- pub fn is_null_ptr<C: HasDataLayout>(self, cx: C) -> EvalResult<'tcx, bool> {
+ pub fn is_null_ptr<C: HasDataLayout>(self, cx: C) -> bool {
match self {
- Scalar::Bits {
- bits, defined,
- } => if defined < cx.data_layout().pointer_size.bits() as u8 {
- err!(ReadUndefBytes)
- } else {
- Ok(bits == 0)
+ Scalar::Bits { bits, size } => {
+ assert_eq!(size as u64, cx.data_layout().pointer_size.bytes());
+ bits == 0
},
- Scalar::Ptr(_) => Ok(false),
+ Scalar::Ptr(_) => false,
}
}
- pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
- Value::ScalarPair(self, Scalar::Bits {
- bits: len as u128,
- defined: cx.data_layout().pointer_size.bits() as u8,
- })
- }
-
- pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
- Value::ScalarPair(self, Scalar::Ptr(vtable))
- }
-
pub fn to_value(self) -> Value {
- Value::Scalar(self)
+ Value::Scalar(ScalarMaybeUndef::Scalar(self))
}
}
pub enum Scalar {
/// The raw bytes of a simple value.
Bits {
- /// The first `defined` number of bits are valid
- defined: u8,
+ /// The first `size` bytes are the value.
+ /// Do not try to read less or more bytes that that
+ size: u8,
bits: u128,
},
Ptr(Pointer),
}
-impl<'tcx> Scalar {
- pub fn undef() -> Self {
- Scalar::Bits { bits: 0, defined: 0 }
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
+pub enum ScalarMaybeUndef {
+ Scalar(Scalar),
+ Undef,
+}
+
+impl From<Scalar> for ScalarMaybeUndef {
+ fn from(s: Scalar) -> Self {
+ ScalarMaybeUndef::Scalar(s)
+ }
+}
+
+impl ScalarMaybeUndef {
+ pub fn unwrap_or_err(self) -> EvalResult<'static, Scalar> {
+ match self {
+ ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
+ ScalarMaybeUndef::Undef => err!(ReadUndefBytes),
+ }
+ }
+
+ pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
+ Value::ScalarPair(self, Scalar::Bits {
+ bits: len as u128,
+ size: cx.data_layout().pointer_size.bytes() as u8,
+ }.into())
}
+ pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
+ Value::ScalarPair(self, Scalar::Ptr(vtable).into())
+ }
+
+ pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
+ match self {
+ ScalarMaybeUndef::Scalar(scalar) => {
+ scalar.ptr_offset(i, cx).map(ScalarMaybeUndef::Scalar)
+ },
+ ScalarMaybeUndef::Undef => Ok(ScalarMaybeUndef::Undef)
+ }
+ }
+}
+
+impl<'tcx> Scalar {
pub fn from_bool(b: bool) -> Self {
- // FIXME: can we make defined `1`?
- Scalar::Bits { bits: b as u128, defined: 8 }
+ Scalar::Bits { bits: b as u128, size: 1 }
}
pub fn from_char(c: char) -> Self {
- Scalar::Bits { bits: c as u128, defined: 32 }
+ Scalar::Bits { bits: c as u128, size: 4 }
}
- pub fn to_bits(self, size: Size) -> EvalResult<'tcx, u128> {
+ pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
match self {
- Scalar::Bits { .. } if size.bits() == 0 => bug!("to_bits cannot be used with zsts"),
- Scalar::Bits { bits, defined } if size.bits() <= defined as u64 => Ok(bits),
- Scalar::Bits { .. } => err!(ReadUndefBytes),
+ Scalar::Bits { bits, size } => {
+ assert_eq!(target_size.bytes(), size as u64);
+ assert_ne!(size, 0, "to_bits cannot be used with zsts");
+ Ok(bits)
+ }
Scalar::Ptr(_) => err!(ReadPointerAsBytes),
}
}
pub fn to_bool(self) -> EvalResult<'tcx, bool> {
match self {
- Scalar::Bits { bits: 0, defined: 8 } => Ok(false),
- Scalar::Bits { bits: 1, defined: 8 } => Ok(true),
+ Scalar::Bits { bits: 0, size: 1 } => Ok(false),
+ Scalar::Bits { bits: 1, size: 1 } => Ok(true),
_ => err!(InvalidBool),
}
}
use hir::def_id::DefId;
use hir::{self, HirId, InlineAsm};
use middle::region;
-use mir::interpret::{EvalErrorKind, Scalar, Value};
+use mir::interpret::{EvalErrorKind, Scalar, Value, ScalarMaybeUndef};
use mir::visit::MirVisitable;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
.map(|&u| {
let mut s = String::new();
print_miri_value(
- Value::Scalar(Scalar::Bits {
+ Scalar::Bits {
bits: u,
- defined: size.bits() as u8,
- }),
+ size: size.bytes() as u8,
+ }.to_value(),
switch_ty,
&mut s,
).unwrap();
pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result {
use ty::TypeVariants::*;
- match (value, &ty.sty) {
- (Value::Scalar(Scalar::Bits { bits: 0, .. }), &TyBool) => write!(f, "false"),
- (Value::Scalar(Scalar::Bits { bits: 1, .. }), &TyBool) => write!(f, "true"),
- (Value::Scalar(Scalar::Bits { bits, .. }), &TyFloat(ast::FloatTy::F32)) => {
- write!(f, "{}f32", Single::from_bits(bits))
- }
- (Value::Scalar(Scalar::Bits { bits, .. }), &TyFloat(ast::FloatTy::F64)) => {
- write!(f, "{}f64", Double::from_bits(bits))
- }
- (Value::Scalar(Scalar::Bits { bits, .. }), &TyUint(ui)) => write!(f, "{:?}{}", bits, ui),
- (Value::Scalar(Scalar::Bits { bits, .. }), &TyInt(i)) => {
- let bit_width = ty::tls::with(|tcx| {
- let ty = tcx.lift_to_global(&ty).unwrap();
- tcx.layout_of(ty::ParamEnv::empty().and(ty))
- .unwrap()
- .size
- .bits()
- });
- let shift = 128 - bit_width;
- write!(f, "{:?}{}", ((bits as i128) << shift) >> shift, i)
- }
- (Value::Scalar(Scalar::Bits { bits, .. }), &TyChar) => {
- write!(f, "{:?}", ::std::char::from_u32(bits as u32).unwrap())
+ // print some primitives
+ if let Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { bits, .. })) = value {
+ match ty.sty {
+ TyBool if bits == 0 => return write!(f, "false"),
+ TyBool if bits == 1 => return write!(f, "true"),
+ TyFloat(ast::FloatTy::F32) => return write!(f, "{}f32", Single::from_bits(bits)),
+ TyFloat(ast::FloatTy::F64) => return write!(f, "{}f64", Double::from_bits(bits)),
+ TyUint(ui) => return write!(f, "{:?}{}", bits, ui),
+ TyInt(i) => {
+ let bit_width = ty::tls::with(|tcx| {
+ let ty = tcx.lift_to_global(&ty).unwrap();
+ tcx.layout_of(ty::ParamEnv::empty().and(ty))
+ .unwrap()
+ .size
+ .bits()
+ });
+ let shift = 128 - bit_width;
+ return write!(f, "{:?}{}", ((bits as i128) << shift) >> shift, i);
+ }
+ TyChar => return write!(f, "{:?}", ::std::char::from_u32(bits as u32).unwrap()),
+ _ => {},
}
- (_, &TyFnDef(did, _)) => write!(f, "{}", item_path_str(did)),
- (
- Value::ScalarPair(Scalar::Ptr(ptr), Scalar::Bits { bits: len, .. }),
- &TyRef(_, &ty::TyS { sty: TyStr, .. }, _),
- ) => ty::tls::with(|tcx| match tcx.alloc_map.lock().get(ptr.alloc_id) {
- Some(interpret::AllocType::Memory(alloc)) => {
- assert_eq!(len as usize as u128, len);
- let slice = &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
- let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
- write!(f, "{:?}", s)
+ }
+ // print function definitons
+ if let TyFnDef(did, _) = ty.sty {
+ return write!(f, "{}", item_path_str(did));
+ }
+ // print string literals
+ if let Value::ScalarPair(ptr, len) = value {
+ if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = ptr {
+ if let ScalarMaybeUndef::Scalar(Scalar::Bits { bits: len, .. }) = len {
+ if let TyRef(_, &ty::TyS { sty: TyStr, .. }, _) = ty.sty {
+ return ty::tls::with(|tcx| {
+ let alloc = tcx.alloc_map.lock().get(ptr.alloc_id);
+ if let Some(interpret::AllocType::Memory(alloc)) = alloc {
+ assert_eq!(len as usize as u128, len);
+ let slice = &alloc
+ .bytes
+ [(ptr.offset.bytes() as usize)..]
+ [..(len as usize)];
+ let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
+ write!(f, "{:?}", s)
+ } else {
+ write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len)
+ }
+ });
+ }
}
- _ => write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len),
- }),
- _ => write!(f, "{:?}:{}", value, ty),
+ }
}
+ // just raw dump everything else
+ write!(f, "{:?}:{}", value, ty)
}
fn item_path_str(def_id: DefId) -> String {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use super::*;
#[derive(Clone)]
pub struct Preorder<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
- visited: BitVector<BasicBlock>,
+ visited: BitArray<BasicBlock>,
worklist: Vec<BasicBlock>,
}
Preorder {
mir,
- visited: BitVector::new(mir.basic_blocks().len()),
+ visited: BitArray::new(mir.basic_blocks().len()),
worklist,
}
}
/// A Postorder traversal of this graph is `D B C A` or `D C B A`
pub struct Postorder<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
- visited: BitVector<BasicBlock>,
+ visited: BitArray<BasicBlock>,
visit_stack: Vec<(BasicBlock, Successors<'a>)>
}
pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> {
let mut po = Postorder {
mir,
- visited: BitVector::new(mir.basic_blocks().len()),
+ visited: BitArray::new(mir.basic_blocks().len()),
visit_stack: Vec::new()
};
//! Contains infrastructure for configuring the compiler, including parsing
//! command line options.
-pub use self::EntryFnType::*;
-pub use self::CrateType::*;
-pub use self::Passes::*;
-pub use self::DebugInfoLevel::*;
-
use std::str::FromStr;
use session::{early_error, early_warn, Session};
Thread,
}
-#[derive(Clone, Copy, PartialEq, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum OptLevel {
No, // -O0
Less, // -O1
}
#[derive(Clone, Copy, PartialEq, Hash)]
-pub enum DebugInfoLevel {
- NoDebugInfo,
- LimitedDebugInfo,
- FullDebugInfo,
+pub enum DebugInfo {
+ None,
+ Limited,
+ Full,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
// Include the debug_assertions flag into dependency tracking, since it
// can influence whether overflow checks are done or not.
debug_assertions: bool [TRACKED],
- debuginfo: DebugInfoLevel [TRACKED],
+ debuginfo: DebugInfo [TRACKED],
lint_opts: Vec<(String, lint::Level)> [TRACKED],
lint_cap: Option<lint::Level> [TRACKED],
describe_lints: bool [UNTRACKED],
(option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
}
-/// Some reasonable defaults
-pub fn basic_options() -> Options {
- Options {
- crate_types: Vec::new(),
- optimize: OptLevel::No,
- debuginfo: NoDebugInfo,
- lint_opts: Vec::new(),
- lint_cap: None,
- describe_lints: false,
- output_types: OutputTypes(BTreeMap::new()),
- search_paths: SearchPaths::new(),
- maybe_sysroot: None,
- target_triple: TargetTriple::from_triple(host_triple()),
- test: false,
- incremental: None,
- debugging_opts: basic_debugging_options(),
- prints: Vec::new(),
- borrowck_mode: BorrowckMode::Ast,
- cg: basic_codegen_options(),
- error_format: ErrorOutputType::default(),
- externs: Externs(BTreeMap::new()),
- crate_name: None,
- alt_std_name: None,
- libs: Vec::new(),
- unstable_features: UnstableFeatures::Disallow,
- debug_assertions: true,
- actually_rustdoc: false,
- cli_forced_codegen_units: None,
- cli_forced_thinlto_off: false,
- remap_path_prefix: Vec::new(),
- edition: DEFAULT_EDITION,
+impl Default for Options {
+ fn default() -> Options {
+ Options {
+ crate_types: Vec::new(),
+ optimize: OptLevel::No,
+ debuginfo: DebugInfo::None,
+ lint_opts: Vec::new(),
+ lint_cap: None,
+ describe_lints: false,
+ output_types: OutputTypes(BTreeMap::new()),
+ search_paths: SearchPaths::new(),
+ maybe_sysroot: None,
+ target_triple: TargetTriple::from_triple(host_triple()),
+ test: false,
+ incremental: None,
+ debugging_opts: basic_debugging_options(),
+ prints: Vec::new(),
+ borrowck_mode: BorrowckMode::Ast,
+ cg: basic_codegen_options(),
+ error_format: ErrorOutputType::default(),
+ externs: Externs(BTreeMap::new()),
+ crate_name: None,
+ alt_std_name: None,
+ libs: Vec::new(),
+ unstable_features: UnstableFeatures::Disallow,
+ debug_assertions: true,
+ actually_rustdoc: false,
+ cli_forced_codegen_units: None,
+ cli_forced_thinlto_off: false,
+ remap_path_prefix: Vec::new(),
+ edition: DEFAULT_EDITION,
+ }
}
}
!self.debugging_opts.parse_only && // The file is just being parsed
!self.debugging_opts.ls // The file is just being queried
}
+
+ #[inline]
+ pub fn share_generics(&self) -> bool {
+ match self.debugging_opts.share_generics {
+ Some(setting) => setting,
+ None => {
+ self.incremental.is_some() ||
+ match self.optimize {
+ OptLevel::No |
+ OptLevel::Less |
+ OptLevel::Size |
+ OptLevel::SizeMin => true,
+ OptLevel::Default |
+ OptLevel::Aggressive => false,
+ }
+ }
+ }
+ }
}
// The type of entry function, so
// functions
#[derive(Copy, Clone, PartialEq)]
pub enum EntryFnType {
- EntryMain,
- EntryStart,
+ Main,
+ Start,
}
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
pub enum CrateType {
- CrateTypeExecutable,
- CrateTypeDylib,
- CrateTypeRlib,
- CrateTypeStaticlib,
- CrateTypeCdylib,
- CrateTypeProcMacro,
+ Executable,
+ Dylib,
+ Rlib,
+ Staticlib,
+ Cdylib,
+ ProcMacro,
}
#[derive(Clone, Hash)]
pub enum Passes {
- SomePasses(Vec<String>),
- AllPasses,
+ Some(Vec<String>),
+ All,
}
impl Passes {
pub fn is_empty(&self) -> bool {
match *self {
- SomePasses(ref v) => v.is_empty(),
- AllPasses => false,
+ Passes::Some(ref v) => v.is_empty(),
+ Passes::All => false,
}
}
}
#[allow(dead_code)]
mod $mod_set {
- use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto,
- CrossLangLto};
+ use super::{$struct_name, Passes, Sanitizer, Lto, CrossLangLto};
use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
use std::path::PathBuf;
fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
match v {
Some("all") => {
- *slot = AllPasses;
+ *slot = Passes::All;
true
}
v => {
let mut passes = vec![];
if parse_list(&mut passes, v) {
- *slot = SomePasses(passes);
+ *slot = Passes::Some(passes);
true
} else {
false
"extra data to put in each output filename"),
codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
"divide crate into N units to optimize in parallel"),
- remark: Passes = (SomePasses(Vec::new()), parse_passes, [UNTRACKED],
+ remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
"print remarks for these optimization passes (space separated, or \"all\")"),
no_stack_check: bool = (false, parse_bool, [UNTRACKED],
"the --no-stack-check flag is deprecated and does nothing"),
"disables the 'leak check' for subtyping; unsound, but useful for tests"),
crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
"inject the given attribute in the crate"),
+ self_profile: bool = (false, parse_bool, [UNTRACKED],
+ "run the self profiler"),
+ profile_json: bool = (false, parse_bool, [UNTRACKED],
+ "output a json file with profiler results"),
}
pub fn default_lib_output() -> CrateType {
- CrateTypeRlib
+ CrateType::Rlib
}
pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
if sess.opts.debug_assertions {
ret.insert((Symbol::intern("debug_assertions"), None));
}
- if sess.opts.crate_types.contains(&CrateTypeProcMacro) {
+ if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
ret.insert((Symbol::intern("proc_macro"), None));
}
return ret;
if cg.debuginfo.is_some() {
early_error(error_format, "-g and -C debuginfo both provided");
}
- FullDebugInfo
+ DebugInfo::Full
} else {
match cg.debuginfo {
- None | Some(0) => NoDebugInfo,
- Some(1) => LimitedDebugInfo,
- Some(2) => FullDebugInfo,
+ None | Some(0) => DebugInfo::None,
+ Some(1) => DebugInfo::Limited,
+ Some(2) => DebugInfo::Full,
Some(arg) => {
early_error(
error_format,
Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
};
- if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
+ if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
early_warn(
error_format,
"-C remark will not show source locations without \
for part in unparsed_crate_type.split(',') {
let new_part = match part {
"lib" => default_lib_output(),
- "rlib" => CrateTypeRlib,
- "staticlib" => CrateTypeStaticlib,
- "dylib" => CrateTypeDylib,
- "cdylib" => CrateTypeCdylib,
- "bin" => CrateTypeExecutable,
- "proc-macro" => CrateTypeProcMacro,
+ "rlib" => CrateType::Rlib,
+ "staticlib" => CrateType::Staticlib,
+ "dylib" => CrateType::Dylib,
+ "cdylib" => CrateType::Cdylib,
+ "bin" => CrateType::Executable,
+ "proc-macro" => CrateType::ProcMacro,
_ => {
return Err(format!("unknown crate type: `{}`", part));
}
impl fmt::Display for CrateType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- CrateTypeExecutable => "bin".fmt(f),
- CrateTypeDylib => "dylib".fmt(f),
- CrateTypeRlib => "rlib".fmt(f),
- CrateTypeStaticlib => "staticlib".fmt(f),
- CrateTypeCdylib => "cdylib".fmt(f),
- CrateTypeProcMacro => "proc-macro".fmt(f),
+ CrateType::Executable => "bin".fmt(f),
+ CrateType::Dylib => "dylib".fmt(f),
+ CrateType::Rlib => "rlib".fmt(f),
+ CrateType::Staticlib => "staticlib".fmt(f),
+ CrateType::Cdylib => "cdylib".fmt(f),
+ CrateType::ProcMacro => "proc-macro".fmt(f),
}
}
}
use std::hash::Hash;
use std::path::PathBuf;
use std::collections::hash_map::DefaultHasher;
- use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes,
+ use super::{CrateType, DebugInfo, ErrorOutputType, Lto, OptLevel, OutputTypes,
Passes, Sanitizer, CrossLangLto};
use syntax::feature_gate::UnstableFeatures;
use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple};
impl_dep_tracking_hash_via_hash!(Passes);
impl_dep_tracking_hash_via_hash!(OptLevel);
impl_dep_tracking_hash_via_hash!(Lto);
- impl_dep_tracking_hash_via_hash!(DebugInfoLevel);
+ impl_dep_tracking_hash_via_hash!(DebugInfo);
impl_dep_tracking_hash_via_hash!(UnstableFeatures);
impl_dep_tracking_hash_via_hash!(OutputTypes);
impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
use syntax::symbol::Symbol;
use syntax::edition::{Edition, DEFAULT_EDITION};
use syntax;
+ use super::Options;
fn optgroups() -> getopts::Options {
let mut opts = getopts::Options::new();
#[test]
fn test_output_types_tracking_hash_different_paths() {
- let mut v1 = super::basic_options();
- let mut v2 = super::basic_options();
- let mut v3 = super::basic_options();
+ let mut v1 = Options::default();
+ let mut v2 = Options::default();
+ let mut v3 = Options::default();
v1.output_types =
OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]);
#[test]
fn test_output_types_tracking_hash_different_construction_order() {
- let mut v1 = super::basic_options();
- let mut v2 = super::basic_options();
+ let mut v1 = Options::default();
+ let mut v2 = Options::default();
v1.output_types = OutputTypes::new(&[
(OutputType::Exe, Some(PathBuf::from("./some/thing"))),
#[test]
fn test_externs_tracking_hash_different_construction_order() {
- let mut v1 = super::basic_options();
- let mut v2 = super::basic_options();
- let mut v3 = super::basic_options();
+ let mut v1 = Options::default();
+ let mut v2 = Options::default();
+ let mut v3 = Options::default();
v1.externs = Externs::new(mk_map(vec![
(
#[test]
fn test_lints_tracking_hash_different_values() {
- let mut v1 = super::basic_options();
- let mut v2 = super::basic_options();
- let mut v3 = super::basic_options();
+ let mut v1 = Options::default();
+ let mut v2 = Options::default();
+ let mut v3 = Options::default();
v1.lint_opts = vec![
(String::from("a"), lint::Allow),
#[test]
fn test_lints_tracking_hash_different_construction_order() {
- let mut v1 = super::basic_options();
- let mut v2 = super::basic_options();
+ let mut v1 = Options::default();
+ let mut v2 = Options::default();
v1.lint_opts = vec![
(String::from("a"), lint::Allow),
#[test]
fn test_search_paths_tracking_hash_different_order() {
- let mut v1 = super::basic_options();
- let mut v2 = super::basic_options();
- let mut v3 = super::basic_options();
- let mut v4 = super::basic_options();
+ let mut v1 = Options::default();
+ let mut v2 = Options::default();
+ let mut v3 = Options::default();
+ let mut v4 = Options::default();
// Reference
v1.search_paths
#[test]
fn test_native_libs_tracking_hash_different_values() {
- let mut v1 = super::basic_options();
- let mut v2 = super::basic_options();
- let mut v3 = super::basic_options();
- let mut v4 = super::basic_options();
+ let mut v1 = Options::default();
+ let mut v2 = Options::default();
+ let mut v3 = Options::default();
+ let mut v4 = Options::default();
// Reference
v1.libs = vec![
#[test]
fn test_native_libs_tracking_hash_different_order() {
- let mut v1 = super::basic_options();
- let mut v2 = super::basic_options();
- let mut v3 = super::basic_options();
+ let mut v1 = Options::default();
+ let mut v2 = Options::default();
+ let mut v3 = Options::default();
// Reference
v1.libs = vec![
#[test]
fn test_codegen_options_tracking_hash() {
- let reference = super::basic_options();
- let mut opts = super::basic_options();
+ let reference = Options::default();
+ let mut opts = Options::default();
// Make sure the changing an [UNTRACKED] option leaves the hash unchanged
opts.cg.ar = Some(String::from("abc"));
opts.cg.codegen_units = Some(42);
assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
- opts.cg.remark = super::SomePasses(vec![String::from("pass1"), String::from("pass2")]);
+ opts.cg.remark = super::Passes::Some(vec![String::from("pass1"), String::from("pass2")]);
assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
opts.cg.save_temps = true;
#[test]
fn test_debugging_options_tracking_hash() {
- let reference = super::basic_options();
- let mut opts = super::basic_options();
+ let reference = Options::default();
+ let mut opts = Options::default();
// Make sure the changing an [UNTRACKED] option leaves the hash unchanged
opts.debugging_opts.verbose = true;
#[test]
fn test_edition_parsing() {
// test default edition
- let options = super::basic_options();
+ let options = Options::default();
assert!(options.edition == DEFAULT_EDITION);
let matches = optgroups()
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo};
-pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo};
+pub use self::code_stats::{DataTypeKind, SizeKind, FieldInfo, VariantInfo};
+use self::code_stats::CodeStats;
use hir::def_id::CrateNum;
use ich::Fingerprint;
use syntax::{ast, codemap};
use syntax::feature_gate::AttributeType;
use syntax_pos::{MultiSpan, Span};
+use util::profiling::SelfProfiler;
use rustc_target::spec::{LinkerFlavor, PanicStrategy};
use rustc_target::spec::{Target, TargetTriple};
/// Used by -Z profile-queries in util::common
pub profile_channel: Lock<Option<mpsc::Sender<ProfileQueriesMsg>>>,
+ /// Used by -Z self-profile
+ pub self_profiling: Lock<SelfProfiler>,
+
/// Some measurements that are being gathered during compilation.
pub perf_stats: PerfStats,
}
}
+ pub fn profiler<F: FnOnce(&mut SelfProfiler) -> ()>(&self, f: F) {
+ let mut profiler = self.self_profiling.borrow_mut();
+ f(&mut profiler);
+ }
+
+ pub fn print_profiler_results(&self) {
+ let mut profiler = self.self_profiling.borrow_mut();
+ profiler.print_results(&self.opts);
+ }
+
+ pub fn save_json_results(&self) {
+ let profiler = self.self_profiling.borrow();
+ profiler.save_results(&self.opts);
+ }
+
pub fn print_perf_stats(&self) {
println!(
"Total time spent computing symbol hashes: {}",
}
pub fn teach(&self, code: &DiagnosticId) -> bool {
- self.opts.debugging_opts.teach && self.parse_sess.span_diagnostic.must_teach(code)
+ self.opts.debugging_opts.teach && self.diagnostic().must_teach(code)
}
/// Are we allowed to use features from the Rust 2018 edition?
imported_macro_spans: OneThread::new(RefCell::new(HashMap::new())),
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
ignored_attr_names: ich::compute_ignored_attr_names(),
+ self_profiling: Lock::new(SelfProfiler::new()),
profile_channel: Lock::new(None),
perf_stats: PerfStats {
symbol_hash_time: Lock::new(Duration::from_secs(0)),
use mir::interpret::{GlobalId};
use rustc_data_structures::sync::Lock;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use std::iter;
use std::cmp;
use std::fmt;
} else {
return Err(Unimplemented);
};
- let mut ty_params = BitVector::new(substs_a.types().count());
+ let mut ty_params = BitArray::new(substs_a.types().count());
let mut found = false;
for ty in field.walk() {
if let ty::TyParam(p) = ty.sty {
use dep_graph::{DepNode, DepConstructor};
use errors::DiagnosticBuilder;
use session::Session;
-use session::config::{BorrowckMode, OutputFilenames, OptLevel};
-use session::config::CrateType::*;
+use session::config::{BorrowckMode, OutputFilenames};
+use session::config::CrateType;
use middle;
use hir::{TraitCandidate, HirId, ItemLocalId};
use hir::def::{Def, Export};
}
/// If true, we should enable two-phase borrows checks. This is
- /// done with either `-Ztwo-phase-borrows` or with
- /// `#![feature(nll)]`.
+ /// done with either: `-Ztwo-phase-borrows`, `#![feature(nll)]`,
+ /// or by opting into an edition after 2015.
pub fn two_phase_borrows(self) -> bool {
- self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows
+ if self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows {
+ return true;
+ }
+
+ match self.sess.edition() {
+ Edition::Edition2015 => false,
+ Edition::Edition2018 => true,
+ _ => true,
+ }
}
/// What mode(s) of borrowck should we run? AST? MIR? both?
self.use_mir_borrowck()
}
- #[inline]
- pub fn share_generics(self) -> bool {
- match self.sess.opts.debugging_opts.share_generics {
- Some(setting) => setting,
- None => {
- self.sess.opts.incremental.is_some() ||
- match self.sess.opts.optimize {
- OptLevel::No |
- OptLevel::Less |
- OptLevel::Size |
- OptLevel::SizeMin => true,
- OptLevel::Default |
- OptLevel::Aggressive => false,
- }
- }
- }
- }
-
#[inline]
pub fn local_crate_exports_generics(self) -> bool {
- debug_assert!(self.share_generics());
+ debug_assert!(self.sess.opts.share_generics());
self.sess.crate_types.borrow().iter().any(|crate_type| {
match crate_type {
- CrateTypeExecutable |
- CrateTypeStaticlib |
- CrateTypeProcMacro |
- CrateTypeCdylib => false,
- CrateTypeRlib |
- CrateTypeDylib => true,
+ CrateType::Executable |
+ CrateType::Staticlib |
+ CrateType::ProcMacro |
+ CrateType::Cdylib => false,
+ CrateType::Rlib |
+ CrateType::Dylib => true,
}
})
}
use ty::query::queries;
use ty::query::Query;
use ty::query::QueryCache;
+use util::profiling::ProfileCategory;
use std::hash::Hash;
use std::fmt::Debug;
pub trait QueryConfig<'tcx> {
const NAME: &'static str;
+ const CATEGORY: ProfileCategory;
type Key: Eq + Hash + Clone + Debug;
type Value: Clone + for<'a> HashStable<StableHashingContext<'a>>;
use ty::subst::Substs;
use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};
use util::common::{ErrorReported};
+use util::profiling::ProfileCategory::*;
use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_target::spec::PanicStrategy;
let mut lock = cache.borrow_mut();
if let Some(value) = lock.results.get(key) {
profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
+ tcx.sess.profiler(|p| {
+ p.record_query(Q::CATEGORY);
+ p.record_query_hit(Q::CATEGORY);
+ });
+
let result = Ok((value.value.clone(), value.index));
return TryGetJob::JobCompleted(result);
}
)
);
+ self.sess.profiler(|p| p.record_query(Q::CATEGORY));
+
let job = match JobOwner::try_get(self, span, &key) {
TryGetJob::NotYetStarted(job) => job,
TryGetJob::JobCompleted(result) => {
return result.map(|(v, index)| {
+ self.sess.profiler(|p| p.record_query_hit(Q::CATEGORY));
self.dep_graph.read_index(index);
v
})
if dep_node.kind.is_anon() {
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
+ self.sess.profiler(|p| p.start_activity(Q::CATEGORY));
let res = job.start(self, |tcx| {
tcx.dep_graph.with_anon_task(dep_node.kind, || {
})
});
+ self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
let ((result, dep_node_index), diagnostics) = res;
if !dep_node.kind.is_input() {
if let Some(dep_node_index) = self.try_mark_green_and_read(&dep_node) {
profq_msg!(self, ProfileQueriesMsg::CacheHit);
+ self.sess.profiler(|p| p.record_query_hit(Q::CATEGORY));
+
return self.load_from_disk_and_cache_in_memory::<Q>(key,
job,
dep_node_index,
key, dep_node);
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
+ self.sess.profiler(|p| {
+ p.start_activity(Q::CATEGORY);
+ p.record_query(Q::CATEGORY);
+ });
+
let res = job.start(self, |tcx| {
if dep_node.kind.is_eval_always() {
tcx.dep_graph.with_eval_always_task(dep_node,
Q::compute)
}
});
+
+ self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
let ((result, dep_node_index), diagnostics) = res;
// DepNodeIndex. We must invoke the query itself. The performance cost
// this introduces should be negligible as we'll immediately hit the
// in-memory cache, or another query down the line will.
+
+ self.sess.profiler(|p| {
+ p.start_activity(Q::CATEGORY);
+ p.record_query(Q::CATEGORY);
+ });
+
let _ = self.get_query::<Q>(DUMMY_SP, key);
+
+ self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
}
}
rustc_data_structures::stable_hasher::StableHasher,
ich::StableHashingContext
};
+ use util::profiling::ProfileCategory;
define_queries_struct! {
tcx: $tcx,
type Value = $V;
const NAME: &'static str = stringify!($name);
+ const CATEGORY: ProfileCategory = $category;
}
impl<$tcx> QueryAccessors<$tcx> for queries::$name<$tcx> {
})
}
- #[inline]
- pub fn from_byval_value(
- tcx: TyCtxt<'_, '_, 'tcx>,
- val: Value,
- ty: Ty<'tcx>,
- ) -> &'tcx Self {
- Self::from_const_value(tcx, ConstValue::from_byval_value(val), ty)
- }
-
#[inline]
pub fn from_scalar(
tcx: TyCtxt<'_, '_, 'tcx>,
val: Scalar,
ty: Ty<'tcx>,
) -> &'tcx Self {
- Self::from_const_value(tcx, ConstValue::from_scalar(val), ty)
+ Self::from_const_value(tcx, ConstValue::Scalar(val), ty)
}
#[inline]
let shift = 128 - size.bits();
let truncated = (bits << shift) >> shift;
assert_eq!(truncated, bits, "from_bits called with untruncated value");
- Self::from_scalar(tcx, Scalar::Bits { bits, defined: size.bits() as u8 }, ty.value)
+ Self::from_scalar(tcx, Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value)
}
#[inline]
pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
- Self::from_scalar(tcx, Scalar::undef(), ty)
+ Self::from_scalar(tcx, Scalar::Bits { bits: 0, size: 0 }, ty)
}
#[inline]
self.val.to_byval_value()
}
- #[inline]
- pub fn to_scalar(&self) -> Option<Scalar> {
- self.val.to_scalar()
- }
-
#[inline]
pub fn assert_bits(
&self,
--- /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 session::config::Options;
+
+use std::fs;
+use std::io::{self, StdoutLock, Write};
+use std::time::Instant;
+
+macro_rules! define_categories {
+ ($($name:ident,)*) => {
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
+ pub enum ProfileCategory {
+ $($name),*
+ }
+
+ #[allow(bad_style)]
+ struct Categories<T> {
+ $($name: T),*
+ }
+
+ impl<T: Default> Categories<T> {
+ fn new() -> Categories<T> {
+ Categories {
+ $($name: T::default()),*
+ }
+ }
+ }
+
+ impl<T> Categories<T> {
+ fn get(&self, category: ProfileCategory) -> &T {
+ match category {
+ $(ProfileCategory::$name => &self.$name),*
+ }
+ }
+
+ fn set(&mut self, category: ProfileCategory, value: T) {
+ match category {
+ $(ProfileCategory::$name => self.$name = value),*
+ }
+ }
+ }
+
+ struct CategoryData {
+ times: Categories<u64>,
+ query_counts: Categories<(u64, u64)>,
+ }
+
+ impl CategoryData {
+ fn new() -> CategoryData {
+ CategoryData {
+ times: Categories::new(),
+ query_counts: Categories::new(),
+ }
+ }
+
+ fn print(&self, lock: &mut StdoutLock) {
+ writeln!(lock, "| Phase | Time (ms) | Queries | Hits (%) |")
+ .unwrap();
+ writeln!(lock, "| ---------------- | -------------- | -------------- | -------- |")
+ .unwrap();
+
+ $(
+ let (hits, total) = self.query_counts.$name;
+ let (hits, total) = if total > 0 {
+ (format!("{:.2}",
+ (((hits as f32) / (total as f32)) * 100.0)), total.to_string())
+ } else {
+ ("".into(), "".into())
+ };
+
+ writeln!(
+ lock,
+ "| {0: <16} | {1: <14} | {2: <14} | {3: <8} |",
+ stringify!($name),
+ self.times.$name / 1_000_000,
+ total,
+ hits
+ ).unwrap();
+ )*
+ }
+
+ fn json(&self) -> String {
+ let mut json = String::from("[");
+
+ $(
+ let (hits, total) = self.query_counts.$name;
+
+ json.push_str(&format!(
+ "{{ \"category\": {}, \"time_ms\": {},
+ \"query_count\": {}, \"query_hits\": {} }}",
+ stringify!($name),
+ self.times.$name / 1_000_000,
+ total,
+ format!("{:.2}", (((hits as f32) / (total as f32)) * 100.0))
+ ));
+ )*
+
+ json.push(']');
+
+ json
+ }
+ }
+ }
+}
+
+define_categories! {
+ Parsing,
+ Expansion,
+ TypeChecking,
+ BorrowChecking,
+ Codegen,
+ Linking,
+ Other,
+}
+
+pub struct SelfProfiler {
+ timer_stack: Vec<ProfileCategory>,
+ data: CategoryData,
+ current_timer: Instant,
+}
+
+impl SelfProfiler {
+ pub fn new() -> SelfProfiler {
+ let mut profiler = SelfProfiler {
+ timer_stack: Vec::new(),
+ data: CategoryData::new(),
+ current_timer: Instant::now(),
+ };
+
+ profiler.start_activity(ProfileCategory::Other);
+
+ profiler
+ }
+
+ pub fn start_activity(&mut self, category: ProfileCategory) {
+ match self.timer_stack.last().cloned() {
+ None => {
+ self.current_timer = Instant::now();
+ },
+ Some(current_category) if current_category == category => {
+ //since the current category is the same as the new activity's category,
+ //we don't need to do anything with the timer, we just need to push it on the stack
+ }
+ Some(current_category) => {
+ let elapsed = self.stop_timer();
+
+ //record the current category's time
+ let new_time = self.data.times.get(current_category) + elapsed;
+ self.data.times.set(current_category, new_time);
+ }
+ }
+
+ //push the new category
+ self.timer_stack.push(category);
+ }
+
+ pub fn record_query(&mut self, category: ProfileCategory) {
+ let (hits, total) = *self.data.query_counts.get(category);
+ self.data.query_counts.set(category, (hits, total + 1));
+ }
+
+ pub fn record_query_hit(&mut self, category: ProfileCategory) {
+ let (hits, total) = *self.data.query_counts.get(category);
+ self.data.query_counts.set(category, (hits + 1, total));
+ }
+
+ pub fn end_activity(&mut self, category: ProfileCategory) {
+ match self.timer_stack.pop() {
+ None => bug!("end_activity() was called but there was no running activity"),
+ Some(c) =>
+ assert!(
+ c == category,
+ "end_activity() was called but a different activity was running"),
+ }
+
+ //check if the new running timer is in the same category as this one
+ //if it is, we don't need to do anything
+ if let Some(c) = self.timer_stack.last() {
+ if *c == category {
+ return;
+ }
+ }
+
+ //the new timer is different than the previous,
+ //so record the elapsed time and start a new timer
+ let elapsed = self.stop_timer();
+ let new_time = self.data.times.get(category) + elapsed;
+ self.data.times.set(category, new_time);
+ }
+
+ fn stop_timer(&mut self) -> u64 {
+ let elapsed = self.current_timer.elapsed();
+
+ self.current_timer = Instant::now();
+
+ (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64)
+ }
+
+ pub fn print_results(&mut self, opts: &Options) {
+ self.end_activity(ProfileCategory::Other);
+
+ assert!(
+ self.timer_stack.is_empty(),
+ "there were timers running when print_results() was called");
+
+ let out = io::stdout();
+ let mut lock = out.lock();
+
+ let crate_name =
+ opts.crate_name
+ .as_ref()
+ .map(|n| format!(" for {}", n))
+ .unwrap_or_default();
+
+ writeln!(lock, "Self profiling results{}:", crate_name).unwrap();
+ writeln!(lock).unwrap();
+
+ self.data.print(&mut lock);
+
+ writeln!(lock).unwrap();
+ writeln!(lock, "Optimization level: {:?}", opts.optimize).unwrap();
+
+ let incremental = if opts.incremental.is_some() { "on" } else { "off" };
+ writeln!(lock, "Incremental: {}", incremental).unwrap();
+ }
+
+ pub fn save_results(&self, opts: &Options) {
+ let category_data = self.data.json();
+ let compilation_options =
+ format!("{{ \"optimization_level\": \"{:?}\", \"incremental\": {} }}",
+ opts.optimize,
+ if opts.incremental.is_some() { "true" } else { "false" });
+
+ let json = format!("{{ \"category_data\": {}, \"compilation_options\": {} }}",
+ category_data,
+ compilation_options);
+
+ fs::write("self_profiler_results.json", json).unwrap();
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::{self, ValueRef, AttributePlace};
+use llvm::{self, AttributePlace};
use base;
use builder::{Builder, MemFlags};
use common::{ty_fn_sig, C_usize};
use mir::operand::OperandValue;
use type_::Type;
use type_of::{LayoutLlvmExt, PointerKind};
+use value::Value;
use rustc_target::abi::{LayoutOf, Size, TyLayout};
use rustc::ty::{self, Ty};
}
pub trait ArgAttributesExt {
- fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef);
- fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef);
+ fn apply_llfn(&self, idx: AttributePlace, llfn: &Value);
+ fn apply_callsite(&self, idx: AttributePlace, callsite: &Value);
}
impl ArgAttributesExt for ArgAttributes {
- fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
+ fn apply_llfn(&self, idx: AttributePlace, llfn: &Value) {
let mut regular = self.regular;
unsafe {
let deref = self.pointee_size.bytes();
}
}
- fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) {
+ fn apply_callsite(&self, idx: AttributePlace, callsite: &Value) {
let mut regular = self.regular;
unsafe {
let deref = self.pointee_size.bytes();
}
pub trait LlvmType {
- fn llvm_type(&self, cx: &CodegenCx) -> Type;
+ fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type;
}
impl LlvmType for Reg {
- fn llvm_type(&self, cx: &CodegenCx) -> Type {
+ fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
match self.kind {
RegKind::Integer => Type::ix(cx, self.size.bits()),
RegKind::Float => {
}
}
RegKind::Vector => {
- Type::vector(&Type::i8(cx), self.size.bytes())
+ Type::vector(Type::i8(cx), self.size.bytes())
}
}
}
}
impl LlvmType for CastTarget {
- fn llvm_type(&self, cx: &CodegenCx) -> Type {
+ fn llvm_type(&self, cx: &CodegenCx<'ll, '_>) -> &'ll Type {
let rest_ll_unit = self.rest.unit.llvm_type(cx);
let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 {
(0, 0)
// Simplify to array when all chunks are the same size and type
if rem_bytes == 0 {
- return Type::array(&rest_ll_unit, rest_count);
+ return Type::array(rest_ll_unit, rest_count);
}
}
}
}
-pub trait ArgTypeExt<'a, 'tcx> {
- fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type;
- fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>);
- fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>);
+pub trait ArgTypeExt<'ll, 'tcx> {
+ fn memory_ty(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
+ fn store(&self, bx: &Builder<'_, 'll, 'tcx>, val: &'ll Value, dst: PlaceRef<'ll, 'tcx>);
+ fn store_fn_arg(&self, bx: &Builder<'_, 'll, 'tcx>, idx: &mut usize, dst: PlaceRef<'ll, 'tcx>);
}
-impl<'a, 'tcx> ArgTypeExt<'a, 'tcx> for ArgType<'tcx, Ty<'tcx>> {
+impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> {
/// Get the LLVM type for a place of the original Rust type of
/// this argument/return, i.e. the result of `type_of::type_of`.
- fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type {
+ fn memory_ty(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
self.layout.llvm_type(cx)
}
/// place for the original Rust type of this argument/return.
/// Can be used for both storing formal arguments into Rust variables
/// or results of call/invoke instructions into their destinations.
- fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>) {
+ fn store(&self, bx: &Builder<'_, 'll, 'tcx>, val: &'ll Value, dst: PlaceRef<'ll, 'tcx>) {
if self.is_ignore() {
return;
}
}
}
- fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>) {
+ fn store_fn_arg(&self, bx: &Builder<'a, 'll, 'tcx>, idx: &mut usize, dst: PlaceRef<'ll, 'tcx>) {
let mut next = || {
let val = llvm::get_param(bx.llfn(), *idx as c_uint);
*idx += 1;
}
}
-pub trait FnTypeExt<'a, 'tcx> {
- fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>)
+pub trait FnTypeExt<'tcx> {
+ fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>)
-> Self;
- fn new(cx: &CodegenCx<'a, 'tcx>,
+ fn new(cx: &CodegenCx<'ll, 'tcx>,
sig: ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>]) -> Self;
- fn new_vtable(cx: &CodegenCx<'a, 'tcx>,
+ fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
sig: ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>]) -> Self;
fn new_internal(
- cx: &CodegenCx<'a, 'tcx>,
+ cx: &CodegenCx<'ll, 'tcx>,
sig: ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>],
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
) -> Self;
fn adjust_for_abi(&mut self,
- cx: &CodegenCx<'a, 'tcx>,
+ cx: &CodegenCx<'ll, 'tcx>,
abi: Abi);
- fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type;
+ fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn llvm_cconv(&self) -> llvm::CallConv;
- fn apply_attrs_llfn(&self, llfn: ValueRef);
- fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef);
+ fn apply_attrs_llfn(&self, llfn: &'ll Value);
+ fn apply_attrs_callsite(&self, bx: &Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
}
-impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> {
- fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>)
+impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
+ fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>)
-> Self {
let fn_ty = instance.ty(cx.tcx);
let sig = ty_fn_sig(cx, fn_ty);
FnType::new(cx, sig, &[])
}
- fn new(cx: &CodegenCx<'a, 'tcx>,
+ fn new(cx: &CodegenCx<'ll, 'tcx>,
sig: ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>]) -> Self {
FnType::new_internal(cx, sig, extra_args, |ty, _| {
})
}
- fn new_vtable(cx: &CodegenCx<'a, 'tcx>,
+ fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
sig: ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>]) -> Self {
FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| {
}
fn new_internal(
- cx: &CodegenCx<'a, 'tcx>,
+ cx: &CodegenCx<'ll, 'tcx>,
sig: ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>],
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
}
fn adjust_for_abi(&mut self,
- cx: &CodegenCx<'a, 'tcx>,
+ cx: &CodegenCx<'ll, 'tcx>,
abi: Abi) {
if abi == Abi::Unadjusted { return }
}
}
- fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type {
+ fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
let args_capacity: usize = self.args.iter().map(|arg|
if arg.pad.is_some() { 1 } else { 0 } +
if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 }
}
if self.variadic {
- Type::variadic_func(&llargument_tys, &llreturn_ty)
+ Type::variadic_func(&llargument_tys, llreturn_ty)
} else {
- Type::func(&llargument_tys, &llreturn_ty)
+ Type::func(&llargument_tys, llreturn_ty)
}
}
}
}
- fn apply_attrs_llfn(&self, llfn: ValueRef) {
+ fn apply_attrs_llfn(&self, llfn: &'ll Value) {
let mut i = 0;
let mut apply = |attrs: &ArgAttributes| {
attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
}
}
- fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef) {
+ fn apply_attrs_callsite(&self, bx: &Builder<'a, 'll, 'tcx>, callsite: &'ll Value) {
let mut i = 0;
let mut apply = |attrs: &ArgAttributes| {
attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite);
// except according to those terms.
use std::ffi::CString;
-use std::ptr;
use attributes;
use libc::c_uint;
use llvm::{self, False, True};
pub(crate) unsafe fn codegen(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) {
- let llcx = mods.llcx;
- let llmod = mods.llmod;
+ let llcx = &*mods.llcx;
+ let llmod = mods.llmod();
let usize = match &tcx.sess.target.target.target_pointer_width[..] {
"16" => llvm::LLVMInt16TypeInContext(llcx),
"32" => llvm::LLVMInt32TypeInContext(llcx),
callee,
args.as_ptr(),
args.len() as c_uint,
- ptr::null_mut(),
+ None,
"\0".as_ptr() as *const _);
llvm::LLVMSetTailCall(ret, True);
if output.is_some() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::{self, ValueRef};
+use llvm;
use common::*;
use type_::Type;
use type_of::LayoutLlvmExt;
use builder::Builder;
+use value::Value;
use rustc::hir;
use libc::{c_uint, c_char};
// Take an inline assembly expression and splat it out via LLVM
-pub fn codegen_inline_asm<'a, 'tcx>(
- bx: &Builder<'a, 'tcx>,
+pub fn codegen_inline_asm(
+ bx: &Builder<'a, 'll, 'tcx>,
ia: &hir::InlineAsm,
- outputs: Vec<PlaceRef<'tcx>>,
- mut inputs: Vec<ValueRef>
+ outputs: Vec<PlaceRef<'ll, 'tcx>>,
+ mut inputs: Vec<&'ll Value>
) {
let mut ext_constraints = vec![];
let mut output_types = vec![];
let kind = llvm::LLVMGetMDKindIDInContext(bx.cx.llcx,
key.as_ptr() as *const c_char, key.len() as c_uint);
- let val: llvm::ValueRef = C_i32(bx.cx, ia.ctxt.outer().as_u32() as i32);
+ let val: &'ll Value = C_i32(bx.cx, ia.ctxt.outer().as_u32() as i32);
llvm::LLVMSetMetadata(r, kind,
llvm::LLVMMDNodeInContext(bx.cx.llcx, &val, 1));
use rustc_target::spec::PanicStrategy;
use attributes;
-use llvm::{self, Attribute, ValueRef};
+use llvm::{self, Attribute};
use llvm::AttributePlace::Function;
use llvm_util;
pub use syntax::attr::{self, InlineAttr};
+
use context::CodegenCx;
+use value::Value;
/// Mark LLVM function to use provided inline heuristic.
#[inline]
-pub fn inline(val: ValueRef, inline: InlineAttr) {
+pub fn inline(val: &'ll Value, inline: InlineAttr) {
use self::InlineAttr::*;
match inline {
Hint => Attribute::InlineHint.apply_llfn(Function, val),
/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
#[inline]
-pub fn emit_uwtable(val: ValueRef, emit: bool) {
+pub fn emit_uwtable(val: &'ll Value, emit: bool) {
Attribute::UWTable.toggle_llfn(Function, val, emit);
}
/// Tell LLVM whether the function can or cannot unwind.
#[inline]
-pub fn unwind(val: ValueRef, can_unwind: bool) {
+pub fn unwind(val: &'ll Value, can_unwind: bool) {
Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind);
}
/// Tell LLVM whether it should optimize function for size.
#[inline]
#[allow(dead_code)] // possibly useful function
-pub fn set_optimize_for_size(val: ValueRef, optimize: bool) {
+pub fn set_optimize_for_size(val: &'ll Value, optimize: bool) {
Attribute::OptimizeForSize.toggle_llfn(Function, val, optimize);
}
/// Tell LLVM if this function should be 'naked', i.e. skip the epilogue and prologue.
#[inline]
-pub fn naked(val: ValueRef, is_naked: bool) {
+pub fn naked(val: &'ll Value, is_naked: bool) {
Attribute::Naked.toggle_llfn(Function, val, is_naked);
}
-pub fn set_frame_pointer_elimination(cx: &CodegenCx, llfn: ValueRef) {
+pub fn set_frame_pointer_elimination(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
if cx.sess().must_not_eliminate_frame_pointers() {
llvm::AddFunctionAttrStringValue(
llfn, llvm::AttributePlace::Function,
}
}
-pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) {
+pub fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
// Only use stack probes if the target specification indicates that we
// should be using stack probes
if !cx.sess().target.target.options.stack_probes {
/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
/// attributes.
-pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) {
+pub fn from_fn_attrs(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value, id: DefId) {
let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(id);
inline(llfn, codegen_fn_attrs.inline);
}
fn build_with_llvm(&mut self, kind: ArchiveKind) -> io::Result<()> {
- let mut archives = Vec::new();
+ let removals = mem::replace(&mut self.removals, Vec::new());
+ let mut additions = mem::replace(&mut self.additions, Vec::new());
let mut strings = Vec::new();
let mut members = Vec::new();
- let removals = mem::replace(&mut self.removals, Vec::new());
+
+ let dst = CString::new(self.config.dst.to_str().unwrap())?;
+ let should_update_symbols = self.should_update_symbols;
unsafe {
if let Some(archive) = self.src_archive() {
let name = CString::new(child_name)?;
members.push(llvm::LLVMRustArchiveMemberNew(ptr::null(),
name.as_ptr(),
- child.raw()));
+ Some(child.raw)));
strings.push(name);
}
}
- for addition in mem::replace(&mut self.additions, Vec::new()) {
+ for addition in &mut additions {
match addition {
Addition::File { path, name_in_archive } => {
let path = CString::new(path.to_str().unwrap())?;
- let name = CString::new(name_in_archive)?;
+ let name = CString::new(name_in_archive.clone())?;
members.push(llvm::LLVMRustArchiveMemberNew(path.as_ptr(),
name.as_ptr(),
- ptr::null_mut()));
+ None));
strings.push(path);
strings.push(name);
}
- Addition::Archive { archive, mut skip } => {
+ Addition::Archive { archive, skip } => {
for child in archive.iter() {
let child = child.map_err(string_to_io_error)?;
if !is_relevant_child(&child) {
let name = CString::new(child_name)?;
let m = llvm::LLVMRustArchiveMemberNew(ptr::null(),
name.as_ptr(),
- child.raw());
+ Some(child.raw));
members.push(m);
strings.push(name);
}
- archives.push(archive);
}
}
}
- let dst = self.config.dst.to_str().unwrap().as_bytes();
- let dst = CString::new(dst)?;
let r = llvm::LLVMRustWriteArchive(dst.as_ptr(),
members.len() as libc::size_t,
- members.as_ptr(),
- self.should_update_symbols,
+ members.as_ptr() as *const &_,
+ should_update_symbols,
kind);
let ret = if r.into_result().is_err() {
let err = llvm::LLVMRustGetLastError();
use super::rpath::RPathConfig;
use super::rpath;
use metadata::METADATA_FILENAME;
-use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest};
+use rustc::session::config::{self, DebugInfo, OutputFilenames, OutputType, PrintRequest};
use rustc::session::config::{RUST_CGU_EXT, Lto};
use rustc::session::filesearch;
use rustc::session::search_paths::PathKind;
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) &&
!output_metadata &&
- crate_type == config::CrateTypeExecutable {
+ crate_type == config::CrateType::Executable {
continue;
}
/// split-dwarf like schemes.
fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
// If the objects don't have debuginfo there's nothing to preserve.
- if sess.opts.debuginfo == NoDebugInfo {
+ if sess.opts.debuginfo == DebugInfo::None {
return false
}
// the objects as they're losslessly contained inside the archives.
let output_linked = sess.crate_types.borrow()
.iter()
- .any(|x| *x != config::CrateTypeRlib && *x != config::CrateTypeStaticlib);
+ .any(|x| *x != config::CrateType::Rlib && *x != config::CrateType::Staticlib);
if !output_linked {
return false
}
f: &mut dyn FnMut(CrateNum, &Path)) -> Result<(), String> {
let crates = info.used_crates_static.iter();
let fmts = sess.dependency_formats.borrow();
- let fmts = fmts.get(&config::CrateTypeExecutable)
- .or_else(|| fmts.get(&config::CrateTypeStaticlib))
- .or_else(|| fmts.get(&config::CrateTypeCdylib))
- .or_else(|| fmts.get(&config::CrateTypeProcMacro));
+ let fmts = fmts.get(&config::CrateType::Executable)
+ .or_else(|| fmts.get(&config::CrateType::Staticlib))
+ .or_else(|| fmts.get(&config::CrateType::Cdylib))
+ .or_else(|| fmts.get(&config::CrateType::ProcMacro));
let fmts = match fmts {
Some(f) => f,
None => return Err("could not find formats for rlibs".to_string())
if outputs.outputs.should_codegen() {
let out_filename = out_filename(sess, crate_type, outputs, crate_name);
match crate_type {
- config::CrateTypeRlib => {
+ config::CrateType::Rlib => {
link_rlib(sess,
codegen_results,
RlibFlavor::Normal,
&out_filename,
&tmpdir).build();
}
- config::CrateTypeStaticlib => {
+ config::CrateType::Staticlib => {
link_staticlib(sess, codegen_results, &out_filename, &tmpdir);
}
_ => {
}
cmd.args(&sess.opts.debugging_opts.pre_link_arg);
- let pre_link_objects = if crate_type == config::CrateTypeExecutable {
+ let pre_link_objects = if crate_type == config::CrateType::Executable {
&sess.target.target.options.pre_link_objects_exe
} else {
&sess.target.target.options.pre_link_objects_dll
cmd.arg(root.join(obj));
}
- if crate_type == config::CrateTypeExecutable && sess.crt_static() {
+ if crate_type == config::CrateType::Executable && sess.crt_static() {
for obj in &sess.target.target.options.pre_link_objects_exe_crt {
cmd.arg(root.join(obj));
}
// the symbols. Note, though, that if the object files are being preserved
// for their debug information there's no need for us to run dsymutil.
if sess.target.target.options.is_like_osx &&
- sess.opts.debuginfo != NoDebugInfo &&
+ sess.opts.debuginfo != DebugInfo::None &&
!preserve_objects_for_their_debuginfo(sess)
{
match Command::new("dsymutil").arg(out_filename).output() {
}
cmd.output_filename(out_filename);
- if crate_type == config::CrateTypeExecutable &&
+ if crate_type == config::CrateType::Executable &&
sess.target.target.options.is_like_windows {
if let Some(ref s) = codegen_results.windows_subsystem {
cmd.subsystem(s);
// If we're building a dynamic library then some platforms need to make sure
// that all symbols are exported correctly from the dynamic library.
- if crate_type != config::CrateTypeExecutable ||
+ if crate_type != config::CrateType::Executable ||
sess.target.target.options.is_like_emscripten {
cmd.export_symbols(tmpdir, crate_type);
}
// When linking a dynamic library, we put the metadata into a section of the
// executable. This metadata is in a separate object file from the main
// object file, so we link that in here.
- if crate_type == config::CrateTypeDylib ||
- crate_type == config::CrateTypeProcMacro {
+ if crate_type == config::CrateType::Dylib ||
+ crate_type == config::CrateType::ProcMacro {
if let Some(obj) = codegen_results.metadata_module.object.as_ref() {
cmd.add_object(obj);
}
// Try to strip as much out of the generated object by removing unused
// sections if possible. See more comments in linker.rs
if !sess.opts.cg.link_dead_code {
- let keep_metadata = crate_type == config::CrateTypeDylib;
+ let keep_metadata = crate_type == config::CrateType::Dylib;
cmd.gc_sections(keep_metadata);
}
let used_link_args = &codegen_results.crate_info.link_args;
- if crate_type == config::CrateTypeExecutable {
+ if crate_type == config::CrateType::Executable {
let mut position_independent_executable = false;
if t.options.position_independent_executables {
add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
// Tell the linker what we're doing.
- if crate_type != config::CrateTypeExecutable {
+ if crate_type != config::CrateType::Executable {
cmd.build_dylib(out_filename);
}
- if crate_type == config::CrateTypeExecutable && sess.crt_static() {
+ if crate_type == config::CrateType::Executable && sess.crt_static() {
cmd.build_static_executable();
}
if (!is_full_lto_enabled(sess) ||
ignored_for_lto(sess, &codegen_results.crate_info, cnum)) &&
- crate_type != config::CrateTypeDylib &&
+ crate_type != config::CrateType::Dylib &&
!skip_native {
cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
return
// Note, though, that we don't want to include the whole of a
// compiler-builtins crate (e.g. compiler-rt) because it'll get
// repeatedly linked anyway.
- if crate_type == config::CrateTypeDylib &&
+ if crate_type == config::CrateType::Dylib &&
codegen_results.crate_info.compiler_builtins != Some(cnum) {
cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst));
} else {
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
use rustc::middle::dependency_format::Linkage;
use rustc::session::Session;
-use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel,
+use rustc::session::config::{self, CrateType, OptLevel, DebugInfo,
CrossLangLto};
use rustc::ty::TyCtxt;
use rustc_target::spec::{LinkerFlavor, LldFlavor};
fn debuginfo(&mut self) {
match self.sess.opts.debuginfo {
- DebugInfoLevel::NoDebugInfo => {
+ DebugInfo::None => {
// If we are building without debuginfo enabled and we were called with
// `-Zstrip-debuginfo-if-disabled=yes`, tell the linker to strip any debuginfo
// found when linking to get rid of symbols from libstd.
// exported symbols to ensure we don't expose any more. The object files
// have far more public symbols than we actually want to export, so we
// hide them all here.
- if crate_type == CrateType::CrateTypeDylib ||
- crate_type == CrateType::CrateTypeProcMacro {
+ if crate_type == CrateType::Dylib ||
+ crate_type == CrateType::ProcMacro {
return
}
fn debuginfo(&mut self) {
// Preserve names or generate source maps depending on debug info
self.cmd.arg(match self.sess.opts.debuginfo {
- DebugInfoLevel::NoDebugInfo => "-g0",
- DebugInfoLevel::LimitedDebugInfo => "-g3",
- DebugInfoLevel::FullDebugInfo => "-g4"
+ DebugInfo::None => "-g0",
+ DebugInfo::Limited => "-g3",
+ DebugInfo::Full => "-g4"
});
}
OptLevel::Size => "-O2",
OptLevel::SizeMin => "-O2"
});
+ match self.sess.opts.optimize {
+ OptLevel::No => (),
+ OptLevel::Less |
+ OptLevel::Default |
+ OptLevel::Aggressive |
+ OptLevel::Size |
+ OptLevel::SizeMin => {
+ // LLD generates incorrect debugging information when
+ // optimization is applied: strip debug sections.
+ self.cmd.arg("--strip-debug");
+ }
+ }
}
fn pgo_gen(&mut self) {
use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
use back::symbol_export;
use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
-use back::write;
+use back::write::{self, DiagnosticHandlers};
use errors::{FatalError, Handler};
use llvm::archive_ro::ArchiveRO;
-use llvm::{ModuleRef, TargetMachineRef, True, False};
+use llvm::{True, False};
use llvm;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc::middle::exported_symbols::SymbolExportLevel;
pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
match crate_type {
- config::CrateTypeExecutable |
- config::CrateTypeStaticlib |
- config::CrateTypeCdylib => true,
+ config::CrateType::Executable |
+ config::CrateType::Staticlib |
+ config::CrateType::Cdylib => true,
- config::CrateTypeDylib |
- config::CrateTypeRlib |
- config::CrateTypeProcMacro => false,
+ config::CrateType::Dylib |
+ config::CrateType::Rlib |
+ config::CrateType::ProcMacro => false,
}
}
match *self {
LtoModuleCodegen::Fat { ref mut module, .. } => {
let module = module.take().unwrap();
- let config = cgcx.config(module.kind);
- let llmod = module.llvm().unwrap().llmod;
- let tm = module.llvm().unwrap().tm;
- run_pass_manager(cgcx, tm, llmod, config, false);
- timeline.record("fat-done");
+ {
+ let config = cgcx.config(module.kind);
+ let llmod = module.llvm().unwrap().llmod();
+ let tm = &*module.llvm().unwrap().tm;
+ run_pass_manager(cgcx, tm, llmod, config, false);
+ timeline.record("fat-done");
+ }
Ok(module)
}
LtoModuleCodegen::Thin(ref mut thin) => thin.optimize(cgcx, timeline),
.filter(|&(_, module)| module.kind == ModuleKind::Regular)
.map(|(i, module)| {
let cost = unsafe {
- llvm::LLVMRustModuleCost(module.llvm().unwrap().llmod)
+ llvm::LLVMRustModuleCost(module.llvm().unwrap().llmod())
};
(cost, i)
})
.max()
.expect("must be codegen'ing at least one module");
let module = modules.remove(costliest_module);
- let llmod = module.llvm().expect("can't lto pre-codegened modules").llmod;
- info!("using {:?} as a base module", module.llmod_id);
-
- // For all other modules we codegened we'll need to link them into our own
- // bitcode. All modules were codegened in their own LLVM context, however,
- // and we want to move everything to the same LLVM context. Currently the
- // way we know of to do that is to serialize them to a string and them parse
- // them later. Not great but hey, that's why it's "fat" LTO, right?
- for module in modules {
- let llvm = module.llvm().expect("can't lto pre-codegened modules");
- let buffer = ModuleBuffer::new(llvm.llmod);
- let llmod_id = CString::new(&module.llmod_id[..]).unwrap();
- serialized_modules.push((SerializedModule::Local(buffer), llmod_id));
- }
-
- // For all serialized bitcode files we parse them and link them in as we did
- // above, this is all mostly handled in C++. Like above, though, we don't
- // know much about the memory management here so we err on the side of being
- // save and persist everything with the original module.
let mut serialized_bitcode = Vec::new();
- let mut linker = Linker::new(llmod);
- for (bc_decoded, name) in serialized_modules {
- info!("linking {:?}", name);
- time_ext(cgcx.time_passes, None, &format!("ll link {:?}", name), || {
- let data = bc_decoded.data();
- linker.add(&data).map_err(|()| {
- let msg = format!("failed to load bc of {:?}", name);
- write::llvm_err(&diag_handler, msg)
- })
- })?;
- timeline.record(&format!("link {:?}", name));
- serialized_bitcode.push(bc_decoded);
- }
- drop(linker);
- cgcx.save_temp_bitcode(&module, "lto.input");
+ {
+ let (llcx, llmod) = {
+ let llvm = module.llvm().expect("can't lto pre-codegened modules");
+ (&llvm.llcx, llvm.llmod())
+ };
+ info!("using {:?} as a base module", module.llmod_id);
+
+ // The linking steps below may produce errors and diagnostics within LLVM
+ // which we'd like to handle and print, so set up our diagnostic handlers
+ // (which get unregistered when they go out of scope below).
+ let _handler = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
+
+ // For all other modules we codegened we'll need to link them into our own
+ // bitcode. All modules were codegened in their own LLVM context, however,
+ // and we want to move everything to the same LLVM context. Currently the
+ // way we know of to do that is to serialize them to a string and them parse
+ // them later. Not great but hey, that's why it's "fat" LTO, right?
+ for module in modules {
+ let llvm = module.llvm().expect("can't lto pre-codegened modules");
+ let buffer = ModuleBuffer::new(llvm.llmod());
+ let llmod_id = CString::new(&module.llmod_id[..]).unwrap();
+ serialized_modules.push((SerializedModule::Local(buffer), llmod_id));
+ }
- // Internalize everything that *isn't* in our whitelist to help strip out
- // more modules and such
- unsafe {
- let ptr = symbol_white_list.as_ptr();
- llvm::LLVMRustRunRestrictionPass(llmod,
- ptr as *const *const libc::c_char,
- symbol_white_list.len() as libc::size_t);
- cgcx.save_temp_bitcode(&module, "lto.after-restriction");
- }
+ // For all serialized bitcode files we parse them and link them in as we did
+ // above, this is all mostly handled in C++. Like above, though, we don't
+ // know much about the memory management here so we err on the side of being
+ // save and persist everything with the original module.
+ let mut linker = Linker::new(llmod);
+ for (bc_decoded, name) in serialized_modules {
+ info!("linking {:?}", name);
+ time_ext(cgcx.time_passes, None, &format!("ll link {:?}", name), || {
+ let data = bc_decoded.data();
+ linker.add(&data).map_err(|()| {
+ let msg = format!("failed to load bc of {:?}", name);
+ write::llvm_err(&diag_handler, msg)
+ })
+ })?;
+ timeline.record(&format!("link {:?}", name));
+ serialized_bitcode.push(bc_decoded);
+ }
+ drop(linker);
+ cgcx.save_temp_bitcode(&module, "lto.input");
- if cgcx.no_landing_pads {
+ // Internalize everything that *isn't* in our whitelist to help strip out
+ // more modules and such
unsafe {
- llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
+ let ptr = symbol_white_list.as_ptr();
+ llvm::LLVMRustRunRestrictionPass(llmod,
+ ptr as *const *const libc::c_char,
+ symbol_white_list.len() as libc::size_t);
+ cgcx.save_temp_bitcode(&module, "lto.after-restriction");
+ }
+
+ if cgcx.no_landing_pads {
+ unsafe {
+ llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
+ }
+ cgcx.save_temp_bitcode(&module, "lto.after-nounwind");
}
- cgcx.save_temp_bitcode(&module, "lto.after-nounwind");
+ timeline.record("passes");
}
- timeline.record("passes");
Ok(vec![LtoModuleCodegen::Fat {
module: Some(module),
}])
}
-struct Linker(llvm::LinkerRef);
+struct Linker<'a>(&'a mut llvm::Linker<'a>);
-impl Linker {
- fn new(llmod: ModuleRef) -> Linker {
+impl Linker<'a> {
+ fn new(llmod: &'a llvm::Module) -> Self {
unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) }
}
}
}
-impl Drop for Linker {
+impl Drop for Linker<'a> {
fn drop(&mut self) {
- unsafe { llvm::LLVMRustLinkerFree(self.0); }
+ unsafe { llvm::LLVMRustLinkerFree(&mut *(self.0 as *mut _)); }
}
}
info!("local module: {} - {}", i, module.llmod_id);
let llvm = module.llvm().expect("can't lto precodegened module");
let name = CString::new(module.llmod_id.clone()).unwrap();
- let buffer = ThinBuffer::new(llvm.llmod);
+ let buffer = ThinBuffer::new(llvm.llmod());
thin_modules.push(llvm::ThinLTOModule {
identifier: name.as_ptr(),
data: buffer.data().as_ptr(),
thin_modules.len() as u32,
symbol_white_list.as_ptr(),
symbol_white_list.len() as u32,
- );
- if data.is_null() {
- let msg = "failed to prepare thin LTO context".to_string();
- return Err(write::llvm_err(&diag_handler, msg))
- }
+ ).ok_or_else(|| {
+ write::llvm_err(&diag_handler, "failed to prepare thin LTO context".to_string())
+ })?;
+
let data = ThinData(data);
info!("thin LTO data created");
timeline.record("data");
}
fn run_pass_manager(cgcx: &CodegenContext,
- tm: TargetMachineRef,
- llmod: ModuleRef,
+ tm: &llvm::TargetMachine,
+ llmod: &llvm::Module,
config: &ModuleConfig,
thin: bool) {
// Now we have one massive module inside of llmod. Time to run the
if config.verify_llvm_ir {
let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
- assert!(!pass.is_null());
- llvm::LLVMRustAddPass(pm, pass);
+ llvm::LLVMRustAddPass(pm, pass.unwrap());
}
// When optimizing for LTO we don't actually pass in `-O0`, but we force
if config.verify_llvm_ir {
let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
- assert!(!pass.is_null());
- llvm::LLVMRustAddPass(pm, pass);
+ llvm::LLVMRustAddPass(pm, pass.unwrap());
}
time_ext(cgcx.time_passes, None, "LTO passes", ||
}
}
-pub struct ModuleBuffer(*mut llvm::ModuleBuffer);
+pub struct ModuleBuffer(&'static mut llvm::ModuleBuffer);
unsafe impl Send for ModuleBuffer {}
unsafe impl Sync for ModuleBuffer {}
impl ModuleBuffer {
- pub fn new(m: ModuleRef) -> ModuleBuffer {
+ pub fn new(m: &llvm::Module) -> ModuleBuffer {
ModuleBuffer(unsafe {
llvm::LLVMRustModuleBufferCreate(m)
})
impl Drop for ModuleBuffer {
fn drop(&mut self) {
- unsafe { llvm::LLVMRustModuleBufferFree(self.0); }
+ unsafe { llvm::LLVMRustModuleBufferFree(&mut *(self.0 as *mut _)); }
}
}
module_names: Vec<CString>,
}
-struct ThinData(*mut llvm::ThinLTOData);
+struct ThinData(&'static mut llvm::ThinLTOData);
unsafe impl Send for ThinData {}
unsafe impl Sync for ThinData {}
impl Drop for ThinData {
fn drop(&mut self) {
unsafe {
- llvm::LLVMRustFreeThinLTOData(self.0);
+ llvm::LLVMRustFreeThinLTOData(&mut *(self.0 as *mut _));
}
}
}
-pub struct ThinBuffer(*mut llvm::ThinLTOBuffer);
+pub struct ThinBuffer(&'static mut llvm::ThinLTOBuffer);
unsafe impl Send for ThinBuffer {}
unsafe impl Sync for ThinBuffer {}
impl ThinBuffer {
- pub fn new(m: ModuleRef) -> ThinBuffer {
+ pub fn new(m: &llvm::Module) -> ThinBuffer {
unsafe {
let buffer = llvm::LLVMRustThinLTOBufferCreate(m);
ThinBuffer(buffer)
impl Drop for ThinBuffer {
fn drop(&mut self) {
unsafe {
- llvm::LLVMRustThinLTOBufferFree(self.0);
+ llvm::LLVMRustThinLTOBufferFree(&mut *(self.0 as *mut _));
}
}
}
// crates but for locally codegened modules we may be able to reuse
// that LLVM Context and Module.
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
- let llmod = llvm::LLVMRustParseBitcodeForThinLTO(
+ let llmod_raw = llvm::LLVMRustParseBitcodeForThinLTO(
llcx,
self.data().as_ptr(),
self.data().len(),
self.shared.module_names[self.idx].as_ptr(),
- );
- if llmod.is_null() {
+ ).ok_or_else(|| {
let msg = "failed to parse bitcode for thin LTO module".to_string();
- return Err(write::llvm_err(&diag_handler, msg));
- }
+ write::llvm_err(&diag_handler, msg)
+ })? as *const _;
let module = ModuleCodegen {
source: ModuleSource::Codegened(ModuleLlvm {
- llmod,
+ llmod_raw,
llcx,
tm,
}),
name: self.name().to_string(),
kind: ModuleKind::Regular,
};
- cgcx.save_temp_bitcode(&module, "thin-lto-input");
-
- // Before we do much else find the "main" `DICompileUnit` that we'll be
- // using below. If we find more than one though then rustc has changed
- // in a way we're not ready for, so generate an ICE by returning
- // an error.
- let mut cu1 = ptr::null_mut();
- let mut cu2 = ptr::null_mut();
- llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
- if !cu2.is_null() {
- let msg = "multiple source DICompileUnits found".to_string();
- return Err(write::llvm_err(&diag_handler, msg))
- }
+ {
+ let llmod = module.llvm().unwrap().llmod();
+ cgcx.save_temp_bitcode(&module, "thin-lto-input");
+
+ // Before we do much else find the "main" `DICompileUnit` that we'll be
+ // using below. If we find more than one though then rustc has changed
+ // in a way we're not ready for, so generate an ICE by returning
+ // an error.
+ let mut cu1 = ptr::null_mut();
+ let mut cu2 = ptr::null_mut();
+ llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
+ if !cu2.is_null() {
+ let msg = "multiple source DICompileUnits found".to_string();
+ return Err(write::llvm_err(&diag_handler, msg))
+ }
- // Like with "fat" LTO, get some better optimizations if landing pads
- // are disabled by removing all landing pads.
- if cgcx.no_landing_pads {
- llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
- cgcx.save_temp_bitcode(&module, "thin-lto-after-nounwind");
- timeline.record("nounwind");
- }
+ // Like with "fat" LTO, get some better optimizations if landing pads
+ // are disabled by removing all landing pads.
+ if cgcx.no_landing_pads {
+ llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
+ cgcx.save_temp_bitcode(&module, "thin-lto-after-nounwind");
+ timeline.record("nounwind");
+ }
- // Up next comes the per-module local analyses that we do for Thin LTO.
- // Each of these functions is basically copied from the LLVM
- // implementation and then tailored to suit this implementation. Ideally
- // each of these would be supported by upstream LLVM but that's perhaps
- // a patch for another day!
- //
- // You can find some more comments about these functions in the LLVM
- // bindings we've got (currently `PassWrapper.cpp`)
- if !llvm::LLVMRustPrepareThinLTORename(self.shared.data.0, llmod) {
- let msg = "failed to prepare thin LTO module".to_string();
- return Err(write::llvm_err(&diag_handler, msg))
- }
- cgcx.save_temp_bitcode(&module, "thin-lto-after-rename");
- timeline.record("rename");
- if !llvm::LLVMRustPrepareThinLTOResolveWeak(self.shared.data.0, llmod) {
- let msg = "failed to prepare thin LTO module".to_string();
- return Err(write::llvm_err(&diag_handler, msg))
- }
- cgcx.save_temp_bitcode(&module, "thin-lto-after-resolve");
- timeline.record("resolve");
- if !llvm::LLVMRustPrepareThinLTOInternalize(self.shared.data.0, llmod) {
- let msg = "failed to prepare thin LTO module".to_string();
- return Err(write::llvm_err(&diag_handler, msg))
- }
- cgcx.save_temp_bitcode(&module, "thin-lto-after-internalize");
- timeline.record("internalize");
- if !llvm::LLVMRustPrepareThinLTOImport(self.shared.data.0, llmod) {
- let msg = "failed to prepare thin LTO module".to_string();
- return Err(write::llvm_err(&diag_handler, msg))
+ // Up next comes the per-module local analyses that we do for Thin LTO.
+ // Each of these functions is basically copied from the LLVM
+ // implementation and then tailored to suit this implementation. Ideally
+ // each of these would be supported by upstream LLVM but that's perhaps
+ // a patch for another day!
+ //
+ // You can find some more comments about these functions in the LLVM
+ // bindings we've got (currently `PassWrapper.cpp`)
+ if !llvm::LLVMRustPrepareThinLTORename(self.shared.data.0, llmod) {
+ let msg = "failed to prepare thin LTO module".to_string();
+ return Err(write::llvm_err(&diag_handler, msg))
+ }
+ cgcx.save_temp_bitcode(&module, "thin-lto-after-rename");
+ timeline.record("rename");
+ if !llvm::LLVMRustPrepareThinLTOResolveWeak(self.shared.data.0, llmod) {
+ let msg = "failed to prepare thin LTO module".to_string();
+ return Err(write::llvm_err(&diag_handler, msg))
+ }
+ cgcx.save_temp_bitcode(&module, "thin-lto-after-resolve");
+ timeline.record("resolve");
+ if !llvm::LLVMRustPrepareThinLTOInternalize(self.shared.data.0, llmod) {
+ let msg = "failed to prepare thin LTO module".to_string();
+ return Err(write::llvm_err(&diag_handler, msg))
+ }
+ cgcx.save_temp_bitcode(&module, "thin-lto-after-internalize");
+ timeline.record("internalize");
+ if !llvm::LLVMRustPrepareThinLTOImport(self.shared.data.0, llmod) {
+ let msg = "failed to prepare thin LTO module".to_string();
+ return Err(write::llvm_err(&diag_handler, msg))
+ }
+ cgcx.save_temp_bitcode(&module, "thin-lto-after-import");
+ timeline.record("import");
+
+ // Ok now this is a bit unfortunate. This is also something you won't
+ // find upstream in LLVM's ThinLTO passes! This is a hack for now to
+ // work around bugs in LLVM.
+ //
+ // First discovered in #45511 it was found that as part of ThinLTO
+ // importing passes LLVM will import `DICompileUnit` metadata
+ // information across modules. This means that we'll be working with one
+ // LLVM module that has multiple `DICompileUnit` instances in it (a
+ // bunch of `llvm.dbg.cu` members). Unfortunately there's a number of
+ // bugs in LLVM's backend which generates invalid DWARF in a situation
+ // like this:
+ //
+ // https://bugs.llvm.org/show_bug.cgi?id=35212
+ // https://bugs.llvm.org/show_bug.cgi?id=35562
+ //
+ // While the first bug there is fixed the second ended up causing #46346
+ // which was basically a resurgence of #45511 after LLVM's bug 35212 was
+ // fixed.
+ //
+ // This function below is a huge hack around this problem. The function
+ // below is defined in `PassWrapper.cpp` and will basically "merge"
+ // all `DICompileUnit` instances in a module. Basically it'll take all
+ // the objects, rewrite all pointers of `DISubprogram` to point to the
+ // first `DICompileUnit`, and then delete all the other units.
+ //
+ // This is probably mangling to the debug info slightly (but hopefully
+ // not too much) but for now at least gets LLVM to emit valid DWARF (or
+ // so it appears). Hopefully we can remove this once upstream bugs are
+ // fixed in LLVM.
+ llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
+ cgcx.save_temp_bitcode(&module, "thin-lto-after-patch");
+ timeline.record("patch");
+
+ // Alright now that we've done everything related to the ThinLTO
+ // analysis it's time to run some optimizations! Here we use the same
+ // `run_pass_manager` as the "fat" LTO above except that we tell it to
+ // populate a thin-specific pass manager, which presumably LLVM treats a
+ // little differently.
+ info!("running thin lto passes over {}", module.name);
+ let config = cgcx.config(module.kind);
+ run_pass_manager(cgcx, module.llvm().unwrap().tm, llmod, config, true);
+ cgcx.save_temp_bitcode(&module, "thin-lto-after-pm");
+ timeline.record("thin-done");
}
- cgcx.save_temp_bitcode(&module, "thin-lto-after-import");
- timeline.record("import");
-
- // Ok now this is a bit unfortunate. This is also something you won't
- // find upstream in LLVM's ThinLTO passes! This is a hack for now to
- // work around bugs in LLVM.
- //
- // First discovered in #45511 it was found that as part of ThinLTO
- // importing passes LLVM will import `DICompileUnit` metadata
- // information across modules. This means that we'll be working with one
- // LLVM module that has multiple `DICompileUnit` instances in it (a
- // bunch of `llvm.dbg.cu` members). Unfortunately there's a number of
- // bugs in LLVM's backend which generates invalid DWARF in a situation
- // like this:
- //
- // https://bugs.llvm.org/show_bug.cgi?id=35212
- // https://bugs.llvm.org/show_bug.cgi?id=35562
- //
- // While the first bug there is fixed the second ended up causing #46346
- // which was basically a resurgence of #45511 after LLVM's bug 35212 was
- // fixed.
- //
- // This function below is a huge hack around this problem. The function
- // below is defined in `PassWrapper.cpp` and will basically "merge"
- // all `DICompileUnit` instances in a module. Basically it'll take all
- // the objects, rewrite all pointers of `DISubprogram` to point to the
- // first `DICompileUnit`, and then delete all the other units.
- //
- // This is probably mangling to the debug info slightly (but hopefully
- // not too much) but for now at least gets LLVM to emit valid DWARF (or
- // so it appears). Hopefully we can remove this once upstream bugs are
- // fixed in LLVM.
- llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
- cgcx.save_temp_bitcode(&module, "thin-lto-after-patch");
- timeline.record("patch");
-
- // Alright now that we've done everything related to the ThinLTO
- // analysis it's time to run some optimizations! Here we use the same
- // `run_pass_manager` as the "fat" LTO above except that we tell it to
- // populate a thin-specific pass manager, which presumably LLVM treats a
- // little differently.
- info!("running thin lto passes over {}", module.name);
- let config = cgcx.config(module.kind);
- run_pass_manager(cgcx, tm, llmod, config, true);
- cgcx.save_temp_bitcode(&module, "thin-lto-after-pm");
- timeline.record("thin-done");
Ok(module)
}
fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel {
match crate_type {
- config::CrateTypeExecutable |
- config::CrateTypeStaticlib |
- config::CrateTypeProcMacro |
- config::CrateTypeCdylib => SymbolExportLevel::C,
- config::CrateTypeRlib |
- config::CrateTypeDylib => SymbolExportLevel::Rust,
+ config::CrateType::Executable |
+ config::CrateType::Staticlib |
+ config::CrateType::ProcMacro |
+ config::CrateType::Cdylib => SymbolExportLevel::C,
+ config::CrateType::Rlib |
+ config::CrateType::Dylib => SymbolExportLevel::Rust,
}
}
}
}
- if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
+ if tcx.sess.crate_types.borrow().contains(&config::CrateType::Dylib) {
let symbol_name = metadata_symbol_name(tcx);
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
symbols.push((exported_symbol, SymbolExportLevel::Rust));
}
- if tcx.share_generics() && tcx.local_crate_exports_generics() {
+ if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() {
use rustc::mir::mono::{Linkage, Visibility, MonoItem};
use rustc::ty::InstanceDef;
use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir};
use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind};
use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
-use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses,
- AllPasses, Sanitizer, Lto};
+use rustc::session::config::{self, OutputFilenames, OutputType, Passes, Sanitizer, Lto};
use rustc::session::Session;
use rustc::util::nodemap::FxHashMap;
use time_graph::{self, TimeGraph, Timeline};
-use llvm;
-use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef};
-use llvm::{SMDiagnosticRef, ContextRef};
+use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
use {CodegenResults, ModuleSource, ModuleCodegen, CompiledModule, ModuleKind};
use CrateInfo;
use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
pub fn write_output_file(
handler: &errors::Handler,
- target: llvm::TargetMachineRef,
- pm: llvm::PassManagerRef,
- m: ModuleRef,
+ target: &'ll llvm::TargetMachine,
+ pm: &llvm::PassManager<'ll>,
+ m: &'ll llvm::Module,
output: &Path,
file_type: llvm::FileType) -> Result<(), FatalError> {
unsafe {
}
}
-pub fn create_target_machine(sess: &Session, find_features: bool) -> TargetMachineRef {
+pub fn create_target_machine(
+ sess: &Session,
+ find_features: bool,
+) -> &'static mut llvm::TargetMachine {
target_machine_factory(sess, find_features)().unwrap_or_else(|err| {
llvm_err(sess.diagnostic(), err).raise()
})
// that `is_pie_binary` is false. When we discover LLVM target features
// `sess.crate_types` is uninitialized so we cannot access it.
pub fn target_machine_factory(sess: &Session, find_features: bool)
- -> Arc<dyn Fn() -> Result<TargetMachineRef, String> + Send + Sync>
+ -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync>
{
let reloc_model = get_reloc_model(sess);
)
};
- if tm.is_null() {
- Err(format!("Could not create LLVM TargetMachine for triple: {}",
- triple.to_str().unwrap()))
- } else {
- Ok(tm)
- }
+ tm.ok_or_else(|| {
+ format!("Could not create LLVM TargetMachine for triple: {}",
+ triple.to_str().unwrap())
+ })
})
}
regular_module_config: Arc<ModuleConfig>,
metadata_module_config: Arc<ModuleConfig>,
allocator_module_config: Arc<ModuleConfig>,
- pub tm_factory: Arc<dyn Fn() -> Result<TargetMachineRef, String> + Send + Sync>,
+ pub tm_factory: Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync>,
pub msvc_imps_needed: bool,
pub target_pointer_width: String,
- debuginfo: config::DebugInfoLevel,
+ debuginfo: config::DebugInfo,
// Number of cgus excluding the allocator/metadata modules
pub total_cgus: usize,
let cgu = Some(&module.name[..]);
let path = self.output_filenames.temp_path_ext(&ext, cgu);
let cstr = path2cstr(&path);
- let llmod = module.llvm().unwrap().llmod;
+ let llmod = module.llvm().unwrap().llmod();
llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr());
}
}
}
-struct DiagnosticHandlers<'a> {
+pub struct DiagnosticHandlers<'a> {
data: *mut (&'a CodegenContext, &'a Handler),
- llcx: ContextRef,
+ llcx: &'a llvm::Context,
}
impl<'a> DiagnosticHandlers<'a> {
- fn new(cgcx: &'a CodegenContext,
- handler: &'a Handler,
- llcx: ContextRef) -> DiagnosticHandlers<'a> {
+ pub fn new(cgcx: &'a CodegenContext,
+ handler: &'a Handler,
+ llcx: &'a llvm::Context) -> Self {
let data = Box::into_raw(Box::new((cgcx, handler)));
unsafe {
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data as *mut _);
cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_string());
}
-unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef,
+unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic,
user: *const c_void,
cookie: c_uint) {
if user.is_null() {
report_inline_asm(cgcx, &msg, cookie);
}
-unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) {
+unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) {
if user.is_null() {
return
}
llvm::diagnostic::Optimization(opt) => {
let enabled = match cgcx.remark {
- AllPasses => true,
- SomePasses(ref v) => v.iter().any(|s| *s == opt.pass_name),
+ Passes::All => true,
+ Passes::Some(ref v) => v.iter().any(|s| *s == opt.pass_name),
};
if enabled {
opt.message));
}
}
- llvm::diagnostic::PGO(diagnostic_ref) => {
+ llvm::diagnostic::PGO(diagnostic_ref) |
+ llvm::diagnostic::Linker(diagnostic_ref) => {
let msg = llvm::build_string(|s| {
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
- }).expect("non-UTF8 PGO diagnostic");
+ }).expect("non-UTF8 diagnostic");
diag_handler.warn(&msg);
}
llvm::diagnostic::UnknownDiagnostic(..) => {},
-> Result<(), FatalError>
{
let (llmod, llcx, tm) = match module.source {
- ModuleSource::Codegened(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm),
+ ModuleSource::Codegened(ref llvm) => (llvm.llmod(), &*llvm.llcx, &*llvm.tm),
ModuleSource::Preexisting(_) => {
bug!("optimize_and_codegen: called with ModuleSource::Preexisting")
}
let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
let mpm = llvm::LLVMCreatePassManager();
- // If we're verifying or linting, add them to the function pass
- // manager.
- let addpass = |pass_name: &str| {
- let pass_name = CString::new(pass_name).unwrap();
- let pass = llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr());
- if pass.is_null() {
- return false;
- }
- let pass_manager = match llvm::LLVMRustPassKind(pass) {
- llvm::PassKind::Function => fpm,
- llvm::PassKind::Module => mpm,
- llvm::PassKind::Other => {
- diag_handler.err("Encountered LLVM pass kind we can't handle");
- return true
- },
+ {
+ // If we're verifying or linting, add them to the function pass
+ // manager.
+ let addpass = |pass_name: &str| {
+ let pass_name = CString::new(pass_name).unwrap();
+ let pass = match llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr()) {
+ Some(pass) => pass,
+ None => return false,
+ };
+ let pass_manager = match llvm::LLVMRustPassKind(pass) {
+ llvm::PassKind::Function => &*fpm,
+ llvm::PassKind::Module => &*mpm,
+ llvm::PassKind::Other => {
+ diag_handler.err("Encountered LLVM pass kind we can't handle");
+ return true
+ },
+ };
+ llvm::LLVMRustAddPass(pass_manager, pass);
+ true
};
- llvm::LLVMRustAddPass(pass_manager, pass);
- true
- };
- if config.verify_llvm_ir { assert!(addpass("verify")); }
- if !config.no_prepopulate_passes {
- llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
- llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
- let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
- let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal;
- with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| {
- llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
- llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
- })
- }
+ if config.verify_llvm_ir { assert!(addpass("verify")); }
+ if !config.no_prepopulate_passes {
+ llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
+ llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
+ let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
+ let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal;
+ with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| {
+ llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
+ llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
+ })
+ }
- for pass in &config.passes {
- if !addpass(pass) {
- diag_handler.warn(&format!("unknown pass `{}`, ignoring",
- pass));
+ for pass in &config.passes {
+ if !addpass(pass) {
+ diag_handler.warn(&format!("unknown pass `{}`, ignoring",
+ pass));
+ }
}
- }
- for pass in &cgcx.plugin_passes {
- if !addpass(pass) {
- diag_handler.err(&format!("a plugin asked for LLVM pass \
- `{}` but LLVM does not \
- recognize it", pass));
+ for pass in &cgcx.plugin_passes {
+ if !addpass(pass) {
+ diag_handler.err(&format!("a plugin asked for LLVM pass \
+ `{}` but LLVM does not \
+ recognize it", pass));
+ }
}
}
-> Result<CompiledModule, FatalError>
{
timeline.record("codegen");
- let (llmod, llcx, tm) = match module.source {
- ModuleSource::Codegened(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm),
- ModuleSource::Preexisting(_) => {
- bug!("codegen: called with ModuleSource::Preexisting")
- }
- };
- let module_name = module.name.clone();
- let module_name = Some(&module_name[..]);
- let handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
-
- if cgcx.msvc_imps_needed {
- create_msvc_imps(cgcx, llcx, llmod);
- }
-
- // A codegen-specific pass manager is used to generate object
- // files for an LLVM module.
- //
- // Apparently each of these pass managers is a one-shot kind of
- // thing, so we create a new one for each type of output. The
- // pass manager passed to the closure should be ensured to not
- // escape the closure itself, and the manager should only be
- // used once.
- unsafe fn with_codegen<F, R>(tm: TargetMachineRef,
- llmod: ModuleRef,
- no_builtins: bool,
- f: F) -> R
- where F: FnOnce(PassManagerRef) -> R,
{
- let cpm = llvm::LLVMCreatePassManager();
- llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
- llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
- f(cpm)
- }
-
- // If we don't have the integrated assembler, then we need to emit asm
- // from LLVM and use `gcc` to create the object file.
- let asm_to_obj = config.emit_obj && config.no_integrated_as;
-
- // Change what we write and cleanup based on whether obj files are
- // just llvm bitcode. In that case write bitcode, and possibly
- // delete the bitcode if it wasn't requested. Don't generate the
- // machine code, instead copy the .o file from the .bc
- let write_bc = config.emit_bc || config.obj_is_bitcode;
- let rm_bc = !config.emit_bc && config.obj_is_bitcode;
- let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm_to_obj;
- let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode;
-
- let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
- let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
-
-
- if write_bc || config.emit_bc_compressed || config.embed_bitcode {
- let thin;
- let old;
- let data = if llvm::LLVMRustThinLTOAvailable() {
- thin = ThinBuffer::new(llmod);
- thin.data()
- } else {
- old = ModuleBuffer::new(llmod);
- old.data()
+ let (llmod, llcx, tm) = match module.source {
+ ModuleSource::Codegened(ref llvm) => (llvm.llmod(), &*llvm.llcx, &*llvm.tm),
+ ModuleSource::Preexisting(_) => {
+ bug!("codegen: called with ModuleSource::Preexisting")
+ }
};
- timeline.record("make-bc");
+ let module_name = module.name.clone();
+ let module_name = Some(&module_name[..]);
+ let handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
- if write_bc {
- if let Err(e) = fs::write(&bc_out, data) {
- diag_handler.err(&format!("failed to write bytecode: {}", e));
- }
- timeline.record("write-bc");
+ if cgcx.msvc_imps_needed {
+ create_msvc_imps(cgcx, llcx, llmod);
}
- if config.embed_bitcode {
- embed_bitcode(cgcx, llcx, llmod, Some(data));
- timeline.record("embed-bc");
- }
+ // A codegen-specific pass manager is used to generate object
+ // files for an LLVM module.
+ //
+ // Apparently each of these pass managers is a one-shot kind of
+ // thing, so we create a new one for each type of output. The
+ // pass manager passed to the closure should be ensured to not
+ // escape the closure itself, and the manager should only be
+ // used once.
+ unsafe fn with_codegen<'ll, F, R>(tm: &'ll llvm::TargetMachine,
+ llmod: &'ll llvm::Module,
+ no_builtins: bool,
+ f: F) -> R
+ where F: FnOnce(&'ll mut PassManager<'ll>) -> R,
+ {
+ let cpm = llvm::LLVMCreatePassManager();
+ llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
+ llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
+ f(cpm)
+ }
+
+ // If we don't have the integrated assembler, then we need to emit asm
+ // from LLVM and use `gcc` to create the object file.
+ let asm_to_obj = config.emit_obj && config.no_integrated_as;
+
+ // Change what we write and cleanup based on whether obj files are
+ // just llvm bitcode. In that case write bitcode, and possibly
+ // delete the bitcode if it wasn't requested. Don't generate the
+ // machine code, instead copy the .o file from the .bc
+ let write_bc = config.emit_bc || config.obj_is_bitcode;
+ let rm_bc = !config.emit_bc && config.obj_is_bitcode;
+ let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm_to_obj;
+ let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode;
+
+ let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
+ let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
+
+
+ if write_bc || config.emit_bc_compressed || config.embed_bitcode {
+ let thin;
+ let old;
+ let data = if llvm::LLVMRustThinLTOAvailable() {
+ thin = ThinBuffer::new(llmod);
+ thin.data()
+ } else {
+ old = ModuleBuffer::new(llmod);
+ old.data()
+ };
+ timeline.record("make-bc");
- if config.emit_bc_compressed {
- let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
- let data = bytecode::encode(&module.llmod_id, data);
- if let Err(e) = fs::write(&dst, data) {
- diag_handler.err(&format!("failed to write bytecode: {}", e));
+ if write_bc {
+ if let Err(e) = fs::write(&bc_out, data) {
+ diag_handler.err(&format!("failed to write bytecode: {}", e));
+ }
+ timeline.record("write-bc");
}
- timeline.record("compress-bc");
- }
- } else if config.embed_bitcode_marker {
- embed_bitcode(cgcx, llcx, llmod, None);
- }
- time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()),
- || -> Result<(), FatalError> {
- if config.emit_ir {
- let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
- let out = path2cstr(&out);
-
- extern "C" fn demangle_callback(input_ptr: *const c_char,
- input_len: size_t,
- output_ptr: *mut c_char,
- output_len: size_t) -> size_t {
- let input = unsafe {
- slice::from_raw_parts(input_ptr as *const u8, input_len as usize)
- };
+ if config.embed_bitcode {
+ embed_bitcode(cgcx, llcx, llmod, Some(data));
+ timeline.record("embed-bc");
+ }
- let input = match str::from_utf8(input) {
- Ok(s) => s,
- Err(_) => return 0,
- };
+ if config.emit_bc_compressed {
+ let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION);
+ let data = bytecode::encode(&module.llmod_id, data);
+ if let Err(e) = fs::write(&dst, data) {
+ diag_handler.err(&format!("failed to write bytecode: {}", e));
+ }
+ timeline.record("compress-bc");
+ }
+ } else if config.embed_bitcode_marker {
+ embed_bitcode(cgcx, llcx, llmod, None);
+ }
+
+ time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()),
+ || -> Result<(), FatalError> {
+ if config.emit_ir {
+ let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
+ let out = path2cstr(&out);
+
+ extern "C" fn demangle_callback(input_ptr: *const c_char,
+ input_len: size_t,
+ output_ptr: *mut c_char,
+ output_len: size_t) -> size_t {
+ let input = unsafe {
+ slice::from_raw_parts(input_ptr as *const u8, input_len as usize)
+ };
- let output = unsafe {
- slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize)
- };
- let mut cursor = io::Cursor::new(output);
+ let input = match str::from_utf8(input) {
+ Ok(s) => s,
+ Err(_) => return 0,
+ };
- let demangled = match rustc_demangle::try_demangle(input) {
- Ok(d) => d,
- Err(_) => return 0,
- };
+ let output = unsafe {
+ slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize)
+ };
+ let mut cursor = io::Cursor::new(output);
+
+ let demangled = match rustc_demangle::try_demangle(input) {
+ Ok(d) => d,
+ Err(_) => return 0,
+ };
+
+ if let Err(_) = write!(cursor, "{:#}", demangled) {
+ // Possible only if provided buffer is not big enough
+ return 0;
+ }
- if let Err(_) = write!(cursor, "{:#}", demangled) {
- // Possible only if provided buffer is not big enough
- return 0;
+ cursor.position() as size_t
}
- cursor.position() as size_t
+ with_codegen(tm, llmod, config.no_builtins, |cpm| {
+ llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback);
+ llvm::LLVMDisposePassManager(cpm);
+ });
+ timeline.record("ir");
}
- with_codegen(tm, llmod, config.no_builtins, |cpm| {
- llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback);
- llvm::LLVMDisposePassManager(cpm);
- });
- timeline.record("ir");
- }
-
- if config.emit_asm || asm_to_obj {
- let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
+ if config.emit_asm || asm_to_obj {
+ let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
- // We can't use the same module for asm and binary output, because that triggers
- // various errors like invalid IR or broken binaries, so we might have to clone the
- // module to produce the asm output
- let llmod = if config.emit_obj {
- llvm::LLVMCloneModule(llmod)
- } else {
- llmod
- };
- with_codegen(tm, llmod, config.no_builtins, |cpm| {
- write_output_file(diag_handler, tm, cpm, llmod, &path,
- llvm::FileType::AssemblyFile)
- })?;
- if config.emit_obj {
- llvm::LLVMDisposeModule(llmod);
+ // We can't use the same module for asm and binary output, because that triggers
+ // various errors like invalid IR or broken binaries, so we might have to clone the
+ // module to produce the asm output
+ let llmod = if config.emit_obj {
+ llvm::LLVMCloneModule(llmod)
+ } else {
+ llmod
+ };
+ with_codegen(tm, llmod, config.no_builtins, |cpm| {
+ write_output_file(diag_handler, tm, cpm, llmod, &path,
+ llvm::FileType::AssemblyFile)
+ })?;
+ timeline.record("asm");
}
- timeline.record("asm");
- }
- if write_obj {
- with_codegen(tm, llmod, config.no_builtins, |cpm| {
- write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
- llvm::FileType::ObjectFile)
- })?;
- timeline.record("obj");
- } else if asm_to_obj {
- let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
- run_assembler(cgcx, diag_handler, &assembly, &obj_out);
- timeline.record("asm_to_obj");
-
- if !config.emit_asm && !cgcx.save_temps {
- drop(fs::remove_file(&assembly));
+ if write_obj {
+ with_codegen(tm, llmod, config.no_builtins, |cpm| {
+ write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
+ llvm::FileType::ObjectFile)
+ })?;
+ timeline.record("obj");
+ } else if asm_to_obj {
+ let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
+ run_assembler(cgcx, diag_handler, &assembly, &obj_out);
+ timeline.record("asm_to_obj");
+
+ if !config.emit_asm && !cgcx.save_temps {
+ drop(fs::remove_file(&assembly));
+ }
}
- }
- Ok(())
- })?;
+ Ok(())
+ })?;
- if copy_bc_to_obj {
- debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
- if let Err(e) = link_or_copy(&bc_out, &obj_out) {
- diag_handler.err(&format!("failed to copy bitcode to object file: {}", e));
+ if copy_bc_to_obj {
+ debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
+ if let Err(e) = link_or_copy(&bc_out, &obj_out) {
+ diag_handler.err(&format!("failed to copy bitcode to object file: {}", e));
+ }
}
- }
- if rm_bc {
- debug!("removing_bitcode {:?}", bc_out);
- if let Err(e) = fs::remove_file(&bc_out) {
- diag_handler.err(&format!("failed to remove bitcode: {}", e));
+ if rm_bc {
+ debug!("removing_bitcode {:?}", bc_out);
+ if let Err(e) = fs::remove_file(&bc_out) {
+ diag_handler.err(&format!("failed to remove bitcode: {}", e));
+ }
}
- }
- drop(handlers);
+ drop(handlers);
+ }
Ok(module.into_compiled_module(config.emit_obj,
config.emit_bc,
config.emit_bc_compressed,
/// Basically all of this is us attempting to follow in the footsteps of clang
/// on iOS. See #35968 for lots more info.
unsafe fn embed_bitcode(cgcx: &CodegenContext,
- llcx: ContextRef,
- llmod: ModuleRef,
+ llcx: &llvm::Context,
+ llmod: &llvm::Module,
bitcode: Option<&[u8]>) {
let llconst = C_bytes_in_context(llcx, bitcode.unwrap_or(&[]));
let llglobal = llvm::LLVMAddGlobal(
llmod,
- val_ty(llconst).to_ref(),
+ val_ty(llconst),
"rustc.embedded.module\0".as_ptr() as *const _,
);
llvm::LLVMSetInitializer(llglobal, llconst);
let llconst = C_bytes_in_context(llcx, &[]);
let llglobal = llvm::LLVMAddGlobal(
llmod,
- val_ty(llconst).to_ref(),
+ val_ty(llconst),
"rustc.embedded.cmdline\0".as_ptr() as *const _,
);
llvm::LLVMSetInitializer(llglobal, llconst);
}
fn need_crate_bitcode_for_rlib(sess: &Session) -> bool {
- sess.crate_types.borrow().contains(&config::CrateTypeRlib) &&
+ sess.crate_types.borrow().contains(&config::CrateType::Rlib) &&
sess.opts.output_types.contains_key(&OutputType::Exe)
}
// anything about it yet until we've got a final product.
Lto::Yes | Lto::Fat | Lto::Thin => {
cgcx.crate_types.len() != 1 ||
- cgcx.crate_types[0] != config::CrateTypeRlib
+ cgcx.crate_types[0] != config::CrateType::Rlib
}
// When we're automatically doing ThinLTO for multi-codegen-unit
}
}
-pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
+pub unsafe fn with_llvm_pmb(llmod: &llvm::Module,
config: &ModuleConfig,
opt_level: llvm::CodeGenOptLevel,
prepare_for_thin_lto: bool,
- f: &mut dyn FnMut(llvm::PassManagerBuilderRef)) {
+ f: &mut dyn FnMut(&llvm::PassManagerBuilder)) {
use std::ptr;
// Create the PassManagerBuilder for LLVM. We configure it with
fn msvc_imps_needed(tcx: TyCtxt) -> bool {
tcx.sess.target.target.options.is_like_msvc &&
- tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib)
+ tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateType::Rlib)
}
// Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
// when using MSVC linker. We do this only for data, as linker can fix up
// code references on its own.
// See #26591, #27438
-fn create_msvc_imps(cgcx: &CodegenContext, llcx: ContextRef, llmod: ModuleRef) {
+fn create_msvc_imps(cgcx: &CodegenContext, llcx: &llvm::Context, llmod: &llvm::Module) {
if !cgcx.msvc_imps_needed {
return
}
.collect::<Vec<_>>();
for (imp_name, val) in globals {
let imp = llvm::LLVMAddGlobal(llmod,
- i8p_ty.to_ref(),
+ i8p_ty,
imp_name.as_ptr() as *const _);
llvm::LLVMSetInitializer(imp, consts::ptrcast(val, i8p_ty));
llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
//!
//! Hopefully useful general knowledge about codegen:
//!
-//! * There's no way to find out the Ty type of a ValueRef. Doing so
+//! * There's no way to find out the Ty type of a Value. Doing so
//! would be "trying to get the eggs out of an omelette" (credit:
-//! pcwalton). You can, instead, find out its TypeRef by calling val_ty,
-//! but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int,
-//! int) and rec(x=int, y=int, z=int) will have the same TypeRef.
+//! pcwalton). You can, instead, find out its llvm::Type by calling val_ty,
+//! but one llvm::Type corresponds to many `Ty`s; for instance, tup(int, int,
+//! int) and rec(x=int, y=int, z=int) will have the same llvm::Type.
use super::ModuleLlvm;
use super::ModuleSource;
use abi;
use back::link;
-use back::write::{self, OngoingCodegen, create_target_machine};
-use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param};
-use llvm;
+use back::write::{self, OngoingCodegen};
+use llvm::{self, TypeKind, get_param};
use metadata;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::middle::lang_items::StartFnLangItem;
use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
use rustc::middle::exported_symbols;
use rustc::util::common::{time, print_time_passes_entry};
-use rustc::session::config::{self, NoDebugInfo};
+use rustc::util::profiling::ProfileCategory;
+use rustc::session::config::{self, DebugInfo, EntryFnType};
use rustc::session::Session;
use rustc_incremental;
use allocator;
use rustc_mir::monomorphize::item::DefPathBasedNames;
use common::{self, C_struct_in_context, C_array, val_ty};
use consts;
-use context::{self, CodegenCx};
+use context::CodegenCx;
use debuginfo;
use declare;
use meth;
use std::any::Any;
use std::ffi::CString;
-use std::str;
use std::sync::Arc;
use std::time::{Instant, Duration};
use std::i32;
use syntax::attr;
use rustc::hir::{self, CodegenFnAttrs};
+use value::Value;
+
use mir::operand::OperandValue;
use rustc_codegen_utils::check_for_rustc_errors_attr;
-pub struct StatRecorder<'a, 'tcx: 'a> {
- cx: &'a CodegenCx<'a, 'tcx>,
+pub struct StatRecorder<'a, 'll: 'a, 'tcx: 'll> {
+ cx: &'a CodegenCx<'ll, 'tcx>,
name: Option<String>,
istart: usize,
}
-impl<'a, 'tcx> StatRecorder<'a, 'tcx> {
- pub fn new(cx: &'a CodegenCx<'a, 'tcx>, name: String) -> StatRecorder<'a, 'tcx> {
+impl StatRecorder<'a, 'll, 'tcx> {
+ pub fn new(cx: &'a CodegenCx<'ll, 'tcx>, name: String) -> Self {
let istart = cx.stats.borrow().n_llvm_insns;
StatRecorder {
cx,
}
}
-impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> {
+impl Drop for StatRecorder<'a, 'll, 'tcx> {
fn drop(&mut self) {
if self.cx.sess().codegen_stats() {
let mut stats = self.cx.stats.borrow_mut();
}
}
-pub fn compare_simd_types<'a, 'tcx>(
- bx: &Builder<'a, 'tcx>,
- lhs: ValueRef,
- rhs: ValueRef,
+pub fn compare_simd_types(
+ bx: &Builder<'a, 'll, 'tcx>,
+ lhs: &'ll Value,
+ rhs: &'ll Value,
t: Ty<'tcx>,
- ret_ty: Type,
+ ret_ty: &'ll Type,
op: hir::BinOpKind
-) -> ValueRef {
+) -> &'ll Value {
let signed = match t.sty {
ty::TyFloat(_) => {
let cmp = bin_op_to_fcmp_predicate(op);
/// The `old_info` argument is a bit funny. It is intended for use
/// in an upcast, where the new vtable for an object will be derived
/// from the old one.
-pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>,
- source: Ty<'tcx>,
- target: Ty<'tcx>,
- old_info: Option<ValueRef>)
- -> ValueRef {
+pub fn unsized_info(
+ cx: &CodegenCx<'ll, 'tcx>,
+ source: Ty<'tcx>,
+ target: Ty<'tcx>,
+ old_info: Option<&'ll Value>,
+) -> &'ll Value {
let (source, target) = cx.tcx.struct_lockstep_tails(source, target);
match (&source.sty, &target.sty) {
(&ty::TyArray(_, len), &ty::TySlice(_)) => {
}
/// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer.
-pub fn unsize_thin_ptr<'a, 'tcx>(
- bx: &Builder<'a, 'tcx>,
- src: ValueRef,
+pub fn unsize_thin_ptr(
+ bx: &Builder<'a, 'll, 'tcx>,
+ src: &'ll Value,
src_ty: Ty<'tcx>,
dst_ty: Ty<'tcx>
-) -> (ValueRef, ValueRef) {
+) -> (&'ll Value, &'ll Value) {
debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty);
match (&src_ty.sty, &dst_ty.sty) {
(&ty::TyRef(_, a, _),
/// Coerce `src`, which is a reference to a value of type `src_ty`,
/// to a value of type `dst_ty` and store the result in `dst`
-pub fn coerce_unsized_into<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
- src: PlaceRef<'tcx>,
- dst: PlaceRef<'tcx>) {
+pub fn coerce_unsized_into(
+ bx: &Builder<'a, 'll, 'tcx>,
+ src: PlaceRef<'ll, 'tcx>,
+ dst: PlaceRef<'ll, 'tcx>
+) {
let src_ty = src.layout.ty;
let dst_ty = dst.layout.ty;
let coerce_ptr = || {
}
pub fn cast_shift_expr_rhs(
- cx: &Builder, op: hir::BinOpKind, lhs: ValueRef, rhs: ValueRef
-) -> ValueRef {
+ cx: &Builder<'_, 'll, '_>, op: hir::BinOpKind, lhs: &'ll Value, rhs: &'ll Value
+) -> &'ll Value {
cast_shift_rhs(op, lhs, rhs, |a, b| cx.trunc(a, b), |a, b| cx.zext(a, b))
}
-fn cast_shift_rhs<F, G>(op: hir::BinOpKind,
- lhs: ValueRef,
- rhs: ValueRef,
+fn cast_shift_rhs<'ll, F, G>(op: hir::BinOpKind,
+ lhs: &'ll Value,
+ rhs: &'ll Value,
trunc: F,
zext: G)
- -> ValueRef
- where F: FnOnce(ValueRef, Type) -> ValueRef,
- G: FnOnce(ValueRef, Type) -> ValueRef
+ -> &'ll Value
+ where F: FnOnce(&'ll Value, &'ll Type) -> &'ll Value,
+ G: FnOnce(&'ll Value, &'ll Type) -> &'ll Value
{
// Shifts may have any size int on the rhs
if op.is_shift() {
let mut rhs_llty = val_ty(rhs);
let mut lhs_llty = val_ty(lhs);
- if rhs_llty.kind() == Vector {
+ if rhs_llty.kind() == TypeKind::Vector {
rhs_llty = rhs_llty.element_type()
}
- if lhs_llty.kind() == Vector {
+ if lhs_llty.kind() == TypeKind::Vector {
lhs_llty = lhs_llty.element_type()
}
let rhs_sz = rhs_llty.int_width();
sess.target.target.options.is_like_msvc
}
-pub fn call_assume<'a, 'tcx>(bx: &Builder<'a, 'tcx>, val: ValueRef) {
+pub fn call_assume(bx: &Builder<'_, 'll, '_>, val: &'ll Value) {
let assume_intrinsic = bx.cx.get_intrinsic("llvm.assume");
bx.call(assume_intrinsic, &[val], None);
}
-pub fn from_immediate(bx: &Builder, val: ValueRef) -> ValueRef {
+pub fn from_immediate(bx: &Builder<'_, 'll, '_>, val: &'ll Value) -> &'ll Value {
if val_ty(val) == Type::i1(bx.cx) {
bx.zext(val, Type::i8(bx.cx))
} else {
}
}
-pub fn to_immediate(bx: &Builder, val: ValueRef, layout: layout::TyLayout) -> ValueRef {
+pub fn to_immediate(
+ bx: &Builder<'_, 'll, '_>,
+ val: &'ll Value,
+ layout: layout::TyLayout,
+) -> &'ll Value {
if let layout::Abi::Scalar(ref scalar) = layout.abi {
return to_immediate_scalar(bx, val, scalar);
}
val
}
-pub fn to_immediate_scalar(bx: &Builder, val: ValueRef, scalar: &layout::Scalar) -> ValueRef {
+pub fn to_immediate_scalar(
+ bx: &Builder<'_, 'll, '_>,
+ val: &'ll Value,
+ scalar: &layout::Scalar,
+) -> &'ll Value {
if scalar.is_bool() {
return bx.trunc(val, Type::i1(bx.cx));
}
val
}
-pub fn call_memcpy(bx: &Builder,
- dst: ValueRef,
- src: ValueRef,
- n_bytes: ValueRef,
- align: Align,
- flags: MemFlags) {
+pub fn call_memcpy(
+ bx: &Builder<'_, 'll, '_>,
+ dst: &'ll Value,
+ src: &'ll Value,
+ n_bytes: &'ll Value,
+ align: Align,
+ flags: MemFlags,
+) {
if flags.contains(MemFlags::NONTEMPORAL) {
// HACK(nox): This is inefficient but there is no nontemporal memcpy.
let val = bx.load(src, align);
bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
}
-pub fn memcpy_ty<'a, 'tcx>(
- bx: &Builder<'a, 'tcx>,
- dst: ValueRef,
- src: ValueRef,
+pub fn memcpy_ty(
+ bx: &Builder<'_, 'll, 'tcx>,
+ dst: &'ll Value,
+ src: &'ll Value,
layout: TyLayout<'tcx>,
align: Align,
flags: MemFlags,
call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags);
}
-pub fn call_memset<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
- ptr: ValueRef,
- fill_byte: ValueRef,
- size: ValueRef,
- align: ValueRef,
- volatile: bool) -> ValueRef {
+pub fn call_memset(
+ bx: &Builder<'_, 'll, '_>,
+ ptr: &'ll Value,
+ fill_byte: &'ll Value,
+ size: &'ll Value,
+ align: &'ll Value,
+ volatile: bool,
+) -> &'ll Value {
let ptr_width = &bx.cx.sess().target.target.target_pointer_width;
let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width);
let llintrinsicfn = bx.cx.get_intrinsic(&intrinsic_key);
mir::codegen_mir(cx, lldecl, &mir, instance, sig);
}
-pub fn set_link_section(llval: ValueRef, attrs: &CodegenFnAttrs) {
+pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
let sect = match attrs.link_section {
Some(name) => name,
None => return,
let et = cx.sess().entry_fn.get().map(|e| e.2);
match et {
- Some(config::EntryMain) => create_entry_fn(cx, span, main_llfn, main_def_id, true),
- Some(config::EntryStart) => create_entry_fn(cx, span, main_llfn, main_def_id, false),
+ Some(EntryFnType::Main) => create_entry_fn(cx, span, main_llfn, main_def_id, true),
+ Some(EntryFnType::Start) => create_entry_fn(cx, span, main_llfn, main_def_id, false),
None => {} // Do nothing.
}
- fn create_entry_fn<'cx>(cx: &'cx CodegenCx,
- sp: Span,
- rust_main: ValueRef,
- rust_main_def_id: DefId,
- use_start_lang_item: bool) {
- let llfty = Type::func(&[Type::c_int(cx), Type::i8p(cx).ptr_to()], &Type::c_int(cx));
+ fn create_entry_fn(
+ cx: &CodegenCx<'ll, '_>,
+ sp: Span,
+ rust_main: &'ll Value,
+ rust_main_def_id: DefId,
+ use_start_lang_item: bool,
+ ) {
+ let llfty = Type::func(&[Type::c_int(cx), Type::i8p(cx).ptr_to()], Type::c_int(cx));
let main_ret_ty = cx.tcx.fn_sig(rust_main_def_id).output();
// Given that `main()` has no arguments,
}
fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
- llmod_id: &str,
+ llvm_module: &ModuleLlvm,
link_meta: &LinkMeta)
- -> (ContextRef, ModuleRef, EncodedMetadata) {
+ -> EncodedMetadata {
use std::io::Write;
use flate2::Compression;
use flate2::write::DeflateEncoder;
- let (metadata_llcx, metadata_llmod) = unsafe {
- context::create_context_and_module(tcx.sess, llmod_id)
- };
+ let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum MetadataKind {
let kind = tcx.sess.crate_types.borrow().iter().map(|ty| {
match *ty {
- config::CrateTypeExecutable |
- config::CrateTypeStaticlib |
- config::CrateTypeCdylib => MetadataKind::None,
+ config::CrateType::Executable |
+ config::CrateType::Staticlib |
+ config::CrateType::Cdylib => MetadataKind::None,
- config::CrateTypeRlib => MetadataKind::Uncompressed,
+ config::CrateType::Rlib => MetadataKind::Uncompressed,
- config::CrateTypeDylib |
- config::CrateTypeProcMacro => MetadataKind::Compressed,
+ config::CrateType::Dylib |
+ config::CrateType::ProcMacro => MetadataKind::Compressed,
}
}).max().unwrap_or(MetadataKind::None);
if kind == MetadataKind::None {
- return (metadata_llcx,
- metadata_llmod,
- EncodedMetadata::new());
+ return EncodedMetadata::new();
}
let metadata = tcx.encode_metadata(link_meta);
if kind == MetadataKind::Uncompressed {
- return (metadata_llcx, metadata_llmod, metadata);
+ return metadata;
}
assert!(kind == MetadataKind::Compressed);
let name = exported_symbols::metadata_symbol_name(tcx);
let buf = CString::new(name).unwrap();
let llglobal = unsafe {
- llvm::LLVMAddGlobal(metadata_llmod, val_ty(llconst).to_ref(), buf.as_ptr())
+ llvm::LLVMAddGlobal(metadata_llmod, val_ty(llconst), buf.as_ptr())
};
unsafe {
llvm::LLVMSetInitializer(llglobal, llconst);
let directive = CString::new(directive).unwrap();
llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr())
}
- return (metadata_llcx, metadata_llmod, metadata);
+ return metadata;
}
-pub struct ValueIter {
- cur: ValueRef,
- step: unsafe extern "C" fn(ValueRef) -> ValueRef,
+pub struct ValueIter<'ll> {
+ cur: Option<&'ll Value>,
+ step: unsafe extern "C" fn(&'ll Value) -> Option<&'ll Value>,
}
-impl Iterator for ValueIter {
- type Item = ValueRef;
+impl Iterator for ValueIter<'ll> {
+ type Item = &'ll Value;
- fn next(&mut self) -> Option<ValueRef> {
+ fn next(&mut self) -> Option<&'ll Value> {
let old = self.cur;
- if !old.is_null() {
+ if let Some(old) = old {
self.cur = unsafe { (self.step)(old) };
- Some(old)
- } else {
- None
}
+ old
}
}
-pub fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter {
+pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
unsafe {
ValueIter {
cur: llvm::LLVMGetFirstGlobal(llmod),
let link_meta = link::build_link_meta(crate_hash);
// Codegen the metadata.
+ tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen));
let llmod_id = "metadata";
- let (metadata_llcx, metadata_llmod, metadata) =
- time(tcx.sess, "write metadata", || {
- write_metadata(tcx, llmod_id, &link_meta)
- });
+ let metadata_llvm_module = ModuleLlvm::new(tcx.sess, llmod_id);
+ let metadata = time(tcx.sess, "write metadata", || {
+ write_metadata(tcx, &metadata_llvm_module, &link_meta)
+ });
+ tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen));
let metadata_module = ModuleCodegen {
name: link::METADATA_MODULE_NAME.to_string(),
llmod_id: llmod_id.to_string(),
- source: ModuleSource::Codegened(ModuleLlvm {
- llcx: metadata_llcx,
- llmod: metadata_llmod,
- tm: create_target_machine(tcx.sess, false),
- }),
+ source: ModuleSource::Codegened(metadata_llvm_module),
kind: ModuleKind::Metadata,
};
let allocator_module = if let Some(kind) = *tcx.sess.allocator_kind.get() {
unsafe {
let llmod_id = "allocator";
- let (llcx, llmod) =
- context::create_context_and_module(tcx.sess, llmod_id);
- let modules = ModuleLlvm {
- llmod,
- llcx,
- tm: create_target_machine(tcx.sess, false),
- };
+ let modules = ModuleLlvm::new(tcx.sess, llmod_id);
time(tcx.sess, "write allocator module", || {
allocator::codegen(tcx, &modules, kind)
});
let load_wasm_items = tcx.sess.crate_types.borrow()
.iter()
- .any(|c| *c != config::CrateTypeRlib) &&
+ .any(|c| *c != config::CrateType::Rlib) &&
tcx.sess.opts.target_triple.triple() == "wasm32-unknown-unknown";
if load_wasm_items {
.to_fingerprint().to_hex());
// Instantiate monomorphizations without filling out definitions yet...
- let cx = CodegenCx::new(tcx, cgu, &llmod_id);
- let module = {
+ let llvm_module = ModuleLlvm::new(tcx.sess, &llmod_id);
+ let stats = {
+ let cx = CodegenCx::new(tcx, cgu, &llvm_module);
let mono_items = cx.codegen_unit
.items_in_deterministic_order(cx.tcx);
for &(mono_item, (linkage, visibility)) in &mono_items {
// Run replace-all-uses-with for statics that need it
for &(old_g, new_g) in cx.statics_to_rauw.borrow().iter() {
unsafe {
- let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g));
+ let bitcast = llvm::LLVMConstPointerCast(new_g, val_ty(old_g));
llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
llvm::LLVMDeleteGlobal(old_g);
}
unsafe {
let g = llvm::LLVMAddGlobal(cx.llmod,
- val_ty(array).to_ref(),
+ val_ty(array),
name.as_ptr());
llvm::LLVMSetInitializer(g, array);
llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
}
// Finalize debuginfo
- if cx.sess().opts.debuginfo != NoDebugInfo {
+ if cx.sess().opts.debuginfo != DebugInfo::None {
debuginfo::finalize(&cx);
}
- let llvm_module = ModuleLlvm {
- llcx: cx.llcx,
- llmod: cx.llmod,
- tm: create_target_machine(cx.sess(), false),
- };
-
- ModuleCodegen {
- name: cgu_name,
- source: ModuleSource::Codegened(llvm_module),
- kind: ModuleKind::Regular,
- llmod_id,
- }
+ cx.stats.into_inner()
};
- (cx.into_stats(), module)
+ (stats, ModuleCodegen {
+ name: cgu_name,
+ source: ModuleSource::Codegened(llvm_module),
+ kind: ModuleKind::Regular,
+ llmod_id,
+ })
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(dead_code)] // FFI wrappers
-
-use llvm;
use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect};
-use llvm::{Opcode, IntPredicate, RealPredicate, False, OperandBundleDef};
-use llvm::{ValueRef, BasicBlockRef, BuilderRef};
+use llvm::{IntPredicate, RealPredicate, False, OperandBundleDef};
+use llvm::{self, BasicBlock};
use common::*;
use type_::Type;
use value::Value;
use std::ffi::CString;
use std::ops::Range;
use std::ptr;
-use syntax_pos::Span;
// All Builders must have an llfn associated with them
#[must_use]
-pub struct Builder<'a, 'tcx: 'a> {
- pub llbuilder: BuilderRef,
- pub cx: &'a CodegenCx<'a, 'tcx>,
+pub struct Builder<'a, 'll: 'a, 'tcx: 'll> {
+ pub llbuilder: &'ll mut llvm::Builder<'ll>,
+ pub cx: &'a CodegenCx<'ll, 'tcx>,
}
-impl<'a, 'tcx> Drop for Builder<'a, 'tcx> {
+impl Drop for Builder<'a, 'll, 'tcx> {
fn drop(&mut self) {
unsafe {
- llvm::LLVMDisposeBuilder(self.llbuilder);
+ llvm::LLVMDisposeBuilder(&mut *(self.llbuilder as *mut _));
}
}
}
}
}
-impl<'a, 'tcx> Builder<'a, 'tcx> {
- pub fn new_block<'b>(cx: &'a CodegenCx<'a, 'tcx>, llfn: ValueRef, name: &'b str) -> Self {
+impl Builder<'a, 'll, 'tcx> {
+ pub fn new_block<'b>(cx: &'a CodegenCx<'ll, 'tcx>, llfn: &'ll Value, name: &'b str) -> Self {
let bx = Builder::with_cx(cx);
let llbb = unsafe {
let name = CString::new(name).unwrap();
bx
}
- pub fn with_cx(cx: &'a CodegenCx<'a, 'tcx>) -> Self {
+ pub fn with_cx(cx: &'a CodegenCx<'ll, 'tcx>) -> Self {
// Create a fresh builder from the crate context.
let llbuilder = unsafe {
llvm::LLVMCreateBuilderInContext(cx.llcx)
}
}
- pub fn build_sibling_block<'b>(&self, name: &'b str) -> Builder<'a, 'tcx> {
+ pub fn build_sibling_block<'b>(&self, name: &'b str) -> Builder<'a, 'll, 'tcx> {
Builder::new_block(self.cx, self.llfn(), name)
}
self.cx.tcx
}
- pub fn llfn(&self) -> ValueRef {
+ pub fn llfn(&self) -> &'ll Value {
unsafe {
llvm::LLVMGetBasicBlockParent(self.llbb())
}
}
- pub fn llbb(&self) -> BasicBlockRef {
+ pub fn llbb(&self) -> &'ll BasicBlock {
unsafe {
llvm::LLVMGetInsertBlock(self.llbuilder)
}
}
}
- pub fn set_value_name(&self, value: ValueRef, name: &str) {
+ pub fn set_value_name(&self, value: &'ll Value, name: &str) {
let cname = CString::new(name.as_bytes()).unwrap();
unsafe {
llvm::LLVMSetValueName(value, cname.as_ptr());
}
}
- pub fn position_before(&self, insn: ValueRef) {
- unsafe {
- llvm::LLVMPositionBuilderBefore(self.llbuilder, insn);
- }
- }
-
- pub fn position_at_end(&self, llbb: BasicBlockRef) {
+ pub fn position_at_end(&self, llbb: &'ll BasicBlock) {
unsafe {
llvm::LLVMPositionBuilderAtEnd(self.llbuilder, llbb);
}
}
- pub fn position_at_start(&self, llbb: BasicBlockRef) {
+ pub fn position_at_start(&self, llbb: &'ll BasicBlock) {
unsafe {
llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb);
}
}
}
- pub fn ret(&self, v: ValueRef) {
+ pub fn ret(&self, v: &'ll Value) {
self.count_insn("ret");
unsafe {
llvm::LLVMBuildRet(self.llbuilder, v);
}
}
- pub fn aggregate_ret(&self, ret_vals: &[ValueRef]) {
- unsafe {
- llvm::LLVMBuildAggregateRet(self.llbuilder,
- ret_vals.as_ptr(),
- ret_vals.len() as c_uint);
- }
- }
-
- pub fn br(&self, dest: BasicBlockRef) {
+ pub fn br(&self, dest: &'ll BasicBlock) {
self.count_insn("br");
unsafe {
llvm::LLVMBuildBr(self.llbuilder, dest);
}
}
- pub fn cond_br(&self, cond: ValueRef, then_llbb: BasicBlockRef, else_llbb: BasicBlockRef) {
+ pub fn cond_br(
+ &self,
+ cond: &'ll Value,
+ then_llbb: &'ll BasicBlock,
+ else_llbb: &'ll BasicBlock,
+ ) {
self.count_insn("condbr");
unsafe {
llvm::LLVMBuildCondBr(self.llbuilder, cond, then_llbb, else_llbb);
}
}
- pub fn switch(&self, v: ValueRef, else_llbb: BasicBlockRef, num_cases: usize) -> ValueRef {
+ pub fn switch(
+ &self,
+ v: &'ll Value,
+ else_llbb: &'ll BasicBlock,
+ num_cases: usize,
+ ) -> &'ll Value {
unsafe {
llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, num_cases as c_uint)
}
}
- pub fn indirect_br(&self, addr: ValueRef, num_dests: usize) {
- self.count_insn("indirectbr");
- unsafe {
- llvm::LLVMBuildIndirectBr(self.llbuilder, addr, num_dests as c_uint);
- }
- }
-
pub fn invoke(&self,
- llfn: ValueRef,
- args: &[ValueRef],
- then: BasicBlockRef,
- catch: BasicBlockRef,
- bundle: Option<&OperandBundleDef>) -> ValueRef {
+ llfn: &'ll Value,
+ args: &[&'ll Value],
+ then: &'ll BasicBlock,
+ catch: &'ll BasicBlock,
+ bundle: Option<&OperandBundleDef<'ll>>) -> &'ll Value {
self.count_insn("invoke");
- debug!("Invoke {:?} with args ({})",
- Value(llfn),
- args.iter()
- .map(|&v| format!("{:?}", Value(v)))
- .collect::<Vec<String>>()
- .join(", "));
+ debug!("Invoke {:?} with args ({:?})",
+ llfn,
+ args);
let args = self.check_call("invoke", llfn, args);
- let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut());
+ let bundle = bundle.map(|b| &*b.raw);
unsafe {
llvm::LLVMRustBuildInvoke(self.llbuilder,
}
/* Arithmetic */
- pub fn add(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn add(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("add");
unsafe {
llvm::LLVMBuildAdd(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn nswadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
- self.count_insn("nswadd");
- unsafe {
- llvm::LLVMBuildNSWAdd(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- pub fn nuwadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
- self.count_insn("nuwadd");
- unsafe {
- llvm::LLVMBuildNUWAdd(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- pub fn fadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn fadd(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("fadd");
unsafe {
llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn fadd_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn fadd_fast(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("fadd");
unsafe {
let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname());
}
}
- pub fn sub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn sub(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("sub");
unsafe {
llvm::LLVMBuildSub(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn nswsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
- self.count_insn("nswsub");
- unsafe {
- llvm::LLVMBuildNSWSub(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- pub fn nuwsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
- self.count_insn("nuwsub");
- unsafe {
- llvm::LLVMBuildNUWSub(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- pub fn fsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn fsub(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("fsub");
unsafe {
llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn fsub_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn fsub_fast(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("fsub");
unsafe {
let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname());
}
}
- pub fn mul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn mul(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("mul");
unsafe {
llvm::LLVMBuildMul(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn nswmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
- self.count_insn("nswmul");
- unsafe {
- llvm::LLVMBuildNSWMul(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- pub fn nuwmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
- self.count_insn("nuwmul");
- unsafe {
- llvm::LLVMBuildNUWMul(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- pub fn fmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn fmul(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("fmul");
unsafe {
llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn fmul_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn fmul_fast(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("fmul");
unsafe {
let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname());
}
- pub fn udiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn udiv(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("udiv");
unsafe {
llvm::LLVMBuildUDiv(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn exactudiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn exactudiv(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("exactudiv");
unsafe {
llvm::LLVMBuildExactUDiv(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn sdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn sdiv(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("sdiv");
unsafe {
llvm::LLVMBuildSDiv(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn exactsdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn exactsdiv(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("exactsdiv");
unsafe {
llvm::LLVMBuildExactSDiv(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn fdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn fdiv(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("fdiv");
unsafe {
llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn fdiv_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn fdiv_fast(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("fdiv");
unsafe {
let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname());
}
}
- pub fn urem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn urem(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("urem");
unsafe {
llvm::LLVMBuildURem(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn srem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn srem(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("srem");
unsafe {
llvm::LLVMBuildSRem(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn frem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn frem(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("frem");
unsafe {
llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn frem_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn frem_fast(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("frem");
unsafe {
let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname());
}
}
- pub fn shl(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn shl(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("shl");
unsafe {
llvm::LLVMBuildShl(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn lshr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn lshr(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("lshr");
unsafe {
llvm::LLVMBuildLShr(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn ashr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn ashr(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("ashr");
unsafe {
llvm::LLVMBuildAShr(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn and(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn and(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("and");
unsafe {
llvm::LLVMBuildAnd(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn or(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn or(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("or");
unsafe {
llvm::LLVMBuildOr(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn xor(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn xor(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("xor");
unsafe {
llvm::LLVMBuildXor(self.llbuilder, lhs, rhs, noname())
}
}
- pub fn binop(&self, op: Opcode, lhs: ValueRef, rhs: ValueRef)
- -> ValueRef {
- self.count_insn("binop");
- unsafe {
- llvm::LLVMBuildBinOp(self.llbuilder, op, lhs, rhs, noname())
- }
- }
-
- pub fn neg(&self, v: ValueRef) -> ValueRef {
+ pub fn neg(&self, v: &'ll Value) -> &'ll Value {
self.count_insn("neg");
unsafe {
llvm::LLVMBuildNeg(self.llbuilder, v, noname())
}
}
- pub fn nswneg(&self, v: ValueRef) -> ValueRef {
- self.count_insn("nswneg");
- unsafe {
- llvm::LLVMBuildNSWNeg(self.llbuilder, v, noname())
- }
- }
-
- pub fn nuwneg(&self, v: ValueRef) -> ValueRef {
- self.count_insn("nuwneg");
- unsafe {
- llvm::LLVMBuildNUWNeg(self.llbuilder, v, noname())
- }
- }
- pub fn fneg(&self, v: ValueRef) -> ValueRef {
+ pub fn fneg(&self, v: &'ll Value) -> &'ll Value {
self.count_insn("fneg");
unsafe {
llvm::LLVMBuildFNeg(self.llbuilder, v, noname())
}
}
- pub fn not(&self, v: ValueRef) -> ValueRef {
+ pub fn not(&self, v: &'ll Value) -> &'ll Value {
self.count_insn("not");
unsafe {
llvm::LLVMBuildNot(self.llbuilder, v, noname())
}
}
- pub fn alloca(&self, ty: Type, name: &str, align: Align) -> ValueRef {
+ pub fn alloca(&self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value {
let bx = Builder::with_cx(self.cx);
bx.position_at_start(unsafe {
llvm::LLVMGetFirstBasicBlock(self.llfn())
bx.dynamic_alloca(ty, name, align)
}
- pub fn dynamic_alloca(&self, ty: Type, name: &str, align: Align) -> ValueRef {
+ pub fn dynamic_alloca(&self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value {
self.count_insn("alloca");
unsafe {
let alloca = if name.is_empty() {
- llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
+ llvm::LLVMBuildAlloca(self.llbuilder, ty, noname())
} else {
let name = CString::new(name).unwrap();
- llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(),
+ llvm::LLVMBuildAlloca(self.llbuilder, ty,
name.as_ptr())
};
llvm::LLVMSetAlignment(alloca, align.abi() as c_uint);
}
}
- pub fn free(&self, ptr: ValueRef) {
- self.count_insn("free");
- unsafe {
- llvm::LLVMBuildFree(self.llbuilder, ptr);
- }
- }
-
- pub fn load(&self, ptr: ValueRef, align: Align) -> ValueRef {
+ pub fn load(&self, ptr: &'ll Value, align: Align) -> &'ll Value {
self.count_insn("load");
unsafe {
let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname());
}
}
- pub fn volatile_load(&self, ptr: ValueRef) -> ValueRef {
+ pub fn volatile_load(&self, ptr: &'ll Value) -> &'ll Value {
self.count_insn("load.volatile");
unsafe {
let insn = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname());
}
}
- pub fn atomic_load(&self, ptr: ValueRef, order: AtomicOrdering, align: Align) -> ValueRef {
+ pub fn atomic_load(&self, ptr: &'ll Value, order: AtomicOrdering, align: Align) -> &'ll Value {
self.count_insn("load.atomic");
unsafe {
let load = llvm::LLVMRustBuildAtomicLoad(self.llbuilder, ptr, noname(), order);
}
- pub fn range_metadata(&self, load: ValueRef, range: Range<u128>) {
+ pub fn range_metadata(&self, load: &'ll Value, range: Range<u128>) {
unsafe {
let llty = val_ty(load);
let v = [
}
}
- pub fn nonnull_metadata(&self, load: ValueRef) {
+ pub fn nonnull_metadata(&self, load: &'ll Value) {
unsafe {
llvm::LLVMSetMetadata(load, llvm::MD_nonnull as c_uint,
llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0));
}
}
- pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef {
+ pub fn store(&self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
self.store_with_flags(val, ptr, align, MemFlags::empty())
}
pub fn store_with_flags(
&self,
- val: ValueRef,
- ptr: ValueRef,
+ val: &'ll Value,
+ ptr: &'ll Value,
align: Align,
flags: MemFlags,
- ) -> ValueRef {
- debug!("Store {:?} -> {:?} ({:?})", Value(val), Value(ptr), flags);
- assert!(!self.llbuilder.is_null());
+ ) -> &'ll Value {
+ debug!("Store {:?} -> {:?} ({:?})", val, ptr, flags);
self.count_insn("store");
let ptr = self.check_store(val, ptr);
unsafe {
}
}
- pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef,
+ pub fn atomic_store(&self, val: &'ll Value, ptr: &'ll Value,
order: AtomicOrdering, align: Align) {
- debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
+ debug!("Store {:?} -> {:?}", val, ptr);
self.count_insn("store.atomic");
let ptr = self.check_store(val, ptr);
unsafe {
}
}
- pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
+ pub fn gep(&self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
self.count_insn("gep");
unsafe {
llvm::LLVMBuildGEP(self.llbuilder, ptr, indices.as_ptr(),
}
}
- pub fn inbounds_gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
+ pub fn inbounds_gep(&self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
self.count_insn("inboundsgep");
unsafe {
llvm::LLVMBuildInBoundsGEP(
}
}
- pub fn struct_gep(&self, ptr: ValueRef, idx: u64) -> ValueRef {
+ pub fn struct_gep(&self, ptr: &'ll Value, idx: u64) -> &'ll Value {
self.count_insn("structgep");
assert_eq!(idx as c_uint as u64, idx);
unsafe {
}
}
- pub fn global_string(&self, _str: *const c_char) -> ValueRef {
- self.count_insn("globalstring");
- unsafe {
- llvm::LLVMBuildGlobalString(self.llbuilder, _str, noname())
- }
- }
-
- pub fn global_string_ptr(&self, _str: *const c_char) -> ValueRef {
- self.count_insn("globalstringptr");
- unsafe {
- llvm::LLVMBuildGlobalStringPtr(self.llbuilder, _str, noname())
- }
- }
-
/* Casts */
- pub fn trunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn trunc(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("trunc");
unsafe {
- llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn zext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn zext(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("zext");
unsafe {
- llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn sext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn sext(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("sext");
unsafe {
- llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn fptoui(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn fptoui(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("fptoui");
unsafe {
- llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn fptosi(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn fptosi(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("fptosi");
unsafe {
- llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty.to_ref(),noname())
+ llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty,noname())
}
}
- pub fn uitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn uitofp(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("uitofp");
unsafe {
- llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn sitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn sitofp(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("sitofp");
unsafe {
- llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn fptrunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn fptrunc(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("fptrunc");
unsafe {
- llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn fpext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn fpext(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("fpext");
unsafe {
- llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn ptrtoint(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn ptrtoint(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("ptrtoint");
unsafe {
- llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn inttoptr(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn inttoptr(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("inttoptr");
unsafe {
- llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn bitcast(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("bitcast");
unsafe {
- llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
- }
- }
-
- pub fn zext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
- self.count_insn("zextorbitcast");
- unsafe {
- llvm::LLVMBuildZExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn sext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
- self.count_insn("sextorbitcast");
- unsafe {
- llvm::LLVMBuildSExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
- }
- }
-
- pub fn trunc_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
- self.count_insn("truncorbitcast");
- unsafe {
- llvm::LLVMBuildTruncOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
- }
- }
-
- pub fn cast(&self, op: Opcode, val: ValueRef, dest_ty: Type) -> ValueRef {
- self.count_insn("cast");
- unsafe {
- llvm::LLVMBuildCast(self.llbuilder, op, val, dest_ty.to_ref(), noname())
- }
- }
-
- pub fn pointercast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ pub fn pointercast(&self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
self.count_insn("pointercast");
unsafe {
- llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty, noname())
}
}
- pub fn intcast(&self, val: ValueRef, dest_ty: Type, is_signed: bool) -> ValueRef {
+ pub fn intcast(&self, val: &'ll Value, dest_ty: &'ll Type, is_signed: bool) -> &'ll Value {
self.count_insn("intcast");
unsafe {
- llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), is_signed)
- }
- }
-
- pub fn fpcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
- self.count_insn("fpcast");
- unsafe {
- llvm::LLVMBuildFPCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ llvm::LLVMRustBuildIntCast(self.llbuilder, val, dest_ty, is_signed)
}
}
-
/* Comparisons */
- pub fn icmp(&self, op: IntPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn icmp(&self, op: IntPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("icmp");
unsafe {
llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
}
}
- pub fn fcmp(&self, op: RealPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn fcmp(&self, op: RealPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("fcmp");
unsafe {
llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
}
/* Miscellaneous instructions */
- pub fn empty_phi(&self, ty: Type) -> ValueRef {
+ pub fn empty_phi(&self, ty: &'ll Type) -> &'ll Value {
self.count_insn("emptyphi");
unsafe {
- llvm::LLVMBuildPhi(self.llbuilder, ty.to_ref(), noname())
+ llvm::LLVMBuildPhi(self.llbuilder, ty, noname())
}
}
- pub fn phi(&self, ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef {
+ pub fn phi(&self, ty: &'ll Type, vals: &[&'ll Value], bbs: &[&'ll BasicBlock]) -> &'ll Value {
assert_eq!(vals.len(), bbs.len());
let phi = self.empty_phi(ty);
self.count_insn("addincoming");
}
}
- pub fn add_span_comment(&self, sp: Span, text: &str) {
- if self.cx.sess().asm_comments() {
- let s = format!("{} ({})",
- text,
- self.cx.sess().codemap().span_to_string(sp));
- debug!("{}", s);
- self.add_comment(&s);
- }
- }
-
- pub fn add_comment(&self, text: &str) {
- if self.cx.sess().asm_comments() {
- let sanitized = text.replace("$", "");
- let comment_text = format!("{} {}", "#",
- sanitized.replace("\n", "\n\t# "));
- self.count_insn("inlineasm");
- let comment_text = CString::new(comment_text).unwrap();
- let asm = unsafe {
- llvm::LLVMConstInlineAsm(Type::func(&[], &Type::void(self.cx)).to_ref(),
- comment_text.as_ptr(), noname(), False,
- False)
- };
- self.call(asm, &[], None);
- }
- }
-
pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char,
- inputs: &[ValueRef], output: Type,
+ inputs: &[&'ll Value], output: &'ll Type,
volatile: bool, alignstack: bool,
- dia: AsmDialect) -> ValueRef {
+ dia: AsmDialect) -> &'ll Value {
self.count_insn("inlineasm");
let volatile = if volatile { llvm::True }
else { llvm::False };
let argtys = inputs.iter().map(|v| {
- debug!("Asm Input Type: {:?}", Value(*v));
+ debug!("Asm Input Type: {:?}", *v);
val_ty(*v)
}).collect::<Vec<_>>();
debug!("Asm Output Type: {:?}", output);
- let fty = Type::func(&argtys[..], &output);
+ let fty = Type::func(&argtys[..], output);
unsafe {
let v = llvm::LLVMRustInlineAsm(
- fty.to_ref(), asm, cons, volatile, alignstack, dia);
+ fty, asm, cons, volatile, alignstack, dia);
self.call(v, inputs, None)
}
}
- pub fn call(&self, llfn: ValueRef, args: &[ValueRef],
- bundle: Option<&OperandBundleDef>) -> ValueRef {
+ pub fn call(&self, llfn: &'ll Value, args: &[&'ll Value],
+ bundle: Option<&OperandBundleDef<'ll>>) -> &'ll Value {
self.count_insn("call");
- debug!("Call {:?} with args ({})",
- Value(llfn),
- args.iter()
- .map(|&v| format!("{:?}", Value(v)))
- .collect::<Vec<String>>()
- .join(", "));
+ debug!("Call {:?} with args ({:?})",
+ llfn,
+ args);
let args = self.check_call("call", llfn, args);
- let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut());
+ let bundle = bundle.map(|b| &*b.raw);
unsafe {
llvm::LLVMRustBuildCall(self.llbuilder, llfn, args.as_ptr(),
}
}
- pub fn minnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn minnum(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("minnum");
unsafe {
let instr = llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs);
- if instr.is_null() {
- bug!("LLVMRustBuildMinNum is not available in LLVM version < 6.0");
- }
- instr
+ instr.expect("LLVMRustBuildMinNum is not available in LLVM version < 6.0")
}
}
- pub fn maxnum(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ pub fn maxnum(&self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
self.count_insn("maxnum");
unsafe {
let instr = llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs);
- if instr.is_null() {
- bug!("LLVMRustBuildMaxNum is not available in LLVM version < 6.0");
- }
- instr
+ instr.expect("LLVMRustBuildMaxNum is not available in LLVM version < 6.0")
}
}
- pub fn select(&self, cond: ValueRef, then_val: ValueRef, else_val: ValueRef) -> ValueRef {
+ pub fn select(
+ &self, cond: &'ll Value,
+ then_val: &'ll Value,
+ else_val: &'ll Value,
+ ) -> &'ll Value {
self.count_insn("select");
unsafe {
llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, noname())
}
}
- pub fn va_arg(&self, list: ValueRef, ty: Type) -> ValueRef {
+ #[allow(dead_code)]
+ pub fn va_arg(&self, list: &'ll Value, ty: &'ll Type) -> &'ll Value {
self.count_insn("vaarg");
unsafe {
- llvm::LLVMBuildVAArg(self.llbuilder, list, ty.to_ref(), noname())
+ llvm::LLVMBuildVAArg(self.llbuilder, list, ty, noname())
}
}
- pub fn extract_element(&self, vec: ValueRef, idx: ValueRef) -> ValueRef {
+ pub fn extract_element(&self, vec: &'ll Value, idx: &'ll Value) -> &'ll Value {
self.count_insn("extractelement");
unsafe {
llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, noname())
}
}
- pub fn insert_element(&self, vec: ValueRef, elt: ValueRef, idx: ValueRef) -> ValueRef {
+ pub fn insert_element(
+ &self, vec: &'ll Value,
+ elt: &'ll Value,
+ idx: &'ll Value,
+ ) -> &'ll Value {
self.count_insn("insertelement");
unsafe {
llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, noname())
}
}
- pub fn shuffle_vector(&self, v1: ValueRef, v2: ValueRef, mask: ValueRef) -> ValueRef {
+ pub fn shuffle_vector(&self, v1: &'ll Value, v2: &'ll Value, mask: &'ll Value) -> &'ll Value {
self.count_insn("shufflevector");
unsafe {
llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, noname())
}
}
- pub fn vector_splat(&self, num_elts: usize, elt: ValueRef) -> ValueRef {
+ pub fn vector_splat(&self, num_elts: usize, elt: &'ll Value) -> &'ll Value {
unsafe {
let elt_ty = val_ty(elt);
- let undef = llvm::LLVMGetUndef(Type::vector(&elt_ty, num_elts as u64).to_ref());
+ let undef = llvm::LLVMGetUndef(Type::vector(elt_ty, num_elts as u64));
let vec = self.insert_element(undef, elt, C_i32(self.cx, 0));
- let vec_i32_ty = Type::vector(&Type::i32(self.cx), num_elts as u64);
+ let vec_i32_ty = Type::vector(Type::i32(self.cx), num_elts as u64);
self.shuffle_vector(vec, undef, C_null(vec_i32_ty))
}
}
- pub fn vector_reduce_fadd_fast(&self, acc: ValueRef, src: ValueRef) -> ValueRef {
+ pub fn vector_reduce_fadd_fast(&self, acc: &'ll Value, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.fadd_fast");
unsafe {
// FIXME: add a non-fast math version once
// https://bugs.llvm.org/show_bug.cgi?id=36732
// is fixed.
- let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceFAdd is not available in LLVM version < 5.0");
- }
+ let instr = llvm::LLVMRustBuildVectorReduceFAdd(self.llbuilder, acc, src)
+ .expect("LLVMRustBuildVectorReduceFAdd is not available in LLVM version < 5.0");
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
- pub fn vector_reduce_fmul_fast(&self, acc: ValueRef, src: ValueRef) -> ValueRef {
+ pub fn vector_reduce_fmul_fast(&self, acc: &'ll Value, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.fmul_fast");
unsafe {
// FIXME: add a non-fast math version once
// https://bugs.llvm.org/show_bug.cgi?id=36732
// is fixed.
- let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceFMul is not available in LLVM version < 5.0");
- }
+ let instr = llvm::LLVMRustBuildVectorReduceFMul(self.llbuilder, acc, src)
+ .expect("LLVMRustBuildVectorReduceFMul is not available in LLVM version < 5.0");
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
- pub fn vector_reduce_add(&self, src: ValueRef) -> ValueRef {
+ pub fn vector_reduce_add(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.add");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceAdd(self.llbuilder, src);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceAdd is not available in LLVM version < 5.0");
- }
- instr
+ instr.expect("LLVMRustBuildVectorReduceAdd is not available in LLVM version < 5.0")
}
}
- pub fn vector_reduce_mul(&self, src: ValueRef) -> ValueRef {
+ pub fn vector_reduce_mul(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.mul");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceMul(self.llbuilder, src);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceMul is not available in LLVM version < 5.0");
- }
- instr
+ instr.expect("LLVMRustBuildVectorReduceMul is not available in LLVM version < 5.0")
}
}
- pub fn vector_reduce_and(&self, src: ValueRef) -> ValueRef {
+ pub fn vector_reduce_and(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.and");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceAnd(self.llbuilder, src);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceAnd is not available in LLVM version < 5.0");
- }
- instr
+ instr.expect("LLVMRustBuildVectorReduceAnd is not available in LLVM version < 5.0")
}
}
- pub fn vector_reduce_or(&self, src: ValueRef) -> ValueRef {
+ pub fn vector_reduce_or(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.or");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceOr(self.llbuilder, src);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceOr is not available in LLVM version < 5.0");
- }
- instr
+ instr.expect("LLVMRustBuildVectorReduceOr is not available in LLVM version < 5.0")
}
}
- pub fn vector_reduce_xor(&self, src: ValueRef) -> ValueRef {
+ pub fn vector_reduce_xor(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.xor");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceXor(self.llbuilder, src);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceXor is not available in LLVM version < 5.0");
- }
- instr
+ instr.expect("LLVMRustBuildVectorReduceXor is not available in LLVM version < 5.0")
}
}
- pub fn vector_reduce_fmin(&self, src: ValueRef) -> ValueRef {
+ pub fn vector_reduce_fmin(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.fmin");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ false);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0");
- }
- instr
+ instr.expect("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0")
}
}
- pub fn vector_reduce_fmax(&self, src: ValueRef) -> ValueRef {
+ pub fn vector_reduce_fmax(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.fmax");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ false);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0");
- }
- instr
+ instr.expect("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0")
}
}
- pub fn vector_reduce_fmin_fast(&self, src: ValueRef) -> ValueRef {
+ pub fn vector_reduce_fmin_fast(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.fmin_fast");
unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0");
- }
+ let instr = llvm::LLVMRustBuildVectorReduceFMin(self.llbuilder, src, /*NoNaNs:*/ true)
+ .expect("LLVMRustBuildVectorReduceFMin is not available in LLVM version < 5.0");
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
- pub fn vector_reduce_fmax_fast(&self, src: ValueRef) -> ValueRef {
+ pub fn vector_reduce_fmax_fast(&self, src: &'ll Value) -> &'ll Value {
self.count_insn("vector.reduce.fmax_fast");
unsafe {
- let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0");
- }
+ let instr = llvm::LLVMRustBuildVectorReduceFMax(self.llbuilder, src, /*NoNaNs:*/ true)
+ .expect("LLVMRustBuildVectorReduceFMax is not available in LLVM version < 5.0");
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
- pub fn vector_reduce_min(&self, src: ValueRef, is_signed: bool) -> ValueRef {
+ pub fn vector_reduce_min(&self, src: &'ll Value, is_signed: bool) -> &'ll Value {
self.count_insn("vector.reduce.min");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceMin(self.llbuilder, src, is_signed);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceMin is not available in LLVM version < 5.0");
- }
- instr
+ instr.expect("LLVMRustBuildVectorReduceMin is not available in LLVM version < 5.0")
}
}
- pub fn vector_reduce_max(&self, src: ValueRef, is_signed: bool) -> ValueRef {
+ pub fn vector_reduce_max(&self, src: &'ll Value, is_signed: bool) -> &'ll Value {
self.count_insn("vector.reduce.max");
unsafe {
let instr = llvm::LLVMRustBuildVectorReduceMax(self.llbuilder, src, is_signed);
- if instr.is_null() {
- bug!("LLVMRustBuildVectorReduceMax is not available in LLVM version < 5.0");
- }
- instr
+ instr.expect("LLVMRustBuildVectorReduceMax is not available in LLVM version < 5.0")
}
}
- pub fn extract_value(&self, agg_val: ValueRef, idx: u64) -> ValueRef {
+ pub fn extract_value(&self, agg_val: &'ll Value, idx: u64) -> &'ll Value {
self.count_insn("extractvalue");
assert_eq!(idx as c_uint as u64, idx);
unsafe {
}
}
- pub fn insert_value(&self, agg_val: ValueRef, elt: ValueRef,
- idx: u64) -> ValueRef {
+ pub fn insert_value(&self, agg_val: &'ll Value, elt: &'ll Value,
+ idx: u64) -> &'ll Value {
self.count_insn("insertvalue");
assert_eq!(idx as c_uint as u64, idx);
unsafe {
}
}
- pub fn is_null(&self, val: ValueRef) -> ValueRef {
- self.count_insn("isnull");
- unsafe {
- llvm::LLVMBuildIsNull(self.llbuilder, val, noname())
- }
- }
-
- pub fn is_not_null(&self, val: ValueRef) -> ValueRef {
- self.count_insn("isnotnull");
- unsafe {
- llvm::LLVMBuildIsNotNull(self.llbuilder, val, noname())
- }
- }
-
- pub fn ptrdiff(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
- self.count_insn("ptrdiff");
- unsafe {
- llvm::LLVMBuildPtrDiff(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- pub fn landing_pad(&self, ty: Type, pers_fn: ValueRef,
- num_clauses: usize) -> ValueRef {
+ pub fn landing_pad(&self, ty: &'ll Type, pers_fn: &'ll Value,
+ num_clauses: usize) -> &'ll Value {
self.count_insn("landingpad");
unsafe {
- llvm::LLVMBuildLandingPad(self.llbuilder, ty.to_ref(), pers_fn,
+ llvm::LLVMBuildLandingPad(self.llbuilder, ty, pers_fn,
num_clauses as c_uint, noname())
}
}
- pub fn add_clause(&self, landing_pad: ValueRef, clause: ValueRef) {
+ pub fn add_clause(&self, landing_pad: &'ll Value, clause: &'ll Value) {
unsafe {
llvm::LLVMAddClause(landing_pad, clause);
}
}
- pub fn set_cleanup(&self, landing_pad: ValueRef) {
+ pub fn set_cleanup(&self, landing_pad: &'ll Value) {
self.count_insn("setcleanup");
unsafe {
llvm::LLVMSetCleanup(landing_pad, llvm::True);
}
}
- pub fn resume(&self, exn: ValueRef) -> ValueRef {
+ pub fn resume(&self, exn: &'ll Value) -> &'ll Value {
self.count_insn("resume");
unsafe {
llvm::LLVMBuildResume(self.llbuilder, exn)
}
pub fn cleanup_pad(&self,
- parent: Option<ValueRef>,
- args: &[ValueRef]) -> ValueRef {
+ parent: Option<&'ll Value>,
+ args: &[&'ll Value]) -> &'ll Value {
self.count_insn("cleanuppad");
- let parent = parent.unwrap_or(ptr::null_mut());
let name = CString::new("cleanuppad").unwrap();
let ret = unsafe {
llvm::LLVMRustBuildCleanupPad(self.llbuilder,
args.as_ptr(),
name.as_ptr())
};
- assert!(!ret.is_null(), "LLVM does not have support for cleanuppad");
- return ret
+ ret.expect("LLVM does not have support for cleanuppad")
}
- pub fn cleanup_ret(&self, cleanup: ValueRef,
- unwind: Option<BasicBlockRef>) -> ValueRef {
+ pub fn cleanup_ret(
+ &self, cleanup: &'ll Value,
+ unwind: Option<&'ll BasicBlock>,
+ ) -> &'ll Value {
self.count_insn("cleanupret");
- let unwind = unwind.unwrap_or(ptr::null_mut());
let ret = unsafe {
llvm::LLVMRustBuildCleanupRet(self.llbuilder, cleanup, unwind)
};
- assert!(!ret.is_null(), "LLVM does not have support for cleanupret");
- return ret
+ ret.expect("LLVM does not have support for cleanupret")
}
pub fn catch_pad(&self,
- parent: ValueRef,
- args: &[ValueRef]) -> ValueRef {
+ parent: &'ll Value,
+ args: &[&'ll Value]) -> &'ll Value {
self.count_insn("catchpad");
let name = CString::new("catchpad").unwrap();
let ret = unsafe {
args.len() as c_uint, args.as_ptr(),
name.as_ptr())
};
- assert!(!ret.is_null(), "LLVM does not have support for catchpad");
- return ret
+ ret.expect("LLVM does not have support for catchpad")
}
- pub fn catch_ret(&self, pad: ValueRef, unwind: BasicBlockRef) -> ValueRef {
+ pub fn catch_ret(&self, pad: &'ll Value, unwind: &'ll BasicBlock) -> &'ll Value {
self.count_insn("catchret");
let ret = unsafe {
llvm::LLVMRustBuildCatchRet(self.llbuilder, pad, unwind)
};
- assert!(!ret.is_null(), "LLVM does not have support for catchret");
- return ret
+ ret.expect("LLVM does not have support for catchret")
}
- pub fn catch_switch(&self,
- parent: Option<ValueRef>,
- unwind: Option<BasicBlockRef>,
- num_handlers: usize) -> ValueRef {
+ pub fn catch_switch(
+ &self,
+ parent: Option<&'ll Value>,
+ unwind: Option<&'ll BasicBlock>,
+ num_handlers: usize,
+ ) -> &'ll Value {
self.count_insn("catchswitch");
- let parent = parent.unwrap_or(ptr::null_mut());
- let unwind = unwind.unwrap_or(ptr::null_mut());
let name = CString::new("catchswitch").unwrap();
let ret = unsafe {
llvm::LLVMRustBuildCatchSwitch(self.llbuilder, parent, unwind,
num_handlers as c_uint,
name.as_ptr())
};
- assert!(!ret.is_null(), "LLVM does not have support for catchswitch");
- return ret
+ ret.expect("LLVM does not have support for catchswitch")
}
- pub fn add_handler(&self, catch_switch: ValueRef, handler: BasicBlockRef) {
+ pub fn add_handler(&self, catch_switch: &'ll Value, handler: &'ll BasicBlock) {
unsafe {
llvm::LLVMRustAddHandler(catch_switch, handler);
}
}
- pub fn set_personality_fn(&self, personality: ValueRef) {
+ pub fn set_personality_fn(&self, personality: &'ll Value) {
unsafe {
llvm::LLVMSetPersonalityFn(self.llfn(), personality);
}
}
// Atomic Operations
- pub fn atomic_cmpxchg(&self, dst: ValueRef,
- cmp: ValueRef, src: ValueRef,
- order: AtomicOrdering,
- failure_order: AtomicOrdering,
- weak: llvm::Bool) -> ValueRef {
+ pub fn atomic_cmpxchg(
+ &self,
+ dst: &'ll Value,
+ cmp: &'ll Value,
+ src: &'ll Value,
+ order: AtomicOrdering,
+ failure_order: AtomicOrdering,
+ weak: llvm::Bool,
+ ) -> &'ll Value {
unsafe {
llvm::LLVMRustBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src,
order, failure_order, weak)
}
}
- pub fn atomic_rmw(&self, op: AtomicRmwBinOp,
- dst: ValueRef, src: ValueRef,
- order: AtomicOrdering) -> ValueRef {
+ pub fn atomic_rmw(
+ &self,
+ op: AtomicRmwBinOp,
+ dst: &'ll Value,
+ src: &'ll Value,
+ order: AtomicOrdering,
+ ) -> &'ll Value {
unsafe {
llvm::LLVMBuildAtomicRMW(self.llbuilder, op, dst, src, order, False)
}
}
}
- pub fn add_case(&self, s: ValueRef, on_val: ValueRef, dest: BasicBlockRef) {
+ pub fn add_case(&self, s: &'ll Value, on_val: &'ll Value, dest: &'ll BasicBlock) {
unsafe {
llvm::LLVMAddCase(s, on_val, dest)
}
}
- pub fn add_incoming_to_phi(&self, phi: ValueRef, val: ValueRef, bb: BasicBlockRef) {
+ pub fn add_incoming_to_phi(&self, phi: &'ll Value, val: &'ll Value, bb: &'ll BasicBlock) {
self.count_insn("addincoming");
unsafe {
llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint);
}
}
- pub fn set_invariant_load(&self, load: ValueRef) {
+ pub fn set_invariant_load(&self, load: &'ll Value) {
unsafe {
llvm::LLVMSetMetadata(load, llvm::MD_invariant_load as c_uint,
llvm::LLVMMDNodeInContext(self.cx.llcx, ptr::null(), 0));
/// Returns the ptr value that should be used for storing `val`.
fn check_store<'b>(&self,
- val: ValueRef,
- ptr: ValueRef) -> ValueRef {
+ val: &'ll Value,
+ ptr: &'ll Value) -> &'ll Value {
let dest_ptr_ty = val_ty(ptr);
let stored_ty = val_ty(val);
let stored_ptr_ty = stored_ty.ptr_to();
/// Returns the args that should be used for a call to `llfn`.
fn check_call<'b>(&self,
typ: &str,
- llfn: ValueRef,
- args: &'b [ValueRef]) -> Cow<'b, [ValueRef]> {
+ llfn: &'ll Value,
+ args: &'b [&'ll Value]) -> Cow<'b, [&'ll Value]> {
let mut fn_ty = val_ty(llfn);
// Strip off pointers
while fn_ty.kind() == llvm::TypeKind::Pointer {
if expected_ty != actual_ty {
debug!("Type mismatch in function call of {:?}. \
Expected {:?} for param {}, got {:?}; injecting bitcast",
- Value(llfn),
- expected_ty, i, actual_ty);
+ llfn, expected_ty, i, actual_ty);
self.bitcast(actual_val, expected_ty)
} else {
actual_val
return Cow::Owned(casted_args);
}
- pub fn lifetime_start(&self, ptr: ValueRef, size: Size) {
+ pub fn lifetime_start(&self, ptr: &'ll Value, size: Size) {
self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
}
- pub fn lifetime_end(&self, ptr: ValueRef, size: Size) {
+ pub fn lifetime_end(&self, ptr: &'ll Value, size: Size) {
self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size);
}
///
/// If LLVM lifetime intrinsic support is disabled (i.e. optimizations
/// off) or `ptr` is zero-sized, then no-op (does not call `emit`).
- fn call_lifetime_intrinsic(&self, intrinsic: &str, ptr: ValueRef, size: Size) {
+ fn call_lifetime_intrinsic(&self, intrinsic: &str, ptr: &'ll Value, size: Size) {
if self.cx.sess().opts.optimize == config::OptLevel::No {
return;
}
use common::{self, CodegenCx};
use consts;
use declare;
-use llvm::{self, ValueRef};
+use llvm;
use monomorphize::Instance;
use type_of::LayoutLlvmExt;
+use value::Value;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TypeFoldable};
///
/// - `cx`: the crate context
/// - `instance`: the instance to be instantiated
-pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- instance: Instance<'tcx>)
- -> ValueRef
-{
+pub fn get_fn(
+ cx: &CodegenCx<'ll, 'tcx>,
+ instance: Instance<'tcx>,
+) -> &'ll Value {
let tcx = cx.tcx;
debug!("get_fn(instance={:?})", instance);
// This is a monomorphization. Its expected visibility depends
// on whether we are in share-generics mode.
- if cx.tcx.share_generics() {
+ if cx.tcx.sess.opts.share_generics() {
// We are in share_generics mode.
if instance_def_id.is_local() {
llfn
}
-pub fn resolve_and_get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- def_id: DefId,
- substs: &'tcx Substs<'tcx>)
- -> ValueRef
-{
+pub fn resolve_and_get_fn(
+ cx: &CodegenCx<'ll, 'tcx>,
+ def_id: DefId,
+ substs: &'tcx Substs<'tcx>,
+) -> &'ll Value {
get_fn(
cx,
ty::Instance::resolve(
//! Code that is useful in various codegen modules.
-use llvm;
-use llvm::{ValueRef, ContextRef, TypeKind};
+use llvm::{self, TypeKind};
use llvm::{True, False, Bool, OperandBundleDef};
use rustc::hir::def_id::DefId;
use rustc::middle::lang_items::LangItem;
use type_::Type;
use type_of::LayoutLlvmExt;
use value::Value;
+
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{HasDataLayout, LayoutOf};
use rustc::hir;
/// When inside of a landing pad, each function call in LLVM IR needs to be
/// annotated with which landing pad it's a part of. This is accomplished via
/// the `OperandBundleDef` value created for MSVC landing pads.
-pub struct Funclet {
- cleanuppad: ValueRef,
- operand: OperandBundleDef,
+pub struct Funclet<'ll> {
+ cleanuppad: &'ll Value,
+ operand: OperandBundleDef<'ll>,
}
-impl Funclet {
- pub fn new(cleanuppad: ValueRef) -> Funclet {
+impl Funclet<'ll> {
+ pub fn new(cleanuppad: &'ll Value) -> Self {
Funclet {
cleanuppad,
operand: OperandBundleDef::new("funclet", &[cleanuppad]),
}
}
- pub fn cleanuppad(&self) -> ValueRef {
+ pub fn cleanuppad(&self) -> &'ll Value {
self.cleanuppad
}
- pub fn bundle(&self) -> &OperandBundleDef {
+ pub fn bundle(&self) -> &OperandBundleDef<'ll> {
&self.operand
}
}
-pub fn val_ty(v: ValueRef) -> Type {
+pub fn val_ty(v: &'ll Value) -> &'ll Type {
unsafe {
- Type::from_ref(llvm::LLVMTypeOf(v))
+ llvm::LLVMTypeOf(v)
}
}
// LLVM constant constructors.
-pub fn C_null(t: Type) -> ValueRef {
+pub fn C_null(t: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMConstNull(t.to_ref())
+ llvm::LLVMConstNull(t)
}
}
-pub fn C_undef(t: Type) -> ValueRef {
+pub fn C_undef(t: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMGetUndef(t.to_ref())
+ llvm::LLVMGetUndef(t)
}
}
-pub fn C_int(t: Type, i: i64) -> ValueRef {
+pub fn C_int(t: &'ll Type, i: i64) -> &'ll Value {
unsafe {
- llvm::LLVMConstInt(t.to_ref(), i as u64, True)
+ llvm::LLVMConstInt(t, i as u64, True)
}
}
-pub fn C_uint(t: Type, i: u64) -> ValueRef {
+pub fn C_uint(t: &'ll Type, i: u64) -> &'ll Value {
unsafe {
- llvm::LLVMConstInt(t.to_ref(), i, False)
+ llvm::LLVMConstInt(t, i, False)
}
}
-pub fn C_uint_big(t: Type, u: u128) -> ValueRef {
+pub fn C_uint_big(t: &'ll Type, u: u128) -> &'ll Value {
unsafe {
let words = [u as u64, (u >> 64) as u64];
- llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, words.as_ptr())
+ llvm::LLVMConstIntOfArbitraryPrecision(t, 2, words.as_ptr())
}
}
-pub fn C_bool(cx: &CodegenCx, val: bool) -> ValueRef {
+pub fn C_bool(cx: &CodegenCx<'ll, '_>, val: bool) -> &'ll Value {
C_uint(Type::i1(cx), val as u64)
}
-pub fn C_i32(cx: &CodegenCx, i: i32) -> ValueRef {
+pub fn C_i32(cx: &CodegenCx<'ll, '_>, i: i32) -> &'ll Value {
C_int(Type::i32(cx), i as i64)
}
-pub fn C_u32(cx: &CodegenCx, i: u32) -> ValueRef {
+pub fn C_u32(cx: &CodegenCx<'ll, '_>, i: u32) -> &'ll Value {
C_uint(Type::i32(cx), i as u64)
}
-pub fn C_u64(cx: &CodegenCx, i: u64) -> ValueRef {
+pub fn C_u64(cx: &CodegenCx<'ll, '_>, i: u64) -> &'ll Value {
C_uint(Type::i64(cx), i)
}
-pub fn C_usize(cx: &CodegenCx, i: u64) -> ValueRef {
+pub fn C_usize(cx: &CodegenCx<'ll, '_>, i: u64) -> &'ll Value {
let bit_size = cx.data_layout().pointer_size.bits();
if bit_size < 64 {
// make sure it doesn't overflow
C_uint(cx.isize_ty, i)
}
-pub fn C_u8(cx: &CodegenCx, i: u8) -> ValueRef {
+pub fn C_u8(cx: &CodegenCx<'ll, '_>, i: u8) -> &'ll Value {
C_uint(Type::i8(cx), i as u64)
}
// This is a 'c-like' raw string, which differs from
// our boxed-and-length-annotated strings.
-pub fn C_cstr(cx: &CodegenCx, s: LocalInternedString, null_terminated: bool) -> ValueRef {
+pub fn C_cstr(
+ cx: &CodegenCx<'ll, '_>,
+ s: LocalInternedString,
+ null_terminated: bool,
+) -> &'ll Value {
unsafe {
if let Some(&llval) = cx.const_cstr_cache.borrow().get(&s) {
return llval;
// NB: Do not use `do_spill_noroot` to make this into a constant string, or
// you will be kicked off fast isel. See issue #4352 for an example of this.
-pub fn C_str_slice(cx: &CodegenCx, s: LocalInternedString) -> ValueRef {
+pub fn C_str_slice(cx: &CodegenCx<'ll, '_>, s: LocalInternedString) -> &'ll Value {
let len = s.len();
let cs = consts::ptrcast(C_cstr(cx, s, false),
cx.layout_of(cx.tcx.mk_str()).llvm_type(cx).ptr_to());
C_fat_ptr(cx, cs, C_usize(cx, len as u64))
}
-pub fn C_fat_ptr(cx: &CodegenCx, ptr: ValueRef, meta: ValueRef) -> ValueRef {
+pub fn C_fat_ptr(cx: &CodegenCx<'ll, '_>, ptr: &'ll Value, meta: &'ll Value) -> &'ll Value {
assert_eq!(abi::FAT_PTR_ADDR, 0);
assert_eq!(abi::FAT_PTR_EXTRA, 1);
C_struct(cx, &[ptr, meta], false)
}
-pub fn C_struct(cx: &CodegenCx, elts: &[ValueRef], packed: bool) -> ValueRef {
+pub fn C_struct(cx: &CodegenCx<'ll, '_>, elts: &[&'ll Value], packed: bool) -> &'ll Value {
C_struct_in_context(cx.llcx, elts, packed)
}
-pub fn C_struct_in_context(llcx: ContextRef, elts: &[ValueRef], packed: bool) -> ValueRef {
+pub fn C_struct_in_context(
+ llcx: &'ll llvm::Context,
+ elts: &[&'ll Value],
+ packed: bool,
+) -> &'ll Value {
unsafe {
llvm::LLVMConstStructInContext(llcx,
elts.as_ptr(), elts.len() as c_uint,
}
}
-pub fn C_array(ty: Type, elts: &[ValueRef]) -> ValueRef {
+pub fn C_array(ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
unsafe {
- return llvm::LLVMConstArray(ty.to_ref(), elts.as_ptr(), elts.len() as c_uint);
+ return llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint);
}
}
-pub fn C_vector(elts: &[ValueRef]) -> ValueRef {
+pub fn C_vector(elts: &[&'ll Value]) -> &'ll Value {
unsafe {
return llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint);
}
}
-pub fn C_bytes(cx: &CodegenCx, bytes: &[u8]) -> ValueRef {
+pub fn C_bytes(cx: &CodegenCx<'ll, '_>, bytes: &[u8]) -> &'ll Value {
C_bytes_in_context(cx.llcx, bytes)
}
-pub fn C_bytes_in_context(llcx: ContextRef, bytes: &[u8]) -> ValueRef {
+pub fn C_bytes_in_context(llcx: &'ll llvm::Context, bytes: &[u8]) -> &'ll Value {
unsafe {
let ptr = bytes.as_ptr() as *const c_char;
return llvm::LLVMConstStringInContext(llcx, ptr, bytes.len() as c_uint, True);
}
}
-pub fn const_get_elt(v: ValueRef, idx: u64) -> ValueRef {
+pub fn const_get_elt(v: &'ll Value, idx: u64) -> &'ll Value {
unsafe {
assert_eq!(idx as c_uint as u64, idx);
let us = &[idx as c_uint];
let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint);
debug!("const_get_elt(v={:?}, idx={}, r={:?})",
- Value(v), idx, Value(r));
+ v, idx, r);
r
}
}
-pub fn const_get_real(v: ValueRef) -> Option<(f64, bool)> {
+pub fn const_get_real(v: &'ll Value) -> Option<(f64, bool)> {
unsafe {
if is_const_real(v) {
let mut loses_info: llvm::Bool = ::std::mem::uninitialized();
- let r = llvm::LLVMConstRealGetDouble(v, &mut loses_info as *mut llvm::Bool);
+ let r = llvm::LLVMConstRealGetDouble(v, &mut loses_info);
let loses_info = if loses_info == 1 { true } else { false };
Some((r, loses_info))
} else {
}
}
-pub fn const_to_uint(v: ValueRef) -> u64 {
+pub fn const_to_uint(v: &'ll Value) -> u64 {
unsafe {
llvm::LLVMConstIntGetZExtValue(v)
}
}
-pub fn is_const_integral(v: ValueRef) -> bool {
+pub fn is_const_integral(v: &'ll Value) -> bool {
unsafe {
- !llvm::LLVMIsAConstantInt(v).is_null()
+ llvm::LLVMIsAConstantInt(v).is_some()
}
}
-pub fn is_const_real(v: ValueRef) -> bool {
+pub fn is_const_real(v: &'ll Value) -> bool {
unsafe {
- !llvm::LLVMIsAConstantFP(v).is_null()
+ llvm::LLVMIsAConstantFP(v).is_some()
}
}
((hi as u128) << 64) | (lo as u128)
}
-pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option<u128> {
+pub fn const_to_opt_u128(v: &'ll Value, sign_ext: bool) -> Option<u128> {
unsafe {
if is_const_integral(v) {
let (mut lo, mut hi) = (0u64, 0u64);
let success = llvm::LLVMRustConstInt128Get(v, sign_ext,
- &mut hi as *mut u64, &mut lo as *mut u64);
+ &mut hi, &mut lo);
if success {
Some(hi_lo_to_u128(lo, hi))
} else {
// all shifts). For 32- and 64-bit types, this matches the semantics
// of Java. (See related discussion on #1877 and #10183.)
-pub fn build_unchecked_lshift<'a, 'tcx>(
- bx: &Builder<'a, 'tcx>,
- lhs: ValueRef,
- rhs: ValueRef
-) -> ValueRef {
+pub fn build_unchecked_lshift(
+ bx: &Builder<'a, 'll, 'tcx>,
+ lhs: &'ll Value,
+ rhs: &'ll Value
+) -> &'ll Value {
let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shl, lhs, rhs);
// #1877, #10183: Ensure that input is always valid
let rhs = shift_mask_rhs(bx, rhs);
bx.shl(lhs, rhs)
}
-pub fn build_unchecked_rshift<'a, 'tcx>(
- bx: &Builder<'a, 'tcx>, lhs_t: Ty<'tcx>, lhs: ValueRef, rhs: ValueRef
-) -> ValueRef {
+pub fn build_unchecked_rshift(
+ bx: &Builder<'a, 'll, 'tcx>, lhs_t: Ty<'tcx>, lhs: &'ll Value, rhs: &'ll Value
+) -> &'ll Value {
let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shr, lhs, rhs);
// #1877, #10183: Ensure that input is always valid
let rhs = shift_mask_rhs(bx, rhs);
}
}
-fn shift_mask_rhs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, rhs: ValueRef) -> ValueRef {
+fn shift_mask_rhs(bx: &Builder<'a, 'll, 'tcx>, rhs: &'ll Value) -> &'ll Value {
let rhs_llty = val_ty(rhs);
bx.and(rhs, shift_mask_val(bx, rhs_llty, rhs_llty, false))
}
-pub fn shift_mask_val<'a, 'tcx>(
- bx: &Builder<'a, 'tcx>,
- llty: Type,
- mask_llty: Type,
+pub fn shift_mask_val(
+ bx: &Builder<'a, 'll, 'tcx>,
+ llty: &'ll Type,
+ mask_llty: &'ll Type,
invert: bool
-) -> ValueRef {
+) -> &'ll Value {
let kind = llty.kind();
match kind {
TypeKind::Integer => {
// except according to those terms.
use libc::c_uint;
-use llvm;
-use llvm::{SetUnnamedAddr};
-use llvm::{ValueRef, True};
+use llvm::{self, SetUnnamedAddr, True};
use rustc::hir::def_id::DefId;
use rustc::hir::map as hir_map;
use debuginfo;
use syntax_pos::symbol::LocalInternedString;
use type_::Type;
use type_of::LayoutLlvmExt;
+use value::Value;
use rustc::ty::{self, Ty};
+
use rustc::ty::layout::{Align, LayoutOf};
use rustc::hir::{self, CodegenFnAttrs, CodegenFnAttrFlags};
use std::ffi::{CStr, CString};
-pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
+pub fn ptrcast(val: &'ll Value, ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMConstPointerCast(val, ty.to_ref())
+ llvm::LLVMConstPointerCast(val, ty)
}
}
-pub fn bitcast(val: ValueRef, ty: Type) -> ValueRef {
+pub fn bitcast(val: &'ll Value, ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMConstBitCast(val, ty.to_ref())
+ llvm::LLVMConstBitCast(val, ty)
}
}
-fn set_global_alignment(cx: &CodegenCx,
- gv: ValueRef,
+fn set_global_alignment(cx: &CodegenCx<'ll, '_>,
+ gv: &'ll Value,
mut align: Align) {
// The target may require greater alignment for globals than the type does.
// Note: GCC and Clang also allow `__attribute__((aligned))` on variables,
}
}
-pub fn addr_of_mut(cx: &CodegenCx,
- cv: ValueRef,
- align: Align,
- kind: &str)
- -> ValueRef {
+pub fn addr_of_mut(
+ cx: &CodegenCx<'ll, '_>,
+ cv: &'ll Value,
+ align: Align,
+ kind: &str,
+) -> &'ll Value {
unsafe {
let name = cx.generate_local_symbol_name(kind);
let gv = declare::define_global(cx, &name[..], val_ty(cv)).unwrap_or_else(||{
}
}
-pub fn addr_of(cx: &CodegenCx,
- cv: ValueRef,
- align: Align,
- kind: &str)
- -> ValueRef {
+pub fn addr_of(
+ cx: &CodegenCx<'ll, '_>,
+ cv: &'ll Value,
+ align: Align,
+ kind: &str,
+) -> &'ll Value {
if let Some(&gv) = cx.const_globals.borrow().get(&cv) {
unsafe {
// Upgrade the alignment in cases where the same constant is used with different
gv
}
-pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
+pub fn get_static(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll Value {
let instance = Instance::mono(cx.tcx, def_id);
if let Some(&g) = cx.instances.borrow().get(&instance) {
return g;
g
}
-fn check_and_apply_linkage<'tcx>(
- cx: &CodegenCx<'_, 'tcx>,
+fn check_and_apply_linkage(
+ cx: &CodegenCx<'ll, 'tcx>,
attrs: &CodegenFnAttrs,
ty: Ty<'tcx>,
sym: LocalInternedString,
span: Option<Span>
-) -> ValueRef {
+) -> &'ll Value {
let llty = cx.layout_of(ty).llvm_type(cx);
if let Some(linkage) = attrs.linkage {
debug!("get_static: sym={} linkage={:?}", sym, linkage);
let mut val_llty = val_ty(v);
let v = if val_llty == Type::i1(cx) {
val_llty = Type::i8(cx);
- llvm::LLVMConstZExt(v, val_llty.to_ref())
+ llvm::LLVMConstZExt(v, val_llty)
} else {
v
};
let visibility = llvm::LLVMRustGetVisibility(g);
let new_g = llvm::LLVMRustGetOrInsertGlobal(
- cx.llmod, name_string.as_ptr(), val_llty.to_ref());
+ cx.llmod, name_string.as_ptr(), val_llty);
llvm::LLVMRustSetLinkage(new_g, linkage);
llvm::LLVMRustSetVisibility(new_g, visibility);
if attrs.flags.contains(CodegenFnAttrFlags::USED) {
// This static will be stored in the llvm.used variable which is an array of i8*
- let cast = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref());
+ let cast = llvm::LLVMConstPointerCast(g, Type::i8p(cx));
cx.used_statics.borrow_mut().push(cast);
}
}
use common;
use llvm;
-use llvm::{ContextRef, ModuleRef, ValueRef};
use rustc::dep_graph::DepGraphSafe;
use rustc::hir;
use rustc::hir::def_id::DefId;
use base;
use declare;
use monomorphize::Instance;
+use value::Value;
use monomorphize::partitioning::CodegenUnit;
use type_::Type;
use rustc_data_structures::base_n;
use rustc::mir::mono::Stats;
-use rustc::session::config::{self, NoDebugInfo};
+use rustc::session::config::{self, DebugInfo};
use rustc::session::Session;
use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout};
use rustc::ty::{self, Ty, TyCtxt};
use std::ffi::{CStr, CString};
use std::cell::{Cell, RefCell};
-use std::ptr;
use std::iter;
use std::str;
use std::sync::Arc;
use abi::Abi;
/// There is one `CodegenCx` per compilation unit. Each one has its own LLVM
-/// `ContextRef` so that several compilation units may be optimized in parallel.
-/// All other LLVM data structures in the `CodegenCx` are tied to that `ContextRef`.
+/// `llvm::Context` so that several compilation units may be optimized in parallel.
+/// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`.
pub struct CodegenCx<'a, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub check_overflow: bool,
pub use_dll_storage_attrs: bool,
pub tls_model: llvm::ThreadLocalMode,
- pub llmod: ModuleRef,
- pub llcx: ContextRef,
+ pub llmod: &'a llvm::Module,
+ pub llcx: &'a llvm::Context,
pub stats: RefCell<Stats>,
pub codegen_unit: Arc<CodegenUnit<'tcx>>,
/// Cache instances of monomorphic and polymorphic items
- pub instances: RefCell<FxHashMap<Instance<'tcx>, ValueRef>>,
+ pub instances: RefCell<FxHashMap<Instance<'tcx>, &'a Value>>,
/// Cache generated vtables
pub vtables: RefCell<FxHashMap<(Ty<'tcx>,
- Option<ty::PolyExistentialTraitRef<'tcx>>), ValueRef>>,
+ Option<ty::PolyExistentialTraitRef<'tcx>>), &'a Value>>,
/// Cache of constant strings,
- pub const_cstr_cache: RefCell<FxHashMap<LocalInternedString, ValueRef>>,
+ pub const_cstr_cache: RefCell<FxHashMap<LocalInternedString, &'a Value>>,
/// Reverse-direction for const ptrs cast from globals.
- /// Key is a ValueRef holding a *T,
- /// Val is a ValueRef holding a *[T].
+ /// Key is a Value holding a *T,
+ /// Val is a Value holding a *[T].
///
/// Needed because LLVM loses pointer->pointee association
/// when we ptrcast, and we have to ptrcast during codegen
/// of a [T] const because we form a slice, a (*T,usize) pair, not
/// a pointer to an LLVM array type. Similar for trait objects.
- pub const_unsized: RefCell<FxHashMap<ValueRef, ValueRef>>,
+ pub const_unsized: RefCell<FxHashMap<&'a Value, &'a Value>>,
/// Cache of emitted const globals (value -> global)
- pub const_globals: RefCell<FxHashMap<ValueRef, ValueRef>>,
+ pub const_globals: RefCell<FxHashMap<&'a Value, &'a Value>>,
/// Mapping from static definitions to their DefId's.
- pub statics: RefCell<FxHashMap<ValueRef, DefId>>,
+ pub statics: RefCell<FxHashMap<&'a Value, DefId>>,
/// List of globals for static variables which need to be passed to the
/// LLVM function ReplaceAllUsesWith (RAUW) when codegen is complete.
- /// (We have to make sure we don't invalidate any ValueRefs referring
+ /// (We have to make sure we don't invalidate any Values referring
/// to constants.)
- pub statics_to_rauw: RefCell<Vec<(ValueRef, ValueRef)>>,
+ pub statics_to_rauw: RefCell<Vec<(&'a Value, &'a Value)>>,
/// Statics that will be placed in the llvm.used variable
/// See http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable for details
- pub used_statics: RefCell<Vec<ValueRef>>,
+ pub used_statics: RefCell<Vec<&'a Value>>,
- pub lltypes: RefCell<FxHashMap<(Ty<'tcx>, Option<usize>), Type>>,
- pub scalar_lltypes: RefCell<FxHashMap<Ty<'tcx>, Type>>,
+ pub lltypes: RefCell<FxHashMap<(Ty<'tcx>, Option<usize>), &'a Type>>,
+ pub scalar_lltypes: RefCell<FxHashMap<Ty<'tcx>, &'a Type>>,
pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
- pub isize_ty: Type,
+ pub isize_ty: &'a Type,
- pub dbg_cx: Option<debuginfo::CrateDebugContext<'tcx>>,
+ pub dbg_cx: Option<debuginfo::CrateDebugContext<'a, 'tcx>>,
- eh_personality: Cell<Option<ValueRef>>,
- eh_unwind_resume: Cell<Option<ValueRef>>,
- pub rust_try_fn: Cell<Option<ValueRef>>,
+ eh_personality: Cell<Option<&'a Value>>,
+ eh_unwind_resume: Cell<Option<&'a Value>>,
+ pub rust_try_fn: Cell<Option<&'a Value>>,
- intrinsics: RefCell<FxHashMap<&'static str, ValueRef>>,
+ intrinsics: RefCell<FxHashMap<&'static str, &'a Value>>,
/// A counter that is used for generating local symbol names
local_gen_sym_counter: Cell<usize>,
fn is_any_library(sess: &Session) -> bool {
sess.crate_types.borrow().iter().any(|ty| {
- *ty != config::CrateTypeExecutable
+ *ty != config::CrateType::Executable
})
}
!is_any_library(sess) && get_reloc_model(sess) == llvm::RelocMode::PIC
}
-pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) {
- let llcx = llvm::LLVMRustContextCreate(sess.fewer_names());
+pub unsafe fn create_module(
+ sess: &Session,
+ llcx: &'ll llvm::Context,
+ mod_name: &str,
+) -> &'ll llvm::Module {
let mod_name = CString::new(mod_name).unwrap();
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
llvm::LLVMRustSetModulePIELevel(llmod);
}
- (llcx, llmod)
+ llmod
}
impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ crate fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
codegen_unit: Arc<CodegenUnit<'tcx>>,
- llmod_id: &str)
+ llvm_module: &'a ::ModuleLlvm)
-> CodegenCx<'a, 'tcx> {
// An interesting part of Windows which MSVC forces our hand on (and
// apparently MinGW didn't) is the usage of `dllimport` and `dllexport`
let tls_model = get_tls_model(&tcx.sess);
- unsafe {
- let (llcx, llmod) = create_context_and_module(&tcx.sess,
- &llmod_id[..]);
-
- let dbg_cx = if tcx.sess.opts.debuginfo != NoDebugInfo {
- let dctx = debuginfo::CrateDebugContext::new(llmod);
- debuginfo::metadata::compile_unit_metadata(tcx,
- &codegen_unit.name().as_str(),
- &dctx);
- Some(dctx)
- } else {
- None
- };
-
- let mut cx = CodegenCx {
- tcx,
- check_overflow,
- use_dll_storage_attrs,
- tls_model,
- llmod,
- llcx,
- stats: RefCell::new(Stats::default()),
- codegen_unit,
- instances: RefCell::new(FxHashMap()),
- vtables: RefCell::new(FxHashMap()),
- const_cstr_cache: RefCell::new(FxHashMap()),
- const_unsized: RefCell::new(FxHashMap()),
- const_globals: RefCell::new(FxHashMap()),
- statics: RefCell::new(FxHashMap()),
- statics_to_rauw: RefCell::new(Vec::new()),
- used_statics: RefCell::new(Vec::new()),
- lltypes: RefCell::new(FxHashMap()),
- scalar_lltypes: RefCell::new(FxHashMap()),
- pointee_infos: RefCell::new(FxHashMap()),
- isize_ty: Type::from_ref(ptr::null_mut()),
- dbg_cx,
- eh_personality: Cell::new(None),
- eh_unwind_resume: Cell::new(None),
- rust_try_fn: Cell::new(None),
- intrinsics: RefCell::new(FxHashMap()),
- local_gen_sym_counter: Cell::new(0),
- };
- cx.isize_ty = Type::isize(&cx);
- cx
- }
- }
+ let (llcx, llmod) = (&*llvm_module.llcx, llvm_module.llmod());
- pub fn into_stats(self) -> Stats {
- self.stats.into_inner()
+ let dbg_cx = if tcx.sess.opts.debuginfo != DebugInfo::None {
+ let dctx = debuginfo::CrateDebugContext::new(llmod);
+ debuginfo::metadata::compile_unit_metadata(tcx,
+ &codegen_unit.name().as_str(),
+ &dctx);
+ Some(dctx)
+ } else {
+ None
+ };
+
+ let isize_ty = Type::ix_llcx(llcx, tcx.data_layout.pointer_size.bits());
+
+ CodegenCx {
+ tcx,
+ check_overflow,
+ use_dll_storage_attrs,
+ tls_model,
+ llmod,
+ llcx,
+ stats: RefCell::new(Stats::default()),
+ codegen_unit,
+ instances: RefCell::new(FxHashMap()),
+ vtables: RefCell::new(FxHashMap()),
+ const_cstr_cache: RefCell::new(FxHashMap()),
+ const_unsized: RefCell::new(FxHashMap()),
+ const_globals: RefCell::new(FxHashMap()),
+ statics: RefCell::new(FxHashMap()),
+ statics_to_rauw: RefCell::new(Vec::new()),
+ used_statics: RefCell::new(Vec::new()),
+ lltypes: RefCell::new(FxHashMap()),
+ scalar_lltypes: RefCell::new(FxHashMap()),
+ pointee_infos: RefCell::new(FxHashMap()),
+ isize_ty,
+ dbg_cx,
+ eh_personality: Cell::new(None),
+ eh_unwind_resume: Cell::new(None),
+ rust_try_fn: Cell::new(None),
+ intrinsics: RefCell::new(FxHashMap()),
+ local_gen_sym_counter: Cell::new(0),
+ }
}
}
&self.tcx.sess
}
- pub fn get_intrinsic(&self, key: &str) -> ValueRef {
+ pub fn get_intrinsic(&self, key: &str) -> &'b Value {
if let Some(v) = self.intrinsics.borrow().get(key).cloned() {
return v;
}
name
}
- pub fn eh_personality(&self) -> ValueRef {
+ pub fn eh_personality(&self) -> &'b Value {
// The exception handling personality function.
//
// If our compilation unit has the `eh_personality` lang item somewhere
} else {
"rust_eh_personality"
};
- let fty = Type::variadic_func(&[], &Type::i32(self));
+ let fty = Type::variadic_func(&[], Type::i32(self));
declare::declare_cfn(self, name, fty)
}
};
llfn
}
- // Returns a ValueRef of the "eh_unwind_resume" lang item if one is defined,
+ // Returns a Value of the "eh_unwind_resume" lang item if one is defined,
// otherwise declares it as an external function.
- pub fn eh_unwind_resume(&self) -> ValueRef {
+ pub fn eh_unwind_resume(&self) -> &'b Value {
use attributes;
let unwresume = &self.eh_unwind_resume;
if let Some(llfn) = unwresume.get() {
}
}
-impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CodegenCx<'a, 'tcx> {
+impl ty::layout::HasDataLayout for &'a CodegenCx<'ll, 'tcx> {
fn data_layout(&self) -> &ty::layout::TargetDataLayout {
&self.tcx.data_layout
}
}
-impl<'a, 'tcx> HasTargetSpec for &'a CodegenCx<'a, 'tcx> {
+impl HasTargetSpec for &'a CodegenCx<'ll, 'tcx> {
fn target_spec(&self) -> &Target {
&self.tcx.sess.target.target
}
}
-impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CodegenCx<'a, 'tcx> {
+impl ty::layout::HasTyCtxt<'tcx> for &'a CodegenCx<'ll, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.tcx
}
}
-impl<'a, 'tcx> LayoutOf for &'a CodegenCx<'a, 'tcx> {
+impl LayoutOf for &'a CodegenCx<'ll, 'tcx> {
type Ty = Ty<'tcx>;
type TyLayout = TyLayout<'tcx>;
}
/// Declare any llvm intrinsics that you might need
-fn declare_intrinsic(cx: &CodegenCx, key: &str) -> Option<ValueRef> {
+fn declare_intrinsic(cx: &CodegenCx<'ll, '_>, key: &str) -> Option<&'ll Value> {
macro_rules! ifn {
($name:expr, fn() -> $ret:expr) => (
if key == $name {
- let f = declare::declare_cfn(cx, $name, Type::func(&[], &$ret));
+ let f = declare::declare_cfn(cx, $name, Type::func(&[], $ret));
llvm::SetUnnamedAddr(f, false);
cx.intrinsics.borrow_mut().insert($name, f.clone());
return Some(f);
);
($name:expr, fn(...) -> $ret:expr) => (
if key == $name {
- let f = declare::declare_cfn(cx, $name, Type::variadic_func(&[], &$ret));
+ let f = declare::declare_cfn(cx, $name, Type::variadic_func(&[], $ret));
llvm::SetUnnamedAddr(f, false);
cx.intrinsics.borrow_mut().insert($name, f.clone());
return Some(f);
);
($name:expr, fn($($arg:expr),*) -> $ret:expr) => (
if key == $name {
- let f = declare::declare_cfn(cx, $name, Type::func(&[$($arg),*], &$ret));
+ let f = declare::declare_cfn(cx, $name, Type::func(&[$($arg),*], $ret));
llvm::SetUnnamedAddr(f, false);
cx.intrinsics.borrow_mut().insert($name, f.clone());
return Some(f);
let t_f32 = Type::f32(cx);
let t_f64 = Type::f64(cx);
- let t_v2f32 = Type::vector(&t_f32, 2);
- let t_v4f32 = Type::vector(&t_f32, 4);
- let t_v8f32 = Type::vector(&t_f32, 8);
- let t_v16f32 = Type::vector(&t_f32, 16);
+ let t_v2f32 = Type::vector(t_f32, 2);
+ let t_v4f32 = Type::vector(t_f32, 4);
+ let t_v8f32 = Type::vector(t_f32, 8);
+ let t_v16f32 = Type::vector(t_f32, 16);
- let t_v2f64 = Type::vector(&t_f64, 2);
- let t_v4f64 = Type::vector(&t_f64, 4);
- let t_v8f64 = Type::vector(&t_f64, 8);
+ let t_v2f64 = Type::vector(t_f64, 2);
+ let t_v4f64 = Type::vector(t_f64, 4);
+ let t_v8f64 = Type::vector(t_f64, 8);
ifn!("llvm.memcpy.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void);
ifn!("llvm.memcpy.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void);
ifn!("llvm.assume", fn(i1) -> void);
ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void);
- if cx.sess().opts.debuginfo != NoDebugInfo {
+ if cx.sess().opts.debuginfo != DebugInfo::None {
ifn!("llvm.dbg.declare", fn(Type::metadata(cx), Type::metadata(cx)) -> void);
ifn!("llvm.dbg.value", fn(Type::metadata(cx), t_i64, Type::metadata(cx)) -> void);
}
use rustc::mir::{Mir, SourceScope};
use libc::c_uint;
-use std::ptr;
use syntax_pos::Pos;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use syntax_pos::BytePos;
#[derive(Clone, Copy, Debug)]
-pub struct MirDebugScope {
- pub scope_metadata: DIScope,
+pub struct MirDebugScope<'ll> {
+ pub scope_metadata: Option<&'ll DIScope>,
// Start and end offsets of the file to which this DIScope belongs.
// These are used to quickly determine whether some span refers to the same file.
pub file_start_pos: BytePos,
pub file_end_pos: BytePos,
}
-impl MirDebugScope {
+impl MirDebugScope<'ll> {
pub fn is_valid(&self) -> bool {
- !self.scope_metadata.is_null()
+ !self.scope_metadata.is_none()
}
}
/// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
/// If debuginfo is disabled, the returned vector is empty.
-pub fn create_mir_scopes(cx: &CodegenCx, mir: &Mir, debug_context: &FunctionDebugContext)
- -> IndexVec<SourceScope, MirDebugScope> {
+pub fn create_mir_scopes(
+ cx: &CodegenCx<'ll, '_>,
+ mir: &Mir,
+ debug_context: &FunctionDebugContext<'ll>,
+) -> IndexVec<SourceScope, MirDebugScope<'ll>> {
let null_scope = MirDebugScope {
- scope_metadata: ptr::null_mut(),
+ scope_metadata: None,
file_start_pos: BytePos(0),
file_end_pos: BytePos(0)
};
};
// Find all the scopes with variables defined in them.
- let mut has_variables = BitVector::new(mir.source_scopes.len());
+ let mut has_variables = BitArray::new(mir.source_scopes.len());
for var in mir.vars_iter() {
let decl = &mir.local_decls[var];
has_variables.insert(decl.visibility_scope);
scopes
}
-fn make_mir_scope(cx: &CodegenCx,
+fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
mir: &Mir,
- has_variables: &BitVector<SourceScope>,
- debug_context: &FunctionDebugContextData,
+ has_variables: &BitArray<SourceScope>,
+ debug_context: &FunctionDebugContextData<'ll>,
scope: SourceScope,
- scopes: &mut IndexVec<SourceScope, MirDebugScope>) {
+ scopes: &mut IndexVec<SourceScope, MirDebugScope<'ll>>) {
if scopes[scope].is_valid() {
return;
}
// The root is the function itself.
let loc = span_start(cx, mir.span);
scopes[scope] = MirDebugScope {
- scope_metadata: debug_context.fn_metadata,
+ scope_metadata: Some(debug_context.fn_metadata),
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
};
// However, we don't skip creating a nested scope if
// our parent is the root, because we might want to
// put arguments in the root and not have shadowing.
- if parent_scope.scope_metadata != debug_context.fn_metadata {
+ if parent_scope.scope_metadata.unwrap() != debug_context.fn_metadata {
scopes[scope] = parent_scope;
return;
}
debug_context.defining_crate);
let scope_metadata = unsafe {
- llvm::LLVMRustDIBuilderCreateLexicalBlock(
+ Some(llvm::LLVMRustDIBuilderCreateLexicalBlock(
DIB(cx),
- parent_scope.scope_metadata,
+ parent_scope.scope_metadata.unwrap(),
file_metadata,
loc.line as c_uint,
- loc.col.to_usize() as c_uint)
+ loc.col.to_usize() as c_uint))
};
scopes[scope] = MirDebugScope {
scope_metadata,
use common::{C_bytes, CodegenCx, C_i32};
use builder::Builder;
use declare;
+use rustc::session::config::DebugInfo;
use type_::Type;
-use rustc::session::config::NoDebugInfo;
+use value::Value;
-use std::ptr;
use syntax::attr;
/// Allocates the global variable responsible for the .debug_gdb_scripts binary
/// section.
-pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx)
- -> llvm::ValueRef {
+pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>)
+ -> &'ll Value {
let c_section_var_name = "__rustc_debug_gdb_scripts_section__\0";
let section_var_name = &c_section_var_name[..c_section_var_name.len()-1];
c_section_var_name.as_ptr() as *const _)
};
- if section_var == ptr::null_mut() {
+ section_var.unwrap_or_else(|| {
let section_name = b".debug_gdb_scripts\0";
let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0";
unsafe {
- let llvm_type = Type::array(&Type::i8(cx),
+ let llvm_type = Type::array(Type::i8(cx),
section_contents.len() as u64);
let section_var = declare::define_global(cx, section_var_name,
llvm::LLVMSetAlignment(section_var, 1);
section_var
}
- } else {
- section_var
- }
+ })
}
pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx) -> bool {
"omit_gdb_pretty_printer_section");
!omit_gdb_pretty_printer_section &&
- cx.sess().opts.debuginfo != NoDebugInfo &&
+ cx.sess().opts.debuginfo != DebugInfo::None &&
cx.sess().target.target.options.emit_debug_gdb_scripts
}
use super::type_names::compute_debuginfo_type_name;
use super::{CrateDebugContext};
use abi;
+use value::Value;
-use llvm::{self, ValueRef};
+use llvm;
use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor,
DICompositeType, DILexicalBlock, DIFlags};
use libc::{c_uint, c_longlong};
use std::ffi::CString;
-use std::fmt::Write;
+use std::fmt::{self, Write};
+use std::hash::{Hash, Hasher};
use std::iter;
use std::ptr;
use std::path::{Path, PathBuf};
use syntax::symbol::{Interner, InternedString, Symbol};
use syntax_pos::{self, Span, FileName};
+impl PartialEq for llvm::Metadata {
+ fn eq(&self, other: &Self) -> bool {
+ self as *const _ == other as *const _
+ }
+}
+
+impl Eq for llvm::Metadata {}
+
+impl Hash for llvm::Metadata {
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ (self as *const Self).hash(hasher);
+ }
+}
+
+impl fmt::Debug for llvm::Metadata {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ (self as *const Self).fmt(f)
+ }
+}
// From DWARF 5.
// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1
pub const UNKNOWN_LINE_NUMBER: c_uint = 0;
pub const UNKNOWN_COLUMN_NUMBER: c_uint = 0;
-// ptr::null() doesn't work :(
-pub const NO_SCOPE_METADATA: DIScope = (0 as DIScope);
+pub const NO_SCOPE_METADATA: Option<&DIScope> = None;
#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)]
pub struct UniqueTypeId(ast::Name);
// created so far. The metadata nodes are indexed by UniqueTypeId, and, for
// faster lookup, also by Ty. The TypeMap is responsible for creating
// UniqueTypeIds.
-pub struct TypeMap<'tcx> {
+pub struct TypeMap<'ll, 'tcx> {
// The UniqueTypeIds created so far
unique_id_interner: Interner,
// A map from UniqueTypeId to debuginfo metadata for that type. This is a 1:1 mapping.
- unique_id_to_metadata: FxHashMap<UniqueTypeId, DIType>,
+ unique_id_to_metadata: FxHashMap<UniqueTypeId, &'ll DIType>,
// A map from types to debuginfo metadata. This is a N:1 mapping.
- type_to_metadata: FxHashMap<Ty<'tcx>, DIType>,
+ type_to_metadata: FxHashMap<Ty<'tcx>, &'ll DIType>,
// A map from types to UniqueTypeId. This is a N:1 mapping.
type_to_unique_id: FxHashMap<Ty<'tcx>, UniqueTypeId>
}
-impl<'tcx> TypeMap<'tcx> {
- pub fn new() -> TypeMap<'tcx> {
+impl TypeMap<'ll, 'tcx> {
+ pub fn new() -> Self {
TypeMap {
unique_id_interner: Interner::new(),
type_to_metadata: FxHashMap(),
// Adds a Ty to metadata mapping to the TypeMap. The method will fail if
// the mapping already exists.
- fn register_type_with_metadata<'a>(&mut self,
- type_: Ty<'tcx>,
- metadata: DIType) {
+ fn register_type_with_metadata(
+ &mut self,
+ type_: Ty<'tcx>,
+ metadata: &'ll DIType,
+ ) {
if self.type_to_metadata.insert(type_, metadata).is_some() {
bug!("Type metadata for Ty '{}' is already in the TypeMap!", type_);
}
// Adds a UniqueTypeId to metadata mapping to the TypeMap. The method will
// fail if the mapping already exists.
- fn register_unique_id_with_metadata(&mut self,
- unique_type_id: UniqueTypeId,
- metadata: DIType) {
+ fn register_unique_id_with_metadata(
+ &mut self,
+ unique_type_id: UniqueTypeId,
+ metadata: &'ll DIType,
+ ) {
if self.unique_id_to_metadata.insert(unique_type_id, metadata).is_some() {
bug!("Type metadata for unique id '{}' is already in the TypeMap!",
self.get_unique_type_id_as_string(unique_type_id));
}
}
- fn find_metadata_for_type(&self, type_: Ty<'tcx>) -> Option<DIType> {
+ fn find_metadata_for_type(&self, type_: Ty<'tcx>) -> Option<&'ll DIType> {
self.type_to_metadata.get(&type_).cloned()
}
- fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<DIType> {
+ fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<&'ll DIType> {
self.unique_id_to_metadata.get(&unique_type_id).cloned()
}
// needed to generate the missing parts of the description. See the
// documentation section on Recursive Types at the top of this file for more
// information.
-enum RecursiveTypeDescription<'tcx> {
+enum RecursiveTypeDescription<'ll, 'tcx> {
UnfinishedMetadata {
unfinished_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
- metadata_stub: DICompositeType,
- member_description_factory: MemberDescriptionFactory<'tcx>,
+ metadata_stub: &'ll DICompositeType,
+ member_description_factory: MemberDescriptionFactory<'ll, 'tcx>,
},
- FinalMetadata(DICompositeType)
+ FinalMetadata(&'ll DICompositeType)
}
-fn create_and_register_recursive_type_forward_declaration<'a, 'tcx>(
- cx: &CodegenCx<'a, 'tcx>,
+fn create_and_register_recursive_type_forward_declaration(
+ cx: &CodegenCx<'ll, 'tcx>,
unfinished_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
- metadata_stub: DICompositeType,
- member_description_factory: MemberDescriptionFactory<'tcx>)
- -> RecursiveTypeDescription<'tcx> {
+ metadata_stub: &'ll DICompositeType,
+ member_description_factory: MemberDescriptionFactory<'ll, 'tcx>,
+) -> RecursiveTypeDescription<'ll, 'tcx> {
// Insert the stub into the TypeMap in order to allow for recursive references
let mut type_map = debug_context(cx).type_map.borrow_mut();
}
}
-impl<'tcx> RecursiveTypeDescription<'tcx> {
+impl RecursiveTypeDescription<'ll, 'tcx> {
// Finishes up the description of the type in question (mostly by providing
// descriptions of the fields of the given type) and returns the final type
// metadata.
- fn finalize<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> MetadataCreationResult {
+ fn finalize(&self, cx: &CodegenCx<'ll, 'tcx>) -> MetadataCreationResult<'ll> {
match *self {
FinalMetadata(metadata) => MetadataCreationResult::new(metadata, false),
UnfinishedMetadata {
)
}
-fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- unique_type_id: UniqueTypeId,
- array_or_slice_type: Ty<'tcx>,
- element_type: Ty<'tcx>,
- span: Span)
- -> MetadataCreationResult {
+fn fixed_vec_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ unique_type_id: UniqueTypeId,
+ array_or_slice_type: Ty<'tcx>,
+ element_type: Ty<'tcx>,
+ span: Span,
+) -> MetadataCreationResult<'ll> {
let element_type_metadata = type_metadata(cx, element_type, span);
return_if_metadata_created_in_meantime!(cx, unique_type_id);
};
let subrange = unsafe {
- llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)
+ Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound))
};
let subscripts = create_DIArray(DIB(cx), &[subrange]);
return MetadataCreationResult::new(metadata, false);
}
-fn vec_slice_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- slice_ptr_type: Ty<'tcx>,
- element_type: Ty<'tcx>,
- unique_type_id: UniqueTypeId,
- span: Span)
- -> MetadataCreationResult {
+fn vec_slice_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ slice_ptr_type: Ty<'tcx>,
+ element_type: Ty<'tcx>,
+ unique_type_id: UniqueTypeId,
+ span: Span,
+) -> MetadataCreationResult<'ll> {
let data_ptr_type = cx.tcx.mk_imm_ptr(element_type);
let data_ptr_metadata = type_metadata(cx, data_ptr_type, span);
MetadataCreationResult::new(metadata, false)
}
-fn subroutine_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- unique_type_id: UniqueTypeId,
- signature: ty::PolyFnSig<'tcx>,
- span: Span)
- -> MetadataCreationResult
-{
+fn subroutine_type_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ unique_type_id: UniqueTypeId,
+ signature: ty::PolyFnSig<'tcx>,
+ span: Span,
+) -> MetadataCreationResult<'ll> {
let signature = cx.tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&signature,
);
- let signature_metadata: Vec<DIType> = iter::once(
+ let signature_metadata: Vec<_> = iter::once(
// return type
match signature.output().sty {
- ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
- _ => type_metadata(cx, signature.output(), span)
+ ty::TyTuple(ref tys) if tys.is_empty() => None,
+ _ => Some(type_metadata(cx, signature.output(), span))
}
).chain(
// regular arguments
- signature.inputs().iter().map(|argument_type| type_metadata(cx, argument_type, span))
+ signature.inputs().iter().map(|argument_type| {
+ Some(type_metadata(cx, argument_type, span))
+ })
).collect();
return_if_metadata_created_in_meantime!(cx, unique_type_id);
// trait_type should be the actual trait (e.g., Trait). Where the trait is part
// of a DST struct, there is no trait_object_type and the results of this
// function will be a little bit weird.
-fn trait_pointer_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- trait_type: Ty<'tcx>,
- trait_object_type: Option<Ty<'tcx>>,
- unique_type_id: UniqueTypeId)
- -> DIType {
+fn trait_pointer_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ trait_type: Ty<'tcx>,
+ trait_object_type: Option<Ty<'tcx>>,
+ unique_type_id: UniqueTypeId,
+) -> &'ll DIType {
// The implementation provided here is a stub. It makes sure that the trait
// type is assigned the correct name, size, namespace, and source location.
// But it does not describe the trait's methods.
let containing_scope = match trait_type.sty {
ty::TyDynamic(ref data, ..) => if let Some(principal) = data.principal() {
let def_id = principal.def_id();
- get_namespace_for_item(cx, def_id)
+ Some(get_namespace_for_item(cx, def_id))
} else {
NO_SCOPE_METADATA
},
syntax_pos::DUMMY_SP)
}
-pub fn type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- t: Ty<'tcx>,
- usage_site_span: Span)
- -> DIType {
+pub fn type_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ t: Ty<'tcx>,
+ usage_site_span: Span,
+) -> &'ll DIType {
// Get the unique type id of this type.
let unique_type_id = {
let mut type_map = debug_context(cx).type_map.borrow_mut();
metadata
}
-pub fn file_metadata(cx: &CodegenCx,
+pub fn file_metadata(cx: &CodegenCx<'ll, '_>,
file_name: &FileName,
- defining_crate: CrateNum) -> DIFile {
+ defining_crate: CrateNum) -> &'ll DIFile {
debug!("file_metadata: file_name: {}, defining_crate: {}",
file_name,
defining_crate);
file_metadata_raw(cx, &file_name.to_string(), &directory.to_string_lossy())
}
-pub fn unknown_file_metadata(cx: &CodegenCx) -> DIFile {
+pub fn unknown_file_metadata(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
file_metadata_raw(cx, "<unknown>", "")
}
-fn file_metadata_raw(cx: &CodegenCx,
+fn file_metadata_raw(cx: &CodegenCx<'ll, '_>,
file_name: &str,
directory: &str)
- -> DIFile {
+ -> &'ll DIFile {
let key = (Symbol::intern(file_name), Symbol::intern(directory));
if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(&key) {
file_metadata
}
-fn basic_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- t: Ty<'tcx>) -> DIType {
-
+fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
debug!("basic_type_metadata: {:?}", t);
let (name, encoding) = match t.sty {
return ty_metadata;
}
-fn foreign_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- t: Ty<'tcx>,
- unique_type_id: UniqueTypeId) -> DIType {
+fn foreign_type_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ t: Ty<'tcx>,
+ unique_type_id: UniqueTypeId,
+) -> &'ll DIType {
debug!("foreign_type_metadata: {:?}", t);
let name = compute_debuginfo_type_name(cx, t, false);
create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA)
}
-fn pointer_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- pointer_type: Ty<'tcx>,
- pointee_type_metadata: DIType)
- -> DIType {
+fn pointer_type_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ pointer_type: Ty<'tcx>,
+ pointee_type_metadata: &'ll DIType,
+) -> &'ll DIType {
let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type);
let name = compute_debuginfo_type_name(cx, pointer_type, false);
let name = CString::new(name).unwrap();
pub fn compile_unit_metadata(tcx: TyCtxt,
codegen_unit_name: &str,
- debug_context: &CrateDebugContext)
- -> DIDescriptor {
+ debug_context: &CrateDebugContext<'ll, '_>)
+ -> &'ll DIDescriptor {
let mut name_in_debuginfo = match tcx.sess.local_crate_source_file {
Some(ref path) => path.clone(),
None => PathBuf::from(&*tcx.crate_name(LOCAL_CRATE).as_str()),
return unit_metadata;
};
- fn path_to_mdstring(llcx: llvm::ContextRef, path: &Path) -> llvm::ValueRef {
+ fn path_to_mdstring(llcx: &'ll llvm::Context, path: &Path) -> &'ll Value {
let path_str = path2cstr(path);
unsafe {
llvm::LLVMMDStringInContext(llcx,
}
}
-struct MetadataCreationResult {
- metadata: DIType,
+struct MetadataCreationResult<'ll> {
+ metadata: &'ll DIType,
already_stored_in_typemap: bool
}
-impl MetadataCreationResult {
- fn new(metadata: DIType, already_stored_in_typemap: bool) -> MetadataCreationResult {
+impl MetadataCreationResult<'ll> {
+ fn new(metadata: &'ll DIType, already_stored_in_typemap: bool) -> Self {
MetadataCreationResult {
metadata,
already_stored_in_typemap,
// Description of a type member, which can either be a regular field (as in
// structs or tuples) or an enum variant.
#[derive(Debug)]
-struct MemberDescription {
+struct MemberDescription<'ll> {
name: String,
- type_metadata: DIType,
+ type_metadata: &'ll DIType,
offset: Size,
size: Size,
align: Align,
// for some record-like type. MemberDescriptionFactories are used to defer the
// creation of type member descriptions in order to break cycles arising from
// recursive type definitions.
-enum MemberDescriptionFactory<'tcx> {
+enum MemberDescriptionFactory<'ll, 'tcx> {
StructMDF(StructMemberDescriptionFactory<'tcx>),
TupleMDF(TupleMemberDescriptionFactory<'tcx>),
- EnumMDF(EnumMemberDescriptionFactory<'tcx>),
+ EnumMDF(EnumMemberDescriptionFactory<'ll, 'tcx>),
UnionMDF(UnionMemberDescriptionFactory<'tcx>),
- VariantMDF(VariantMemberDescriptionFactory<'tcx>)
+ VariantMDF(VariantMemberDescriptionFactory<'ll, 'tcx>)
}
-impl<'tcx> MemberDescriptionFactory<'tcx> {
- fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
- -> Vec<MemberDescription> {
+impl MemberDescriptionFactory<'ll, 'tcx> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
+ -> Vec<MemberDescription<'ll>> {
match *self {
StructMDF(ref this) => {
this.create_member_descriptions(cx)
}
impl<'tcx> StructMemberDescriptionFactory<'tcx> {
- fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
- -> Vec<MemberDescription> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
+ -> Vec<MemberDescription<'ll>> {
let layout = cx.layout_of(self.ty);
self.variant.fields.iter().enumerate().map(|(i, f)| {
let name = if self.variant.ctor_kind == CtorKind::Fn {
}
-fn prepare_struct_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- struct_type: Ty<'tcx>,
- unique_type_id: UniqueTypeId,
- span: Span)
- -> RecursiveTypeDescription<'tcx> {
+fn prepare_struct_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ struct_type: Ty<'tcx>,
+ unique_type_id: UniqueTypeId,
+ span: Span,
+) -> RecursiveTypeDescription<'ll, 'tcx> {
let struct_name = compute_debuginfo_type_name(cx, struct_type, false);
let (struct_def_id, variant) = match struct_type.sty {
struct_type,
&struct_name,
unique_type_id,
- containing_scope);
+ Some(containing_scope));
create_and_register_recursive_type_forward_declaration(
cx,
}
impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
- fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
- -> Vec<MemberDescription> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
+ -> Vec<MemberDescription<'ll>> {
let layout = cx.layout_of(self.ty);
self.component_types.iter().enumerate().map(|(i, &component_type)| {
let (size, align) = cx.size_and_align_of(component_type);
}
}
-fn prepare_tuple_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- tuple_type: Ty<'tcx>,
- component_types: &[Ty<'tcx>],
- unique_type_id: UniqueTypeId,
- span: Span)
- -> RecursiveTypeDescription<'tcx> {
+fn prepare_tuple_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ tuple_type: Ty<'tcx>,
+ component_types: &[Ty<'tcx>],
+ unique_type_id: UniqueTypeId,
+ span: Span,
+) -> RecursiveTypeDescription<'ll, 'tcx> {
let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false);
create_and_register_recursive_type_forward_declaration(
}
impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
- fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
- -> Vec<MemberDescription> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
+ -> Vec<MemberDescription<'ll>> {
self.variant.fields.iter().enumerate().map(|(i, f)| {
let field = self.layout.field(cx, i);
let (size, align) = field.size_and_align();
}
}
-fn prepare_union_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- union_type: Ty<'tcx>,
- unique_type_id: UniqueTypeId,
- span: Span)
- -> RecursiveTypeDescription<'tcx> {
+fn prepare_union_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ union_type: Ty<'tcx>,
+ unique_type_id: UniqueTypeId,
+ span: Span,
+) -> RecursiveTypeDescription<'ll, 'tcx> {
let union_name = compute_debuginfo_type_name(cx, union_type, false);
let (union_def_id, variant) = match union_type.sty {
// the members of this union; so for every variant of the given enum, this
// factory will produce one MemberDescription (all with no name and a fixed
// offset of zero bytes).
-struct EnumMemberDescriptionFactory<'tcx> {
+struct EnumMemberDescriptionFactory<'ll, 'tcx> {
enum_type: Ty<'tcx>,
layout: TyLayout<'tcx>,
- discriminant_type_metadata: Option<DIType>,
- containing_scope: DIScope,
+ discriminant_type_metadata: Option<&'ll DIType>,
+ containing_scope: &'ll DIScope,
span: Span,
}
-impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
- fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
- -> Vec<MemberDescription> {
+impl EnumMemberDescriptionFactory<'ll, 'tcx> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
+ -> Vec<MemberDescription<'ll>> {
let adt = &self.enum_type.ty_adt_def().unwrap();
match self.layout.variants {
layout::Variants::Single { .. } if adt.variants.is_empty() => vec![],
}
// Creates MemberDescriptions for the fields of a single enum variant.
-struct VariantMemberDescriptionFactory<'tcx> {
+struct VariantMemberDescriptionFactory<'ll, 'tcx> {
// Cloned from the layout::Struct describing the variant.
offsets: Vec<layout::Size>,
args: Vec<(String, Ty<'tcx>)>,
- discriminant_type_metadata: Option<DIType>,
+ discriminant_type_metadata: Option<&'ll DIType>,
span: Span,
}
-impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
- fn create_member_descriptions<'a>(&self, cx: &CodegenCx<'a, 'tcx>)
- -> Vec<MemberDescription> {
+impl VariantMemberDescriptionFactory<'ll, 'tcx> {
+ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
+ -> Vec<MemberDescription<'ll>> {
self.args.iter().enumerate().map(|(i, &(ref name, ty))| {
let (size, align) = cx.size_and_align_of(ty);
MemberDescription {
}
#[derive(Copy, Clone)]
-enum EnumDiscriminantInfo {
- RegularDiscriminant(DIType),
+enum EnumDiscriminantInfo<'ll> {
+ RegularDiscriminant(&'ll DIType),
OptimizedDiscriminant,
NoDiscriminant
}
// of the variant, and (3) a MemberDescriptionFactory for producing the
// descriptions of the fields of the variant. This is a rudimentary version of a
// full RecursiveTypeDescription.
-fn describe_enum_variant<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- layout: layout::TyLayout<'tcx>,
- variant: &'tcx ty::VariantDef,
- discriminant_info: EnumDiscriminantInfo,
- containing_scope: DIScope,
- span: Span)
- -> (DICompositeType, MemberDescriptionFactory<'tcx>) {
+fn describe_enum_variant(
+ cx: &CodegenCx<'ll, 'tcx>,
+ layout: layout::TyLayout<'tcx>,
+ variant: &'tcx ty::VariantDef,
+ discriminant_info: EnumDiscriminantInfo<'ll>,
+ containing_scope: &'ll DIScope,
+ span: Span,
+) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
let variant_name = variant.name.as_str();
let unique_type_id = debug_context(cx).type_map
.borrow_mut()
layout.ty,
&variant_name,
unique_type_id,
- containing_scope);
+ Some(containing_scope));
// If this is not a univariant enum, there is also the discriminant field.
let (discr_offset, discr_arg) = match discriminant_info {
(metadata_stub, member_description_factory)
}
-fn prepare_enum_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- enum_type: Ty<'tcx>,
- enum_def_id: DefId,
- unique_type_id: UniqueTypeId,
- span: Span)
- -> RecursiveTypeDescription<'tcx> {
+fn prepare_enum_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ enum_type: Ty<'tcx>,
+ enum_def_id: DefId,
+ unique_type_id: UniqueTypeId,
+ span: Span,
+) -> RecursiveTypeDescription<'ll, 'tcx> {
let enum_name = compute_debuginfo_type_name(cx, enum_type, false);
let containing_scope = get_namespace_for_item(cx, enum_def_id);
let file_metadata = unknown_file_metadata(cx);
let def = enum_type.ty_adt_def().unwrap();
- let enumerators_metadata: Vec<DIDescriptor> = def.discriminants(cx.tcx)
+ let enumerators_metadata: Vec<_> = def.discriminants(cx.tcx)
.zip(&def.variants)
.map(|(discr, v)| {
let token = v.name.as_str();
let name = CString::new(token.as_bytes()).unwrap();
unsafe {
- llvm::LLVMRustDIBuilderCreateEnumerator(
+ Some(llvm::LLVMRustDIBuilderCreateEnumerator(
DIB(cx),
name.as_ptr(),
// FIXME: what if enumeration has i128 discriminant?
- discr.val as u64)
+ discr.val as u64))
}
})
.collect();
enum_type_size.bits(),
enum_type_align.abi_bits() as u32,
DIFlags::FlagZero,
- ptr::null_mut(),
+ None,
0, // RuntimeLang
unique_type_id_str.as_ptr())
};
/// results in a LLVM struct.
///
/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums.
-fn composite_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- composite_type: Ty<'tcx>,
- composite_type_name: &str,
- composite_type_unique_id: UniqueTypeId,
- member_descriptions: &[MemberDescription],
- containing_scope: DIScope,
-
- // Ignore source location information as long as it
- // can't be reconstructed for non-local crates.
- _file_metadata: DIFile,
- _definition_span: Span)
- -> DICompositeType {
+fn composite_type_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ composite_type: Ty<'tcx>,
+ composite_type_name: &str,
+ composite_type_unique_id: UniqueTypeId,
+ member_descriptions: &[MemberDescription<'ll>],
+ containing_scope: Option<&'ll DIScope>,
+
+ // Ignore source location information as long as it
+ // can't be reconstructed for non-local crates.
+ _file_metadata: &'ll DIFile,
+ _definition_span: Span,
+) -> &'ll DICompositeType {
// Create the (empty) struct metadata node ...
let composite_type_metadata = create_struct_stub(cx,
composite_type,
return composite_type_metadata;
}
-fn set_members_of_composite_type(cx: &CodegenCx,
- composite_type_metadata: DICompositeType,
- member_descriptions: &[MemberDescription]) {
+fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>,
+ composite_type_metadata: &'ll DICompositeType,
+ member_descriptions: &[MemberDescription<'ll>]) {
// In some rare cases LLVM metadata uniquing would lead to an existing type
// description being used instead of a new one created in
// create_struct_stub. This would cause a hard to trace assertion in
}
}
- let member_metadata: Vec<DIDescriptor> = member_descriptions
+ let member_metadata: Vec<_> = member_descriptions
.iter()
.map(|member_description| {
let member_name = member_description.name.as_bytes();
let member_name = CString::new(member_name).unwrap();
unsafe {
- llvm::LLVMRustDIBuilderCreateMemberType(
+ Some(llvm::LLVMRustDIBuilderCreateMemberType(
DIB(cx),
composite_type_metadata,
member_name.as_ptr(),
member_description.align.abi_bits() as u32,
member_description.offset.bits(),
member_description.flags,
- member_description.type_metadata)
+ member_description.type_metadata))
}
})
.collect();
// A convenience wrapper around LLVMRustDIBuilderCreateStructType(). Does not do
// any caching, does not add any fields to the struct. This can be done later
// with set_members_of_composite_type().
-fn create_struct_stub<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- struct_type: Ty<'tcx>,
- struct_type_name: &str,
- unique_type_id: UniqueTypeId,
- containing_scope: DIScope)
- -> DICompositeType {
+fn create_struct_stub(
+ cx: &CodegenCx<'ll, 'tcx>,
+ struct_type: Ty<'tcx>,
+ struct_type_name: &str,
+ unique_type_id: UniqueTypeId,
+ containing_scope: Option<&'ll DIScope>,
+) -> &'ll DICompositeType {
let (struct_size, struct_align) = cx.size_and_align_of(struct_type);
let name = CString::new(struct_type_name).unwrap();
struct_size.bits(),
struct_align.abi_bits() as u32,
DIFlags::FlagZero,
- ptr::null_mut(),
+ None,
empty_array,
0,
- ptr::null_mut(),
+ None,
unique_type_id.as_ptr())
};
return metadata_stub;
}
-fn create_union_stub<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- union_type: Ty<'tcx>,
- union_type_name: &str,
- unique_type_id: UniqueTypeId,
- containing_scope: DIScope)
- -> DICompositeType {
+fn create_union_stub(
+ cx: &CodegenCx<'ll, 'tcx>,
+ union_type: Ty<'tcx>,
+ union_type_name: &str,
+ unique_type_id: UniqueTypeId,
+ containing_scope: &'ll DIScope,
+) -> &'ll DICompositeType {
let (union_size, union_align) = cx.size_and_align_of(union_type);
let name = CString::new(union_type_name).unwrap();
union_size.bits(),
union_align.abi_bits() as u32,
DIFlags::FlagZero,
- empty_array,
+ Some(empty_array),
0, // RuntimeLang
unique_type_id.as_ptr())
};
/// Creates debug information for the given global variable.
///
/// Adds the created metadata nodes directly to the crate's IR.
-pub fn create_global_var_metadata(cx: &CodegenCx,
- def_id: DefId,
- global: ValueRef) {
+pub fn create_global_var_metadata(
+ cx: &CodegenCx<'ll, '_>,
+ def_id: DefId,
+ global: &'ll Value,
+) {
if cx.dbg_cx.is_none() {
return;
}
unsafe {
llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx),
- var_scope,
+ Some(var_scope),
var_name.as_ptr(),
// If null, linkage_name field is omitted,
// which is what we want for no_mangle statics
type_metadata,
is_local_to_unit,
global,
- ptr::null_mut(),
+ None,
global_align.abi() as u32,
);
}
}
// Creates an "extension" of an existing DIScope into another file.
-pub fn extend_scope_to_file(cx: &CodegenCx,
- scope_metadata: DIScope,
- file: &syntax_pos::FileMap,
- defining_crate: CrateNum)
- -> DILexicalBlock {
+pub fn extend_scope_to_file(
+ cx: &CodegenCx<'ll, '_>,
+ scope_metadata: &'ll DIScope,
+ file: &syntax_pos::FileMap,
+ defining_crate: CrateNum,
+) -> &'ll DILexicalBlock {
let file_metadata = file_metadata(cx, &file.name, defining_crate);
unsafe {
llvm::LLVMRustDIBuilderCreateLexicalBlockFile(
/// given type.
///
/// Adds the created metadata nodes directly to the crate's IR.
-pub fn create_vtable_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- ty: ty::Ty<'tcx>,
- vtable: ValueRef) {
+pub fn create_vtable_metadata(
+ cx: &CodegenCx<'ll, 'tcx>,
+ ty: ty::Ty<'tcx>,
+ vtable: &'ll Value,
+) {
if cx.dbg_cx.is_none() {
return;
}
Size::ZERO.bits(),
cx.tcx.data_layout.pointer_align.abi_bits() as u32,
DIFlags::FlagArtificial,
- ptr::null_mut(),
+ None,
empty_array,
0,
- type_metadata,
+ Some(type_metadata),
name.as_ptr()
);
vtable_type,
true,
vtable,
- ptr::null_mut(),
+ None,
0);
}
}
use self::source_loc::InternalDebugLocation::{self, UnknownLocation};
use llvm;
-use llvm::{ModuleRef, ContextRef, ValueRef};
-use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags};
+use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, DIArray, DIFlags};
use rustc::hir::CodegenFnAttrFlags;
use rustc::hir::def_id::{DefId, CrateNum};
use rustc::ty::subst::{Substs, UnpackedKind};
use monomorphize::Instance;
use rustc::ty::{self, ParamEnv, Ty, InstanceDef};
use rustc::mir;
-use rustc::session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
+use rustc::session::config::{self, DebugInfo};
use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
+use value::Value;
use libc::c_uint;
use std::cell::{Cell, RefCell};
use std::ffi::CString;
-use std::ptr;
use syntax_pos::{self, Span, Pos};
use syntax::ast;
const DW_TAG_arg_variable: c_uint = 0x101;
/// A context object for maintaining all state needed by the debuginfo module.
-pub struct CrateDebugContext<'tcx> {
- llcontext: ContextRef,
- llmod: ModuleRef,
- builder: DIBuilderRef,
- created_files: RefCell<FxHashMap<(Symbol, Symbol), DIFile>>,
- created_enum_disr_types: RefCell<FxHashMap<(DefId, layout::Primitive), DIType>>,
+pub struct CrateDebugContext<'a, 'tcx> {
+ llcontext: &'a llvm::Context,
+ llmod: &'a llvm::Module,
+ builder: &'a mut DIBuilder<'a>,
+ created_files: RefCell<FxHashMap<(Symbol, Symbol), &'a DIFile>>,
+ created_enum_disr_types: RefCell<FxHashMap<(DefId, layout::Primitive), &'a DIType>>,
- type_map: RefCell<TypeMap<'tcx>>,
- namespace_map: RefCell<DefIdMap<DIScope>>,
+ type_map: RefCell<TypeMap<'a, 'tcx>>,
+ namespace_map: RefCell<DefIdMap<&'a DIScope>>,
// This collection is used to assert that composite types (structs, enums,
// ...) have their members only set once:
- composite_types_completed: RefCell<FxHashSet<DIType>>,
+ composite_types_completed: RefCell<FxHashSet<&'a DIType>>,
}
-impl<'tcx> CrateDebugContext<'tcx> {
- pub fn new(llmod: ModuleRef) -> CrateDebugContext<'tcx> {
+impl Drop for CrateDebugContext<'a, 'tcx> {
+ fn drop(&mut self) {
+ unsafe {
+ llvm::LLVMRustDIBuilderDispose(&mut *(self.builder as *mut _));
+ }
+ }
+}
+
+impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> {
+ pub fn new(llmod: &'a llvm::Module) -> Self {
debug!("CrateDebugContext::new");
let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) };
// DIBuilder inherits context from the module, so we'd better use the same one
}
}
-pub enum FunctionDebugContext {
- RegularContext(FunctionDebugContextData),
+pub enum FunctionDebugContext<'ll> {
+ RegularContext(FunctionDebugContextData<'ll>),
DebugInfoDisabled,
FunctionWithoutDebugInfo,
}
-impl FunctionDebugContext {
- pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData {
+impl FunctionDebugContext<'ll> {
+ pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData<'ll> {
match *self {
FunctionDebugContext::RegularContext(ref data) => data,
FunctionDebugContext::DebugInfoDisabled => {
}
}
-pub struct FunctionDebugContextData {
- fn_metadata: DISubprogram,
+pub struct FunctionDebugContextData<'ll> {
+ fn_metadata: &'ll DISubprogram,
source_locations_enabled: Cell<bool>,
pub defining_crate: CrateNum,
}
-pub enum VariableAccess<'a> {
+pub enum VariableAccess<'a, 'll> {
// The llptr given is an alloca containing the variable's value
- DirectVariable { alloca: ValueRef },
+ DirectVariable { alloca: &'ll Value },
// The llptr given is an alloca containing the start of some pointer chain
// leading to the variable's content.
- IndirectVariable { alloca: ValueRef, address_operations: &'a [i64] }
+ IndirectVariable { alloca: &'ll Value, address_operations: &'a [i64] }
}
pub enum VariableKind {
unsafe {
llvm::LLVMRustDIBuilderFinalize(DIB(cx));
- llvm::LLVMRustDIBuilderDispose(DIB(cx));
// Debuginfo generation in LLVM by default uses a higher
// version of dwarf than macOS currently understands. We can
// instruct LLVM to emit an older version of dwarf, however,
/// for debug info creation. The function may also return another variant of the
/// FunctionDebugContext enum which indicates why no debuginfo should be created
/// for the function.
-pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- instance: Instance<'tcx>,
- sig: ty::FnSig<'tcx>,
- llfn: ValueRef,
- mir: &mir::Mir) -> FunctionDebugContext {
- if cx.sess().opts.debuginfo == NoDebugInfo {
+pub fn create_function_debug_context(
+ cx: &CodegenCx<'ll, 'tcx>,
+ instance: Instance<'tcx>,
+ sig: ty::FnSig<'tcx>,
+ llfn: &'ll Value,
+ mir: &mir::Mir,
+) -> FunctionDebugContext<'ll> {
+ if cx.sess().opts.debuginfo == DebugInfo::None {
return FunctionDebugContext::DebugInfoDisabled;
}
cx.sess().opts.optimize != config::OptLevel::No,
llfn,
template_parameters,
- ptr::null_mut())
+ None)
};
// Initialize fn debug context (including scope map and namespace map)
return FunctionDebugContext::RegularContext(fn_debug_context);
- fn get_function_signature<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- sig: ty::FnSig<'tcx>) -> DIArray {
- if cx.sess().opts.debuginfo == LimitedDebugInfo {
+ fn get_function_signature(
+ cx: &CodegenCx<'ll, 'tcx>,
+ sig: ty::FnSig<'tcx>,
+ ) -> &'ll DIArray {
+ if cx.sess().opts.debuginfo == DebugInfo::Limited {
return create_DIArray(DIB(cx), &[]);
}
// Return type -- llvm::DIBuilder wants this at index 0
signature.push(match sig.output().sty {
- ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
- _ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)
+ ty::TyTuple(ref tys) if tys.is_empty() => None,
+ _ => Some(type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP))
});
let inputs = if sig.abi == Abi::RustCall {
}
_ => t
};
- type_metadata(cx, t, syntax_pos::DUMMY_SP)
+ Some(type_metadata(cx, t, syntax_pos::DUMMY_SP))
}));
} else {
signature.extend(inputs.iter().map(|t| {
- type_metadata(cx, t, syntax_pos::DUMMY_SP)
+ Some(type_metadata(cx, t, syntax_pos::DUMMY_SP))
}));
}
if sig.abi == Abi::RustCall && !sig.inputs().is_empty() {
if let ty::TyTuple(args) = sig.inputs()[sig.inputs().len() - 1].sty {
signature.extend(
- args.iter().map(|argument_type|
- type_metadata(cx, argument_type, syntax_pos::DUMMY_SP))
+ args.iter().map(|argument_type| {
+ Some(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP))
+ })
);
}
}
return create_DIArray(DIB(cx), &signature[..]);
}
- fn get_template_parameters<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- generics: &ty::Generics,
- substs: &Substs<'tcx>,
- file_metadata: DIFile,
- name_to_append_suffix_to: &mut String)
- -> DIArray
- {
+ fn get_template_parameters(
+ cx: &CodegenCx<'ll, 'tcx>,
+ generics: &ty::Generics,
+ substs: &Substs<'tcx>,
+ file_metadata: &'ll DIFile,
+ name_to_append_suffix_to: &mut String,
+ ) -> &'ll DIArray {
if substs.types().next().is_none() {
return create_DIArray(DIB(cx), &[]);
}
name_to_append_suffix_to.push('>');
// Again, only create type information if full debuginfo is enabled
- let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo {
+ let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
let names = get_parameter_names(cx, generics);
substs.iter().zip(names).filter_map(|(kind, name)| {
if let UnpackedKind::Type(ty) = kind.unpack() {
type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
let name = CString::new(name.as_str().as_bytes()).unwrap();
Some(unsafe {
- llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
+ Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(cx),
- ptr::null_mut(),
+ None,
name.as_ptr(),
actual_type_metadata,
file_metadata,
0,
- 0)
+ 0,
+ ))
})
} else {
None
names
}
- fn get_containing_scope<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>,
- instance: Instance<'tcx>)
- -> DIScope {
+ fn get_containing_scope(
+ cx: &CodegenCx<'ll, 'tcx>,
+ instance: Instance<'tcx>,
+ ) -> &'ll DIScope {
// First, let's see if this is a method within an inherent impl. Because
// if yes, we want to make the result subroutine DIE a child of the
// subroutine's self-type.
}
}
-pub fn declare_local<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
- dbg_context: &FunctionDebugContext,
- variable_name: ast::Name,
- variable_type: Ty<'tcx>,
- scope_metadata: DIScope,
- variable_access: VariableAccess,
- variable_kind: VariableKind,
- span: Span) {
+pub fn declare_local(
+ bx: &Builder<'a, 'll, 'tcx>,
+ dbg_context: &FunctionDebugContext<'ll>,
+ variable_name: ast::Name,
+ variable_type: Ty<'tcx>,
+ scope_metadata: &'ll DIScope,
+ variable_access: VariableAccess<'_, 'll>,
+ variable_kind: VariableKind,
+ span: Span,
+) {
assert!(!dbg_context.get_ref(span).source_locations_enabled.get());
let cx = bx.cx;
use common::CodegenCx;
use std::ffi::CString;
-use std::ptr;
pub fn mangled_name_of_instance<'a, 'tcx>(
cx: &CodegenCx<'a, 'tcx>,
tcx.symbol_name(instance)
}
-pub fn item_namespace(cx: &CodegenCx, def_id: DefId) -> DIScope {
+pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
if let Some(&scope) = debug_context(cx).namespace_map.borrow().get(&def_id) {
return scope;
}
let def_key = cx.tcx.def_key(def_id);
- let parent_scope = def_key.parent.map_or(ptr::null_mut(), |parent| {
+ let parent_scope = def_key.parent.map(|parent| {
item_namespace(cx, DefId {
krate: def_id.krate,
index: parent
use builder::Builder;
use libc::c_uint;
-use std::ptr;
use syntax_pos::{Span, Pos};
/// Sets the current debug location at the beginning of the span.
///
/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...).
pub fn set_source_location(
- debug_context: &FunctionDebugContext, bx: &Builder, scope: DIScope, span: Span
+ debug_context: &FunctionDebugContext<'ll>,
+ bx: &Builder<'_, 'll, '_>,
+ scope: Option<&'ll DIScope>,
+ span: Span,
) {
let function_debug_context = match *debug_context {
FunctionDebugContext::DebugInfoDisabled => return,
let dbg_loc = if function_debug_context.source_locations_enabled.get() {
debug!("set_source_location: {}", bx.sess().codemap().span_to_string(span));
let loc = span_start(bx.cx, span);
- InternalDebugLocation::new(scope, loc.line, loc.col.to_usize())
+ InternalDebugLocation::new(scope.unwrap(), loc.line, loc.col.to_usize())
} else {
UnknownLocation
};
/// they are disabled when beginning to codegen a new function. This functions
/// switches source location emitting on and must therefore be called before the
/// first real statement/expression of the function is codegened.
-pub fn start_emitting_source_locations(dbg_context: &FunctionDebugContext) {
+pub fn start_emitting_source_locations(dbg_context: &FunctionDebugContext<'ll>) {
match *dbg_context {
FunctionDebugContext::RegularContext(ref data) => {
data.source_locations_enabled.set(true)
#[derive(Copy, Clone, PartialEq)]
-pub enum InternalDebugLocation {
- KnownLocation { scope: DIScope, line: usize, col: usize },
+pub enum InternalDebugLocation<'ll> {
+ KnownLocation { scope: &'ll DIScope, line: usize, col: usize },
UnknownLocation
}
-impl InternalDebugLocation {
- pub fn new(scope: DIScope, line: usize, col: usize) -> InternalDebugLocation {
+impl InternalDebugLocation<'ll> {
+ pub fn new(scope: &'ll DIScope, line: usize, col: usize) -> Self {
KnownLocation {
scope,
line,
}
}
-pub fn set_debug_location(bx: &Builder, debug_location: InternalDebugLocation) {
+pub fn set_debug_location(bx: &Builder<'_, 'll, '_>, debug_location: InternalDebugLocation<'ll>) {
let metadata_node = match debug_location {
KnownLocation { scope, line, col } => {
// For MSVC, set the column number to zero.
debug!("setting debug location to {} {}", line, col);
unsafe {
- llvm::LLVMRustDIBuilderCreateDebugLocation(
+ Some(llvm::LLVMRustDIBuilderCreateDebugLocation(
debug_context(bx.cx).llcontext,
line as c_uint,
col_used,
scope,
- ptr::null_mut())
+ None))
}
}
UnknownLocation => {
debug!("clearing debug location ");
- ptr::null_mut()
+ None
}
};
use rustc::ty::DefIdTree;
use llvm;
-use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray};
+use llvm::debuginfo::{DIScope, DIBuilder, DIDescriptor, DIArray};
use common::{CodegenCx};
use syntax_pos::{self, Span};
}
#[allow(non_snake_case)]
-pub fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray {
+pub fn create_DIArray(
+ builder: &DIBuilder<'ll>,
+ arr: &[Option<&'ll DIDescriptor>],
+) -> &'ll DIArray {
return unsafe {
llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32)
};
}
#[inline]
-pub fn debug_context<'a, 'tcx>(cx: &'a CodegenCx<'a, 'tcx>)
- -> &'a CrateDebugContext<'tcx> {
+pub fn debug_context(cx: &'a CodegenCx<'ll, 'tcx>) -> &'a CrateDebugContext<'ll, 'tcx> {
cx.dbg_cx.as_ref().unwrap()
}
#[inline]
#[allow(non_snake_case)]
-pub fn DIB(cx: &CodegenCx) -> DIBuilderRef {
+pub fn DIB(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
cx.dbg_cx.as_ref().unwrap().builder
}
-pub fn get_namespace_for_item(cx: &CodegenCx, def_id: DefId) -> DIScope {
+pub fn get_namespace_for_item(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
item_namespace(cx, cx.tcx.parent(def_id)
.expect("get_namespace_for_item: missing parent?"))
}
//! Some useful guidelines:
//!
//! * Use declare_* family of methods if you are declaring, but are not
-//! interested in defining the ValueRef they return.
-//! * Use define_* family of methods when you might be defining the ValueRef.
+//! interested in defining the Value they return.
+//! * Use define_* family of methods when you might be defining the Value.
//! * When in doubt, define.
-use llvm::{self, ValueRef};
+use llvm;
use llvm::AttributePlace::Function;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, LayoutOf};
/// Declare a global value.
///
/// If there’s a value with the same name already declared, the function will
-/// return its ValueRef instead.
-pub fn declare_global(cx: &CodegenCx, name: &str, ty: Type) -> llvm::ValueRef {
+/// return its Value instead.
+pub fn declare_global(cx: &CodegenCx<'ll, '_>, name: &str, ty: &'ll Type) -> &'ll Value {
debug!("declare_global(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
bug!("name {:?} contains an interior null byte", name)
});
unsafe {
- llvm::LLVMRustGetOrInsertGlobal(cx.llmod, namebuf.as_ptr(), ty.to_ref())
+ llvm::LLVMRustGetOrInsertGlobal(cx.llmod, namebuf.as_ptr(), ty)
}
}
/// Declare a function.
///
/// If there’s a value with the same name already declared, the function will
-/// update the declaration and return existing ValueRef instead.
-fn declare_raw_fn(cx: &CodegenCx, name: &str, callconv: llvm::CallConv, ty: Type) -> ValueRef {
+/// update the declaration and return existing Value instead.
+fn declare_raw_fn(
+ cx: &CodegenCx<'ll, '_>,
+ name: &str,
+ callconv: llvm::CallConv,
+ ty: &'ll Type,
+) -> &'ll Value {
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
let namebuf = CString::new(name).unwrap_or_else(|_|{
bug!("name {:?} contains an interior null byte", name)
});
let llfn = unsafe {
- llvm::LLVMRustGetOrInsertFunction(cx.llmod, namebuf.as_ptr(), ty.to_ref())
+ llvm::LLVMRustGetOrInsertFunction(cx.llmod, namebuf.as_ptr(), ty)
};
llvm::SetFunctionCallConv(llfn, callconv);
/// `declare_fn` instead.
///
/// If there’s a value with the same name already declared, the function will
-/// update the declaration and return existing ValueRef instead.
-pub fn declare_cfn(cx: &CodegenCx, name: &str, fn_type: Type) -> ValueRef {
+/// update the declaration and return existing Value instead.
+pub fn declare_cfn(cx: &CodegenCx<'ll, '_>, name: &str, fn_type: &'ll Type) -> &'ll Value {
declare_raw_fn(cx, name, llvm::CCallConv, fn_type)
}
/// Declare a Rust function.
///
/// If there’s a value with the same name already declared, the function will
-/// update the declaration and return existing ValueRef instead.
-pub fn declare_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name: &str,
- fn_type: Ty<'tcx>) -> ValueRef {
+/// update the declaration and return existing Value instead.
+pub fn declare_fn(
+ cx: &CodegenCx<'ll, 'tcx>,
+ name: &str,
+ fn_type: Ty<'tcx>,
+) -> &'ll Value {
debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
let sig = common::ty_fn_sig(cx, fn_type);
let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
/// return None if the name already has a definition associated with it. In that
/// case an error should be reported to the user, because it usually happens due
/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
-pub fn define_global(cx: &CodegenCx, name: &str, ty: Type) -> Option<ValueRef> {
+pub fn define_global(cx: &CodegenCx<'ll, '_>, name: &str, ty: &'ll Type) -> Option<&'ll Value> {
if get_defined_value(cx, name).is_some() {
None
} else {
/// Use this function when you intend to define a function. This function will
/// return panic if the name already has a definition associated with it. This
/// can happen with #[no_mangle] or #[export_name], for example.
-pub fn define_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- name: &str,
- fn_type: Ty<'tcx>) -> ValueRef {
+pub fn define_fn(
+ cx: &CodegenCx<'ll, 'tcx>,
+ name: &str,
+ fn_type: Ty<'tcx>,
+) -> &'ll Value {
if get_defined_value(cx, name).is_some() {
cx.sess().fatal(&format!("symbol `{}` already defined", name))
} else {
/// Use this function when you intend to define a function. This function will
/// return panic if the name already has a definition associated with it. This
/// can happen with #[no_mangle] or #[export_name], for example.
-pub fn define_internal_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- name: &str,
- fn_type: Ty<'tcx>) -> ValueRef {
+pub fn define_internal_fn(
+ cx: &CodegenCx<'ll, 'tcx>,
+ name: &str,
+ fn_type: Ty<'tcx>,
+) -> &'ll Value {
let llfn = define_fn(cx, name, fn_type);
unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
llfn
/// Get declared value by name.
-pub fn get_declared_value(cx: &CodegenCx, name: &str) -> Option<ValueRef> {
+pub fn get_declared_value(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> {
debug!("get_declared_value(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
bug!("name {:?} contains an interior null byte", name)
});
- let val = unsafe { llvm::LLVMRustGetNamedValue(cx.llmod, namebuf.as_ptr()) };
- if val.is_null() {
- debug!("get_declared_value: {:?} value is null", name);
- None
- } else {
- debug!("get_declared_value: {:?} => {:?}", name, Value(val));
- Some(val)
- }
+ unsafe { llvm::LLVMRustGetNamedValue(cx.llmod, namebuf.as_ptr()) }
}
/// Get defined or externally defined (AvailableExternally linkage) value by
/// name.
-pub fn get_defined_value(cx: &CodegenCx, name: &str) -> Option<ValueRef> {
+pub fn get_defined_value(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> {
get_declared_value(cx, name).and_then(|val|{
let declaration = unsafe {
llvm::LLVMIsDeclaration(val) != 0
use builder::Builder;
use common::*;
-use llvm::{ValueRef};
use llvm;
use meth;
use rustc::ty::layout::LayoutOf;
use rustc::ty::{self, Ty};
use value::Value;
-pub fn size_and_align_of_dst<'a, 'tcx>(bx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef)
- -> (ValueRef, ValueRef) {
+pub fn size_and_align_of_dst(bx: &Builder<'_, 'll, 'tcx>, t: Ty<'tcx>, info: Option<&'ll Value>)
+ -> (&'ll Value, &'ll Value) {
debug!("calculate size of DST: {}; with lost info: {:?}",
- t, Value(info));
+ t, info);
if bx.cx.type_is_sized(t) {
let (size, align) = bx.cx.size_and_align_of(t);
debug!("size_and_align_of_dst t={} info={:?} size: {:?} align: {:?}",
- t, Value(info), size, align);
+ t, info, size, align);
let size = C_usize(bx.cx, size.bytes());
let align = C_usize(bx.cx, align.abi());
return (size, align);
}
- assert!(!info.is_null());
match t.sty {
ty::TyDynamic(..) => {
// load size/align from vtable
- (meth::SIZE.get_usize(bx, info), meth::ALIGN.get_usize(bx, info))
+ let vtable = info.unwrap();
+ (meth::SIZE.get_usize(bx, vtable), meth::ALIGN.get_usize(bx, vtable))
}
ty::TySlice(_) | ty::TyStr => {
let unit = t.sequence_element_type(bx.tcx());
// The info in this case is the length of the str, so the size is that
// times the unit size.
let (size, align) = bx.cx.size_and_align_of(unit);
- (bx.mul(info, C_usize(bx.cx, size.bytes())),
+ (bx.mul(info.unwrap(), C_usize(bx.cx, size.bytes())),
C_usize(bx.cx, align.abi()))
}
_ => {
#![allow(non_upper_case_globals)]
use intrinsics::{self, Intrinsic};
-use llvm;
-use llvm::{ValueRef};
+use llvm::{self, TypeKind};
use abi::{Abi, FnType, LlvmType, PassMode};
use mir::place::PlaceRef;
use mir::operand::{OperandRef, OperandValue};
use syntax::ast;
use syntax::symbol::Symbol;
use builder::Builder;
+use value::Value;
use rustc::session::Session;
use syntax_pos::Span;
use std::cmp::Ordering;
use std::iter;
-fn get_simple_intrinsic(cx: &CodegenCx, name: &str) -> Option<ValueRef> {
+fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> {
let llvm_name = match name {
"sqrtf32" => "llvm.sqrt.f32",
"sqrtf64" => "llvm.sqrt.f64",
/// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs,
/// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics,
/// add them to librustc_codegen_llvm/context.rs
-pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
- callee_ty: Ty<'tcx>,
- fn_ty: &FnType<'tcx, Ty<'tcx>>,
- args: &[OperandRef<'tcx>],
- llresult: ValueRef,
- span: Span) {
+pub fn codegen_intrinsic_call(
+ bx: &Builder<'a, 'll, 'tcx>,
+ callee_ty: Ty<'tcx>,
+ fn_ty: &FnType<'tcx, Ty<'tcx>>,
+ args: &[OperandRef<'ll, 'tcx>],
+ llresult: &'ll Value,
+ span: Span,
+) {
let cx = bx.cx;
let tcx = cx.tcx;
let tp_ty = substs.type_at(0);
if let OperandValue::Pair(_, meta) = args[0].val {
let (llsize, _) =
- glue::size_and_align_of_dst(bx, tp_ty, meta);
+ glue::size_and_align_of_dst(bx, tp_ty, Some(meta));
llsize
} else {
C_usize(cx, cx.size_of(tp_ty).bytes())
let tp_ty = substs.type_at(0);
if let OperandValue::Pair(_, meta) = args[0].val {
let (_, llalign) =
- glue::size_and_align_of_dst(bx, tp_ty, meta);
+ glue::size_and_align_of_dst(bx, tp_ty, Some(meta));
llalign
} else {
C_usize(cx, cx.align_of(tp_ty).abi())
assert_eq!(x.len(), 1);
x.into_iter().next().unwrap()
}
- fn ty_to_type(cx: &CodegenCx, t: &intrinsics::Type) -> Vec<Type> {
+ fn ty_to_type(cx: &CodegenCx<'ll, '_>, t: &intrinsics::Type) -> Vec<&'ll Type> {
use intrinsics::Type::*;
match *t {
Void => vec![Type::void(cx)],
Vector(ref t, ref llvm_elem, length) => {
let t = llvm_elem.as_ref().unwrap_or(t);
let elem = one(ty_to_type(cx, t));
- vec![Type::vector(&elem, length as u64)]
+ vec![Type::vector(elem, length as u64)]
}
Aggregate(false, ref contents) => {
let elems = contents.iter()
// qux` to be converted into `foo, bar, baz, qux`, integer
// arguments to be truncated as needed and pointers to be
// cast.
- fn modify_as_needed<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
- t: &intrinsics::Type,
- arg: &OperandRef<'tcx>)
- -> Vec<ValueRef>
- {
+ fn modify_as_needed(
+ bx: &Builder<'a, 'll, 'tcx>,
+ t: &intrinsics::Type,
+ arg: &OperandRef<'ll, 'tcx>,
+ ) -> Vec<&'ll Value> {
match *t {
intrinsics::Type::Aggregate(true, ref contents) => {
// We found a tuple that needs squishing! So
}
intrinsics::Type::Vector(_, Some(ref llvm_elem), length) => {
let llvm_elem = one(ty_to_type(bx.cx, llvm_elem));
- vec![bx.bitcast(arg.immediate(), Type::vector(&llvm_elem, length as u64))]
+ vec![bx.bitcast(arg.immediate(), Type::vector(llvm_elem, length as u64))]
}
intrinsics::Type::Integer(_, width, llvm_width) if width != llvm_width => {
// the LLVM intrinsic uses a smaller integer
intrinsics::IntrinsicDef::Named(name) => {
let f = declare::declare_cfn(cx,
name,
- Type::func(&inputs, &outputs));
+ Type::func(&inputs, outputs));
bx.call(f, &llargs, None)
}
};
}
}
-fn copy_intrinsic<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
- allow_overlap: bool,
- volatile: bool,
- ty: Ty<'tcx>,
- dst: ValueRef,
- src: ValueRef,
- count: ValueRef)
- -> ValueRef {
+fn copy_intrinsic(
+ bx: &Builder<'a, 'll, 'tcx>,
+ allow_overlap: bool,
+ volatile: bool,
+ ty: Ty<'tcx>,
+ dst: &'ll Value,
+ src: &'ll Value,
+ count: &'ll Value,
+) -> &'ll Value {
let cx = bx.cx;
let (size, align) = cx.size_and_align_of(ty);
let size = C_usize(cx, size.bytes());
None)
}
-fn memset_intrinsic<'a, 'tcx>(
- bx: &Builder<'a, 'tcx>,
+fn memset_intrinsic(
+ bx: &Builder<'a, 'll, 'tcx>,
volatile: bool,
ty: Ty<'tcx>,
- dst: ValueRef,
- val: ValueRef,
- count: ValueRef
-) -> ValueRef {
+ dst: &'ll Value,
+ val: &'ll Value,
+ count: &'ll Value
+) -> &'ll Value {
let cx = bx.cx;
let (size, align) = cx.size_and_align_of(ty);
let size = C_usize(cx, size.bytes());
call_memset(bx, dst, val, bx.mul(size, count), align, volatile)
}
-fn try_intrinsic<'a, 'tcx>(
- bx: &Builder<'a, 'tcx>,
- cx: &CodegenCx,
- func: ValueRef,
- data: ValueRef,
- local_ptr: ValueRef,
- dest: ValueRef,
+fn try_intrinsic(
+ bx: &Builder<'a, 'll, 'tcx>,
+ cx: &CodegenCx<'ll, 'tcx>,
+ func: &'ll Value,
+ data: &'ll Value,
+ local_ptr: &'ll Value,
+ dest: &'ll Value,
) {
if bx.sess().no_landing_pads() {
bx.call(func, &[data], None);
// instructions are meant to work for all targets, as of the time of this
// writing, however, LLVM does not recommend the usage of these new instructions
// as the old ones are still more optimized.
-fn codegen_msvc_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
- cx: &CodegenCx,
- func: ValueRef,
- data: ValueRef,
- local_ptr: ValueRef,
- dest: ValueRef) {
+fn codegen_msvc_try(
+ bx: &Builder<'a, 'll, 'tcx>,
+ cx: &CodegenCx<'ll, 'tcx>,
+ func: &'ll Value,
+ data: &'ll Value,
+ local_ptr: &'ll Value,
+ dest: &'ll Value,
+) {
let llfn = get_rust_try_fn(cx, &mut |bx| {
let cx = bx.cx;
// function calling it, and that function may already have other personality
// functions in play. By calling a shim we're guaranteed that our shim will have
// the right personality function.
-fn codegen_gnu_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
- cx: &CodegenCx,
- func: ValueRef,
- data: ValueRef,
- local_ptr: ValueRef,
- dest: ValueRef) {
+fn codegen_gnu_try(
+ bx: &Builder<'a, 'll, 'tcx>,
+ cx: &CodegenCx<'ll, 'tcx>,
+ func: &'ll Value,
+ data: &'ll Value,
+ local_ptr: &'ll Value,
+ dest: &'ll Value,
+) {
let llfn = get_rust_try_fn(cx, &mut |bx| {
let cx = bx.cx;
// Helper function to give a Block to a closure to codegen a shim function.
// This is currently primarily used for the `try` intrinsic functions above.
-fn gen_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- name: &str,
- inputs: Vec<Ty<'tcx>>,
- output: Ty<'tcx>,
- codegen: &mut dyn for<'b> FnMut(Builder<'b, 'tcx>))
- -> ValueRef {
+fn gen_fn<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ name: &str,
+ inputs: Vec<Ty<'tcx>>,
+ output: Ty<'tcx>,
+ codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
+) -> &'ll Value {
let rust_fn_ty = cx.tcx.mk_fn_ptr(ty::Binder::bind(cx.tcx.mk_fn_sig(
inputs.into_iter(),
output,
// catch exceptions.
//
// This function is only generated once and is then cached.
-fn get_rust_try_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- codegen: &mut dyn for<'b> FnMut(Builder<'b, 'tcx>))
- -> ValueRef {
+fn get_rust_try_fn<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
+) -> &'ll Value {
if let Some(llfn) = cx.rust_try_fn.get() {
return llfn;
}
span_err!(a, b, E0511, "{}", c);
}
-fn generic_simd_intrinsic<'a, 'tcx>(
- bx: &Builder<'a, 'tcx>,
+fn generic_simd_intrinsic(
+ bx: &Builder<'a, 'll, 'tcx>,
name: &str,
callee_ty: Ty<'tcx>,
- args: &[OperandRef<'tcx>],
+ args: &[OperandRef<'ll, 'tcx>],
ret_ty: Ty<'tcx>,
- llret_ty: Type,
+ llret_ty: &'ll Type,
span: Span
-) -> Result<ValueRef, ()> {
+) -> Result<&'ll Value, ()> {
// macros for error handling:
macro_rules! emit_error {
($msg: tt) => {
found `{}` with length {}",
in_len, in_ty,
ret_ty, out_len);
- require!(llret_ty.element_type().kind() == llvm::Integer,
+ require!(llret_ty.element_type().kind() == TypeKind::Integer,
"expected return type with integer elements, found `{}` with non-integer `{}`",
ret_ty,
ret_ty.simd_type(tcx));
}
// truncate the mask to a vector of i1s
let i1 = Type::i1(bx.cx);
- let i1xn = Type::vector(&i1, m_len as u64);
+ let i1xn = Type::vector(i1, m_len as u64);
let m_i1s = bx.trunc(args[0].immediate(), i1xn);
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
}
- fn simd_simple_float_intrinsic<'a, 'tcx>(name: &str,
- in_elem: &::rustc::ty::TyS,
- in_ty: &::rustc::ty::TyS,
- in_len: usize,
- bx: &Builder<'a, 'tcx>,
- span: Span,
- args: &[OperandRef<'tcx>])
- -> Result<ValueRef, ()> {
+ fn simd_simple_float_intrinsic(
+ name: &str,
+ in_elem: &::rustc::ty::TyS,
+ in_ty: &::rustc::ty::TyS,
+ in_len: usize,
+ bx: &Builder<'a, 'll, 'tcx>,
+ span: Span,
+ args: &[OperandRef<'ll, 'tcx>],
+ ) -> Result<&'ll Value, ()> {
macro_rules! emit_error {
($msg: tt) => {
emit_error!($msg, )
}
}
- fn llvm_vector_ty(cx: &CodegenCx, elem_ty: ty::Ty, vec_len: usize,
- mut no_pointers: usize) -> Type {
+ fn llvm_vector_ty(cx: &CodegenCx<'ll, '_>, elem_ty: ty::Ty, vec_len: usize,
+ mut no_pointers: usize) -> &'ll Type {
// FIXME: use cx.layout_of(ty).llvm_type() ?
let mut elem_ty = match elem_ty.sty {
ty::TyInt(v) => Type::int_from_ty(cx, v),
elem_ty = elem_ty.ptr_to();
no_pointers -= 1;
}
- Type::vector(&elem_ty, vec_len as u64)
+ Type::vector(elem_ty, vec_len as u64)
}
// Truncate the mask vector to a vector of i1s:
let (mask, mask_ty) = {
let i1 = Type::i1(bx.cx);
- let i1xn = Type::vector(&i1, in_len as u64);
+ let i1xn = Type::vector(i1, in_len as u64);
(bx.trunc(args[2].immediate(), i1xn), i1xn)
};
llvm_elem_vec_str, llvm_pointer_vec_str);
let f = declare::declare_cfn(bx.cx, &llvm_intrinsic,
Type::func(&[llvm_pointer_vec_ty, alignment_ty, mask_ty,
- llvm_elem_vec_ty], &llvm_elem_vec_ty));
+ llvm_elem_vec_ty], llvm_elem_vec_ty));
llvm::SetUnnamedAddr(f, false);
let v = bx.call(f, &[args[1].immediate(), alignment, mask, args[0].immediate()],
None);
// Truncate the mask vector to a vector of i1s:
let (mask, mask_ty) = {
let i1 = Type::i1(bx.cx);
- let i1xn = Type::vector(&i1, in_len as u64);
+ let i1xn = Type::vector(i1, in_len as u64);
(bx.trunc(args[2].immediate(), i1xn), i1xn)
};
Type::func(&[llvm_elem_vec_ty,
llvm_pointer_vec_ty,
alignment_ty,
- mask_ty], &ret_t));
+ mask_ty], ret_t));
llvm::SetUnnamedAddr(f, false);
let v = bx.call(f, &[args[0].immediate(), args[1].immediate(), alignment, mask],
None);
// boolean reductions operate on vectors of i1s:
let i1 = Type::i1(bx.cx);
- let i1xn = Type::vector(&i1, in_len as u64);
+ let i1xn = Type::vector(i1, in_len as u64);
bx.trunc(args[0].immediate(), i1xn)
};
return match in_elem.sty {
fn int_type_width_signed(ty: Ty, cx: &CodegenCx) -> Option<(u64, bool)> {
match ty.sty {
ty::TyInt(t) => Some((match t {
- ast::IntTy::Isize => {
- match &cx.tcx.sess.target.target.target_pointer_width[..] {
- "16" => 16,
- "32" => 32,
- "64" => 64,
- tws => bug!("Unsupported target word size for isize: {}", tws),
- }
- },
+ ast::IntTy::Isize => cx.tcx.sess.target.isize_ty.bit_width().unwrap() as u64,
ast::IntTy::I8 => 8,
ast::IntTy::I16 => 16,
ast::IntTy::I32 => 32,
ast::IntTy::I128 => 128,
}, true)),
ty::TyUint(t) => Some((match t {
- ast::UintTy::Usize => {
- match &cx.tcx.sess.target.target.target_pointer_width[..] {
- "16" => 16,
- "32" => 32,
- "64" => 64,
- tws => bug!("Unsupported target word size for usize: {}", tws),
- }
- },
+ ast::UintTy::Usize => cx.tcx.sess.target.usize_ty.bit_width().unwrap() as u64,
ast::UintTy::U8 => 8,
ast::UintTy::U16 => 16,
ast::UintTy::U32 => 32,
// Returns the width of a float TypeVariant
// Returns None if the type is not a float
-fn float_type_width<'tcx>(sty: &ty::TypeVariants<'tcx>)
- -> Option<u64> {
- use rustc::ty::TyFloat;
+fn float_type_width<'tcx>(sty: &ty::TypeVariants<'tcx>) -> Option<u64> {
match *sty {
- TyFloat(t) => Some(match t {
- ast::FloatTy::F32 => 32,
- ast::FloatTy::F64 => 64,
- }),
+ ty::TyFloat(t) => Some(t.bit_width() as u64),
_ => None,
}
}
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(crate_visibility_modifier)]
#![feature(custom_attribute)]
+#![feature(extern_types)]
#![feature(fs_read_write)]
+#![feature(in_band_lifetimes)]
#![allow(unused_attributes)]
#![feature(libc)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
#![feature(optin_builtin_traits)]
+#![feature(concat_idents)]
+#![feature(link_args)]
+#![feature(static_nobundle)]
+use back::write::create_target_machine;
use rustc::dep_graph::WorkProduct;
use syntax_pos::symbol::Symbol;
#[macro_use] extern crate rustc_data_structures;
extern crate rustc_demangle;
extern crate rustc_incremental;
-extern crate rustc_llvm as llvm;
+extern crate rustc_llvm;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate rustc_codegen_utils;
use rustc::ty::{self, TyCtxt};
use rustc::util::time_graph;
use rustc::util::nodemap::{FxHashSet, FxHashMap};
+use rustc::util::profiling::ProfileCategory;
use rustc_mir::monomorphize;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
mod declare;
mod glue;
mod intrinsic;
+pub mod llvm;
mod llvm_util;
mod metadata;
mod meth;
// Run the linker on any artifacts that resulted from the LLVM run.
// This should produce either a finished executable or library.
+ sess.profiler(|p| p.start_activity(ProfileCategory::Linking));
time(sess, "linking", || {
back::link::link_binary(sess, &ongoing_codegen,
outputs, &ongoing_codegen.crate_name.as_str());
});
+ sess.profiler(|p| p.end_activity(ProfileCategory::Linking));
// Now that we won't touch anything in the incremental compilation directory
// any more, we can finalize it (which involves renaming it)
Codegened(ModuleLlvm),
}
-#[derive(Debug)]
struct ModuleLlvm {
- llcx: llvm::ContextRef,
- llmod: llvm::ModuleRef,
- tm: llvm::TargetMachineRef,
+ llcx: &'static mut llvm::Context,
+ llmod_raw: *const llvm::Module,
+ tm: &'static mut llvm::TargetMachine,
}
unsafe impl Send for ModuleLlvm { }
unsafe impl Sync for ModuleLlvm { }
+impl ModuleLlvm {
+ fn new(sess: &Session, mod_name: &str) -> Self {
+ unsafe {
+ let llcx = llvm::LLVMRustContextCreate(sess.fewer_names());
+ let llmod_raw = context::create_module(sess, llcx, mod_name) as *const _;
+
+ ModuleLlvm {
+ llmod_raw,
+ llcx,
+ tm: create_target_machine(sess, false),
+ }
+ }
+ }
+
+ fn llmod(&self) -> &llvm::Module {
+ unsafe {
+ &*self.llmod_raw
+ }
+ }
+}
+
impl Drop for ModuleLlvm {
fn drop(&mut self) {
unsafe {
- llvm::LLVMDisposeModule(self.llmod);
- llvm::LLVMContextDispose(self.llcx);
- llvm::LLVMRustDisposeTargetMachine(self.tm);
+ llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
+ llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
}
}
}
--- /dev/null
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A wrapper around LLVM's archive (.a) code
+
+use std::ffi::CString;
+use std::path::Path;
+use std::slice;
+use std::str;
+
+pub struct ArchiveRO {
+ pub raw: &'static mut super::Archive,
+}
+
+unsafe impl Send for ArchiveRO {}
+
+pub struct Iter<'a> {
+ raw: &'a mut super::ArchiveIterator<'a>,
+}
+
+pub struct Child<'a> {
+ pub raw: &'a mut super::ArchiveChild<'a>,
+}
+
+impl ArchiveRO {
+ /// Opens a static archive for read-only purposes. This is more optimized
+ /// than the `open` method because it uses LLVM's internal `Archive` class
+ /// rather than shelling out to `ar` for everything.
+ ///
+ /// If this archive is used with a mutable method, then an error will be
+ /// raised.
+ pub fn open(dst: &Path) -> Result<ArchiveRO, String> {
+ return unsafe {
+ let s = path2cstr(dst);
+ let ar = super::LLVMRustOpenArchive(s.as_ptr()).ok_or_else(|| {
+ super::last_error().unwrap_or("failed to open archive".to_string())
+ })?;
+ Ok(ArchiveRO { raw: ar })
+ };
+
+ #[cfg(unix)]
+ fn path2cstr(p: &Path) -> CString {
+ use std::os::unix::prelude::*;
+ use std::ffi::OsStr;
+ let p: &OsStr = p.as_ref();
+ CString::new(p.as_bytes()).unwrap()
+ }
+ #[cfg(windows)]
+ fn path2cstr(p: &Path) -> CString {
+ CString::new(p.to_str().unwrap()).unwrap()
+ }
+ }
+
+ pub fn iter(&self) -> Iter {
+ unsafe {
+ Iter {
+ raw: super::LLVMRustArchiveIteratorNew(self.raw),
+ }
+ }
+ }
+}
+
+impl Drop for ArchiveRO {
+ fn drop(&mut self) {
+ unsafe {
+ super::LLVMRustDestroyArchive(&mut *(self.raw as *mut _));
+ }
+ }
+}
+
+impl<'a> Iterator for Iter<'a> {
+ type Item = Result<Child<'a>, String>;
+
+ fn next(&mut self) -> Option<Result<Child<'a>, String>> {
+ unsafe {
+ match super::LLVMRustArchiveIteratorNext(self.raw) {
+ Some(raw) => Some(Ok(Child { raw })),
+ None => super::last_error().map(Err),
+ }
+ }
+ }
+}
+
+impl<'a> Drop for Iter<'a> {
+ fn drop(&mut self) {
+ unsafe {
+ super::LLVMRustArchiveIteratorFree(&mut *(self.raw as *mut _));
+ }
+ }
+}
+
+impl<'a> Child<'a> {
+ pub fn name(&self) -> Option<&'a str> {
+ unsafe {
+ let mut name_len = 0;
+ let name_ptr = super::LLVMRustArchiveChildName(self.raw, &mut name_len);
+ if name_ptr.is_null() {
+ None
+ } else {
+ let name = slice::from_raw_parts(name_ptr as *const u8, name_len as usize);
+ str::from_utf8(name).ok().map(|s| s.trim())
+ }
+ }
+ }
+
+ pub fn data(&self) -> &'a [u8] {
+ unsafe {
+ let mut data_len = 0;
+ let data_ptr = super::LLVMRustArchiveChildData(self.raw, &mut data_len);
+ if data_ptr.is_null() {
+ panic!("failed to read data from archive child");
+ }
+ slice::from_raw_parts(data_ptr as *const u8, data_len as usize)
+ }
+ }
+}
+
+impl<'a> Drop for Child<'a> {
+ fn drop(&mut self) {
+ unsafe {
+ super::LLVMRustArchiveChildFree(&mut *(self.raw as *mut _));
+ }
+ }
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! LLVM diagnostic reports.
+
+pub use self::OptimizationDiagnosticKind::*;
+pub use self::Diagnostic::*;
+
+use libc::c_uint;
+use value::Value;
+
+use super::{DiagnosticInfo, Twine};
+
+#[derive(Copy, Clone)]
+pub enum OptimizationDiagnosticKind {
+ OptimizationRemark,
+ OptimizationMissed,
+ OptimizationAnalysis,
+ OptimizationAnalysisFPCommute,
+ OptimizationAnalysisAliasing,
+ OptimizationFailure,
+ OptimizationRemarkOther,
+}
+
+impl OptimizationDiagnosticKind {
+ pub fn describe(self) -> &'static str {
+ match self {
+ OptimizationRemark | OptimizationRemarkOther => "remark",
+ OptimizationMissed => "missed",
+ OptimizationAnalysis => "analysis",
+ OptimizationAnalysisFPCommute => "floating-point",
+ OptimizationAnalysisAliasing => "aliasing",
+ OptimizationFailure => "failure",
+ }
+ }
+}
+
+pub struct OptimizationDiagnostic<'ll> {
+ pub kind: OptimizationDiagnosticKind,
+ pub pass_name: String,
+ pub function: &'ll Value,
+ pub line: c_uint,
+ pub column: c_uint,
+ pub filename: String,
+ pub message: String,
+}
+
+impl OptimizationDiagnostic<'ll> {
+ unsafe fn unpack(
+ kind: OptimizationDiagnosticKind,
+ di: &'ll DiagnosticInfo,
+ ) -> Self {
+ let mut function = None;
+ let mut line = 0;
+ let mut column = 0;
+
+ let mut message = None;
+ let mut filename = None;
+ let pass_name = super::build_string(|pass_name|
+ message = super::build_string(|message|
+ filename = super::build_string(|filename|
+ super::LLVMRustUnpackOptimizationDiagnostic(di,
+ pass_name,
+ &mut function,
+ &mut line,
+ &mut column,
+ filename,
+ message)
+ ).ok()
+ ).ok()
+ ).ok();
+
+ let mut filename = filename.unwrap_or(String::new());
+ if filename.is_empty() {
+ filename.push_str("<unknown file>");
+ }
+
+ OptimizationDiagnostic {
+ kind,
+ pass_name: pass_name.expect("got a non-UTF8 pass name from LLVM"),
+ function: function.unwrap(),
+ line,
+ column,
+ filename,
+ message: message.expect("got a non-UTF8 OptimizationDiagnostic message from LLVM")
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct InlineAsmDiagnostic<'ll> {
+ pub cookie: c_uint,
+ pub message: &'ll Twine,
+ pub instruction: &'ll Value,
+}
+
+impl InlineAsmDiagnostic<'ll> {
+ unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self {
+ let mut cookie = 0;
+ let mut message = None;
+ let mut instruction = None;
+
+ super::LLVMRustUnpackInlineAsmDiagnostic(
+ di,
+ &mut cookie,
+ &mut message,
+ &mut instruction,
+ );
+
+ InlineAsmDiagnostic {
+ cookie,
+ message: message.unwrap(),
+ instruction: instruction.unwrap(),
+ }
+ }
+}
+
+pub enum Diagnostic<'ll> {
+ Optimization(OptimizationDiagnostic<'ll>),
+ InlineAsm(InlineAsmDiagnostic<'ll>),
+ PGO(&'ll DiagnosticInfo),
+ Linker(&'ll DiagnosticInfo),
+
+ /// LLVM has other types that we do not wrap here.
+ UnknownDiagnostic(&'ll DiagnosticInfo),
+}
+
+impl Diagnostic<'ll> {
+ pub unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self {
+ use super::DiagnosticKind as Dk;
+ let kind = super::LLVMRustGetDiagInfoKind(di);
+
+ match kind {
+ Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpack(di)),
+
+ Dk::OptimizationRemark => {
+ Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di))
+ }
+ Dk::OptimizationRemarkOther => {
+ Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di))
+ }
+ Dk::OptimizationRemarkMissed => {
+ Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di))
+ }
+
+ Dk::OptimizationRemarkAnalysis => {
+ Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di))
+ }
+
+ Dk::OptimizationRemarkAnalysisFPCommute => {
+ Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisFPCommute, di))
+ }
+
+ Dk::OptimizationRemarkAnalysisAliasing => {
+ Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisAliasing, di))
+ }
+
+ Dk::OptimizationFailure => {
+ Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di))
+ }
+
+ Dk::PGOProfile => {
+ PGO(di)
+ }
+ Dk::Linker => {
+ Linker(di)
+ }
+
+ _ => UnknownDiagnostic(di),
+ }
+ }
+}
--- /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.
+
+// FIXME: Rename 'DIGlobalVariable' to 'DIGlobalVariableExpression'
+// once support for LLVM 3.9 is dropped.
+//
+// This method was changed in this LLVM patch:
+// https://reviews.llvm.org/D26769
+
+use super::debuginfo::{
+ DIBuilder, DIDescriptor, DIFile, DILexicalBlock, DISubprogram, DIType,
+ DIBasicType, DIDerivedType, DICompositeType, DIScope, DIVariable,
+ DIGlobalVariable, DIArray, DISubrange, DITemplateTypeParameter, DIEnumerator,
+ DINameSpace, DIFlags,
+};
+
+use libc::{c_uint, c_int, size_t, c_char};
+use libc::{c_ulonglong, c_void};
+
+use std::marker::PhantomData;
+
+use super::RustString;
+
+pub type Bool = c_uint;
+
+pub const True: Bool = 1 as Bool;
+pub const False: Bool = 0 as Bool;
+
+#[derive(Copy, Clone, PartialEq)]
+#[repr(C)]
+#[allow(dead_code)] // Variants constructed by C++.
+pub enum LLVMRustResult {
+ Success,
+ Failure,
+}
+// Consts for the LLVM CallConv type, pre-cast to usize.
+
+/// LLVM CallingConv::ID. Should we wrap this?
+#[derive(Copy, Clone, PartialEq, Debug)]
+#[repr(C)]
+pub enum CallConv {
+ CCallConv = 0,
+ FastCallConv = 8,
+ ColdCallConv = 9,
+ X86StdcallCallConv = 64,
+ X86FastcallCallConv = 65,
+ ArmAapcsCallConv = 67,
+ Msp430Intr = 69,
+ X86_ThisCall = 70,
+ PtxKernel = 71,
+ X86_64_SysV = 78,
+ X86_64_Win64 = 79,
+ X86_VectorCall = 80,
+ X86_Intr = 83,
+ AmdGpuKernel = 91,
+}
+
+/// LLVMRustLinkage
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[repr(C)]
+pub enum Linkage {
+ ExternalLinkage = 0,
+ AvailableExternallyLinkage = 1,
+ LinkOnceAnyLinkage = 2,
+ LinkOnceODRLinkage = 3,
+ WeakAnyLinkage = 4,
+ WeakODRLinkage = 5,
+ AppendingLinkage = 6,
+ InternalLinkage = 7,
+ PrivateLinkage = 8,
+ ExternalWeakLinkage = 9,
+ CommonLinkage = 10,
+}
+
+// LLVMRustVisibility
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[repr(C)]
+pub enum Visibility {
+ Default = 0,
+ Hidden = 1,
+ Protected = 2,
+}
+
+/// LLVMDLLStorageClass
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum DLLStorageClass {
+ #[allow(dead_code)]
+ Default = 0,
+ DllImport = 1, // Function to be imported from DLL.
+ #[allow(dead_code)]
+ DllExport = 2, // Function to be accessible from DLL.
+}
+
+/// Matches LLVMRustAttribute in rustllvm.h
+/// Semantically a subset of the C++ enum llvm::Attribute::AttrKind,
+/// though it is not ABI compatible (since it's a C++ enum)
+#[repr(C)]
+#[derive(Copy, Clone, Debug)]
+pub enum Attribute {
+ AlwaysInline = 0,
+ ByVal = 1,
+ Cold = 2,
+ InlineHint = 3,
+ MinSize = 4,
+ Naked = 5,
+ NoAlias = 6,
+ NoCapture = 7,
+ NoInline = 8,
+ NonNull = 9,
+ NoRedZone = 10,
+ NoReturn = 11,
+ NoUnwind = 12,
+ OptimizeForSize = 13,
+ ReadOnly = 14,
+ SExt = 15,
+ StructRet = 16,
+ UWTable = 17,
+ ZExt = 18,
+ InReg = 19,
+ SanitizeThread = 20,
+ SanitizeAddress = 21,
+ SanitizeMemory = 22,
+}
+
+/// LLVMIntPredicate
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum IntPredicate {
+ IntEQ = 32,
+ IntNE = 33,
+ IntUGT = 34,
+ IntUGE = 35,
+ IntULT = 36,
+ IntULE = 37,
+ IntSGT = 38,
+ IntSGE = 39,
+ IntSLT = 40,
+ IntSLE = 41,
+}
+
+/// LLVMRealPredicate
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum RealPredicate {
+ RealPredicateFalse = 0,
+ RealOEQ = 1,
+ RealOGT = 2,
+ RealOGE = 3,
+ RealOLT = 4,
+ RealOLE = 5,
+ RealONE = 6,
+ RealORD = 7,
+ RealUNO = 8,
+ RealUEQ = 9,
+ RealUGT = 10,
+ RealUGE = 11,
+ RealULT = 12,
+ RealULE = 13,
+ RealUNE = 14,
+ RealPredicateTrue = 15,
+}
+
+/// LLVMTypeKind
+#[derive(Copy, Clone, PartialEq, Debug)]
+#[repr(C)]
+pub enum TypeKind {
+ Void = 0,
+ Half = 1,
+ Float = 2,
+ Double = 3,
+ X86_FP80 = 4,
+ FP128 = 5,
+ PPC_FP128 = 6,
+ Label = 7,
+ Integer = 8,
+ Function = 9,
+ Struct = 10,
+ Array = 11,
+ Pointer = 12,
+ Vector = 13,
+ Metadata = 14,
+ X86_MMX = 15,
+ Token = 16,
+}
+
+/// LLVMAtomicRmwBinOp
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum AtomicRmwBinOp {
+ AtomicXchg = 0,
+ AtomicAdd = 1,
+ AtomicSub = 2,
+ AtomicAnd = 3,
+ AtomicNand = 4,
+ AtomicOr = 5,
+ AtomicXor = 6,
+ AtomicMax = 7,
+ AtomicMin = 8,
+ AtomicUMax = 9,
+ AtomicUMin = 10,
+}
+
+/// LLVMAtomicOrdering
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum AtomicOrdering {
+ #[allow(dead_code)]
+ NotAtomic = 0,
+ Unordered = 1,
+ Monotonic = 2,
+ // Consume = 3, // Not specified yet.
+ Acquire = 4,
+ Release = 5,
+ AcquireRelease = 6,
+ SequentiallyConsistent = 7,
+}
+
+/// LLVMRustSynchronizationScope
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum SynchronizationScope {
+ // FIXME: figure out if this variant is needed at all.
+ #[allow(dead_code)]
+ Other,
+ SingleThread,
+ CrossThread,
+}
+
+/// LLVMRustFileType
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum FileType {
+ // FIXME: figure out if this variant is needed at all.
+ #[allow(dead_code)]
+ Other,
+ AssemblyFile,
+ ObjectFile,
+}
+
+/// LLVMMetadataType
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum MetadataType {
+ MD_dbg = 0,
+ MD_tbaa = 1,
+ MD_prof = 2,
+ MD_fpmath = 3,
+ MD_range = 4,
+ MD_tbaa_struct = 5,
+ MD_invariant_load = 6,
+ MD_alias_scope = 7,
+ MD_noalias = 8,
+ MD_nontemporal = 9,
+ MD_mem_parallel_loop_access = 10,
+ MD_nonnull = 11,
+}
+
+/// LLVMRustAsmDialect
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum AsmDialect {
+ // FIXME: figure out if this variant is needed at all.
+ #[allow(dead_code)]
+ Other,
+ Att,
+ Intel,
+}
+
+/// LLVMRustCodeGenOptLevel
+#[derive(Copy, Clone, PartialEq)]
+#[repr(C)]
+pub enum CodeGenOptLevel {
+ // FIXME: figure out if this variant is needed at all.
+ #[allow(dead_code)]
+ Other,
+ None,
+ Less,
+ Default,
+ Aggressive,
+}
+
+/// LLVMRelocMode
+#[derive(Copy, Clone, PartialEq)]
+#[repr(C)]
+pub enum RelocMode {
+ Default,
+ Static,
+ PIC,
+ DynamicNoPic,
+ ROPI,
+ RWPI,
+ ROPI_RWPI,
+}
+
+/// LLVMRustCodeModel
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum CodeModel {
+ // FIXME: figure out if this variant is needed at all.
+ #[allow(dead_code)]
+ Other,
+ Small,
+ Kernel,
+ Medium,
+ Large,
+ None,
+}
+
+/// LLVMRustDiagnosticKind
+#[derive(Copy, Clone)]
+#[repr(C)]
+#[allow(dead_code)] // Variants constructed by C++.
+pub enum DiagnosticKind {
+ Other,
+ InlineAsm,
+ StackSize,
+ DebugMetadataVersion,
+ SampleProfile,
+ OptimizationRemark,
+ OptimizationRemarkMissed,
+ OptimizationRemarkAnalysis,
+ OptimizationRemarkAnalysisFPCommute,
+ OptimizationRemarkAnalysisAliasing,
+ OptimizationRemarkOther,
+ OptimizationFailure,
+ PGOProfile,
+ Linker,
+}
+
+/// LLVMRustArchiveKind
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum ArchiveKind {
+ // FIXME: figure out if this variant is needed at all.
+ #[allow(dead_code)]
+ Other,
+ K_GNU,
+ K_BSD,
+ K_COFF,
+}
+
+/// LLVMRustPassKind
+#[derive(Copy, Clone, PartialEq, Debug)]
+#[repr(C)]
+#[allow(dead_code)] // Variants constructed by C++.
+pub enum PassKind {
+ Other,
+ Function,
+ Module,
+}
+
+/// LLVMRustThinLTOData
+extern { pub type ThinLTOData; }
+
+/// LLVMRustThinLTOBuffer
+extern { pub type ThinLTOBuffer; }
+
+/// LLVMRustThinLTOModule
+#[repr(C)]
+pub struct ThinLTOModule {
+ pub identifier: *const c_char,
+ pub data: *const u8,
+ pub len: usize,
+}
+
+/// LLVMThreadLocalMode
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum ThreadLocalMode {
+ NotThreadLocal,
+ GeneralDynamic,
+ LocalDynamic,
+ InitialExec,
+ LocalExec
+}
+
+extern { type Opaque; }
+#[repr(C)]
+struct InvariantOpaque<'a> {
+ _marker: PhantomData<&'a mut &'a ()>,
+ _opaque: Opaque,
+}
+
+// Opaque pointer types
+extern { pub type Module; }
+extern { pub type Context; }
+extern { pub type Type; }
+extern { pub type Value; }
+extern { pub type Metadata; }
+extern { pub type BasicBlock; }
+#[repr(C)]
+pub struct Builder<'a>(InvariantOpaque<'a>);
+extern { pub type MemoryBuffer; }
+#[repr(C)]
+pub struct PassManager<'a>(InvariantOpaque<'a>);
+extern { pub type PassManagerBuilder; }
+extern { pub type ObjectFile; }
+#[repr(C)]
+pub struct SectionIterator<'a>(InvariantOpaque<'a>);
+extern { pub type Pass; }
+extern { pub type TargetMachine; }
+extern { pub type Archive; }
+#[repr(C)]
+pub struct ArchiveIterator<'a>(InvariantOpaque<'a>);
+#[repr(C)]
+pub struct ArchiveChild<'a>(InvariantOpaque<'a>);
+extern { pub type Twine; }
+extern { pub type DiagnosticInfo; }
+extern { pub type SMDiagnostic; }
+#[repr(C)]
+pub struct RustArchiveMember<'a>(InvariantOpaque<'a>);
+#[repr(C)]
+pub struct OperandBundleDef<'a>(InvariantOpaque<'a>);
+#[repr(C)]
+pub struct Linker<'a>(InvariantOpaque<'a>);
+
+pub type DiagnosticHandler = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
+pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
+
+
+pub mod debuginfo {
+ use super::{InvariantOpaque, Metadata};
+
+ #[repr(C)]
+ pub struct DIBuilder<'a>(InvariantOpaque<'a>);
+
+ pub type DIDescriptor = Metadata;
+ pub type DIScope = DIDescriptor;
+ pub type DIFile = DIScope;
+ pub type DILexicalBlock = DIScope;
+ pub type DISubprogram = DIScope;
+ pub type DINameSpace = DIScope;
+ pub type DIType = DIDescriptor;
+ pub type DIBasicType = DIType;
+ pub type DIDerivedType = DIType;
+ pub type DICompositeType = DIDerivedType;
+ pub type DIVariable = DIDescriptor;
+ pub type DIGlobalVariable = DIDescriptor;
+ pub type DIArray = DIDescriptor;
+ pub type DISubrange = DIDescriptor;
+ pub type DIEnumerator = DIDescriptor;
+ pub type DITemplateTypeParameter = DIDescriptor;
+
+ // These values **must** match with LLVMRustDIFlags!!
+ bitflags! {
+ #[repr(C)]
+ #[derive(Default)]
+ pub struct DIFlags: ::libc::uint32_t {
+ const FlagZero = 0;
+ const FlagPrivate = 1;
+ const FlagProtected = 2;
+ const FlagPublic = 3;
+ const FlagFwdDecl = (1 << 2);
+ const FlagAppleBlock = (1 << 3);
+ const FlagBlockByrefStruct = (1 << 4);
+ const FlagVirtual = (1 << 5);
+ const FlagArtificial = (1 << 6);
+ const FlagExplicit = (1 << 7);
+ const FlagPrototyped = (1 << 8);
+ const FlagObjcClassComplete = (1 << 9);
+ const FlagObjectPointer = (1 << 10);
+ const FlagVector = (1 << 11);
+ const FlagStaticMember = (1 << 12);
+ const FlagLValueReference = (1 << 13);
+ const FlagRValueReference = (1 << 14);
+ const FlagExternalTypeRef = (1 << 15);
+ const FlagIntroducedVirtual = (1 << 18);
+ const FlagBitField = (1 << 19);
+ const FlagNoReturn = (1 << 20);
+ const FlagMainSubprogram = (1 << 21);
+ }
+ }
+}
+
+extern { pub type ModuleBuffer; }
+
+extern "C" {
+ // Create and destroy contexts.
+ pub fn LLVMRustContextCreate(shouldDiscardNames: bool) -> &'static mut Context;
+ pub fn LLVMContextDispose(C: &'static mut Context);
+ pub fn LLVMGetMDKindIDInContext(C: &Context, Name: *const c_char, SLen: c_uint) -> c_uint;
+
+ // Create modules.
+ pub fn LLVMModuleCreateWithNameInContext(ModuleID: *const c_char, C: &Context) -> &Module;
+ pub fn LLVMGetModuleContext(M: &Module) -> &Context;
+ pub fn LLVMCloneModule(M: &Module) -> &Module;
+
+ /// Data layout. See Module::getDataLayout.
+ pub fn LLVMGetDataLayout(M: &Module) -> *const c_char;
+ pub fn LLVMSetDataLayout(M: &Module, Triple: *const c_char);
+
+ /// See Module::setModuleInlineAsm.
+ pub fn LLVMSetModuleInlineAsm(M: &Module, Asm: *const c_char);
+ pub fn LLVMRustAppendModuleInlineAsm(M: &Module, Asm: *const c_char);
+
+ /// See llvm::LLVMTypeKind::getTypeID.
+ pub fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind;
+
+ // Operations on integer types
+ pub fn LLVMInt1TypeInContext(C: &Context) -> &Type;
+ pub fn LLVMInt8TypeInContext(C: &Context) -> &Type;
+ pub fn LLVMInt16TypeInContext(C: &Context) -> &Type;
+ pub fn LLVMInt32TypeInContext(C: &Context) -> &Type;
+ pub fn LLVMInt64TypeInContext(C: &Context) -> &Type;
+ pub fn LLVMIntTypeInContext(C: &Context, NumBits: c_uint) -> &Type;
+
+ pub fn LLVMGetIntTypeWidth(IntegerTy: &Type) -> c_uint;
+
+ // Operations on real types
+ pub fn LLVMFloatTypeInContext(C: &Context) -> &Type;
+ pub fn LLVMDoubleTypeInContext(C: &Context) -> &Type;
+
+ // Operations on function types
+ pub fn LLVMFunctionType(ReturnType: &'a Type,
+ ParamTypes: *const &'a Type,
+ ParamCount: c_uint,
+ IsVarArg: Bool)
+ -> &'a Type;
+ pub fn LLVMCountParamTypes(FunctionTy: &Type) -> c_uint;
+ pub fn LLVMGetParamTypes(FunctionTy: &'a Type, Dest: *mut &'a Type);
+
+ // Operations on struct types
+ pub fn LLVMStructTypeInContext(C: &'a Context,
+ ElementTypes: *const &'a Type,
+ ElementCount: c_uint,
+ Packed: Bool)
+ -> &'a Type;
+
+ // Operations on array, pointer, and vector types (sequence types)
+ pub fn LLVMRustArrayType(ElementType: &Type, ElementCount: u64) -> &Type;
+ pub fn LLVMPointerType(ElementType: &Type, AddressSpace: c_uint) -> &Type;
+ pub fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type;
+
+ pub fn LLVMGetElementType(Ty: &Type) -> &Type;
+ pub fn LLVMGetVectorSize(VectorTy: &Type) -> c_uint;
+
+ // Operations on other types
+ pub fn LLVMVoidTypeInContext(C: &Context) -> &Type;
+ pub fn LLVMX86MMXTypeInContext(C: &Context) -> &Type;
+ pub fn LLVMRustMetadataTypeInContext(C: &Context) -> &Type;
+
+ // Operations on all values
+ pub fn LLVMTypeOf(Val: &Value) -> &Type;
+ pub fn LLVMGetValueName(Val: &Value) -> *const c_char;
+ pub fn LLVMSetValueName(Val: &Value, Name: *const c_char);
+ pub fn LLVMReplaceAllUsesWith(OldVal: &'a Value, NewVal: &'a Value);
+ pub fn LLVMSetMetadata(Val: &'a Value, KindID: c_uint, Node: &'a Value);
+
+ // Operations on constants of any type
+ pub fn LLVMConstNull(Ty: &Type) -> &Value;
+ pub fn LLVMGetUndef(Ty: &Type) -> &Value;
+
+ // Operations on metadata
+ pub fn LLVMMDStringInContext(C: &Context, Str: *const c_char, SLen: c_uint) -> &Value;
+ pub fn LLVMMDNodeInContext(C: &'a Context, Vals: *const &'a Value, Count: c_uint) -> &'a Value;
+ pub fn LLVMAddNamedMetadataOperand(M: &'a Module, Name: *const c_char, Val: &'a Value);
+
+ // Operations on scalar constants
+ pub fn LLVMConstInt(IntTy: &Type, N: c_ulonglong, SignExtend: Bool) -> &Value;
+ pub fn LLVMConstIntOfArbitraryPrecision(IntTy: &Type, Wn: c_uint, Ws: *const u64) -> &Value;
+ pub fn LLVMConstIntGetZExtValue(ConstantVal: &Value) -> c_ulonglong;
+ pub fn LLVMRustConstInt128Get(ConstantVal: &Value, SExt: bool,
+ high: &mut u64, low: &mut u64) -> bool;
+ pub fn LLVMConstRealGetDouble (ConstantVal: &Value, losesInfo: &mut Bool) -> f64;
+
+
+ // Operations on composite constants
+ pub fn LLVMConstStringInContext(C: &Context,
+ Str: *const c_char,
+ Length: c_uint,
+ DontNullTerminate: Bool)
+ -> &Value;
+ pub fn LLVMConstStructInContext(C: &'a Context,
+ ConstantVals: *const &'a Value,
+ Count: c_uint,
+ Packed: Bool)
+ -> &'a Value;
+
+ pub fn LLVMConstArray(ElementTy: &'a Type,
+ ConstantVals: *const &'a Value,
+ Length: c_uint)
+ -> &'a Value;
+ pub fn LLVMConstVector(ScalarConstantVals: *const &Value, Size: c_uint) -> &Value;
+
+ // Constant expressions
+ pub fn LLVMConstInBoundsGEP(
+ ConstantVal: &'a Value,
+ ConstantIndices: *const &'a Value,
+ NumIndices: c_uint,
+ ) -> &'a Value;
+ pub fn LLVMConstZExt(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+ pub fn LLVMConstPtrToInt(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+ pub fn LLVMConstIntToPtr(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+ pub fn LLVMConstBitCast(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+ pub fn LLVMConstPointerCast(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value;
+ pub fn LLVMConstExtractValue(AggConstant: &Value,
+ IdxList: *const c_uint,
+ NumIdx: c_uint)
+ -> &Value;
+
+ // Operations on global variables, functions, and aliases (globals)
+ pub fn LLVMIsDeclaration(Global: &Value) -> Bool;
+ pub fn LLVMRustGetLinkage(Global: &Value) -> Linkage;
+ pub fn LLVMRustSetLinkage(Global: &Value, RustLinkage: Linkage);
+ pub fn LLVMSetSection(Global: &Value, Section: *const c_char);
+ pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility;
+ pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility);
+ pub fn LLVMGetAlignment(Global: &Value) -> c_uint;
+ pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint);
+ pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass);
+
+
+ // Operations on global variables
+ pub fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>;
+ pub fn LLVMAddGlobal(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value;
+ pub fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>;
+ pub fn LLVMRustGetOrInsertGlobal(M: &'a Module, Name: *const c_char, T: &'a Type) -> &'a Value;
+ pub fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>;
+ pub fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>;
+ pub fn LLVMDeleteGlobal(GlobalVar: &Value);
+ pub fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
+ pub fn LLVMSetInitializer(GlobalVar: &'a Value, ConstantVal: &'a Value);
+ pub fn LLVMSetThreadLocal(GlobalVar: &Value, IsThreadLocal: Bool);
+ pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
+ pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
+ pub fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
+ pub fn LLVMRustGetNamedValue(M: &Module, Name: *const c_char) -> Option<&Value>;
+ pub fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
+
+ // Operations on functions
+ pub fn LLVMRustGetOrInsertFunction(M: &'a Module,
+ Name: *const c_char,
+ FunctionTy: &'a Type)
+ -> &'a Value;
+ pub fn LLVMSetFunctionCallConv(Fn: &Value, CC: c_uint);
+ pub fn LLVMRustAddAlignmentAttr(Fn: &Value, index: c_uint, bytes: u32);
+ pub fn LLVMRustAddDereferenceableAttr(Fn: &Value, index: c_uint, bytes: u64);
+ pub fn LLVMRustAddDereferenceableOrNullAttr(Fn: &Value, index: c_uint, bytes: u64);
+ pub fn LLVMRustAddFunctionAttribute(Fn: &Value, index: c_uint, attr: Attribute);
+ pub fn LLVMRustAddFunctionAttrStringValue(Fn: &Value,
+ index: c_uint,
+ Name: *const c_char,
+ Value: *const c_char);
+ pub fn LLVMRustRemoveFunctionAttributes(Fn: &Value, index: c_uint, attr: Attribute);
+
+ // Operations on parameters
+ pub fn LLVMCountParams(Fn: &Value) -> c_uint;
+ pub fn LLVMGetParam(Fn: &Value, Index: c_uint) -> &Value;
+
+ // Operations on basic blocks
+ pub fn LLVMGetBasicBlockParent(BB: &BasicBlock) -> &Value;
+ pub fn LLVMAppendBasicBlockInContext(C: &'a Context,
+ Fn: &'a Value,
+ Name: *const c_char)
+ -> &'a BasicBlock;
+ pub fn LLVMDeleteBasicBlock(BB: &BasicBlock);
+
+ // Operations on instructions
+ pub fn LLVMGetFirstBasicBlock(Fn: &Value) -> &BasicBlock;
+
+ // Operations on call sites
+ pub fn LLVMSetInstructionCallConv(Instr: &Value, CC: c_uint);
+ pub fn LLVMRustAddCallSiteAttribute(Instr: &Value, index: c_uint, attr: Attribute);
+ pub fn LLVMRustAddAlignmentCallSiteAttr(Instr: &Value, index: c_uint, bytes: u32);
+ pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: &Value, index: c_uint, bytes: u64);
+ pub fn LLVMRustAddDereferenceableOrNullCallSiteAttr(Instr: &Value,
+ index: c_uint,
+ bytes: u64);
+
+ // Operations on load/store instructions (only)
+ pub fn LLVMSetVolatile(MemoryAccessInst: &Value, volatile: Bool);
+
+ // Operations on phi nodes
+ pub fn LLVMAddIncoming(PhiNode: &'a Value,
+ IncomingValues: *const &'a Value,
+ IncomingBlocks: *const &'a BasicBlock,
+ Count: c_uint);
+
+ // Instruction builders
+ pub fn LLVMCreateBuilderInContext(C: &'a Context) -> &'a mut Builder<'a>;
+ pub fn LLVMPositionBuilderAtEnd(Builder: &Builder<'a>, Block: &'a BasicBlock);
+ pub fn LLVMGetInsertBlock(Builder: &Builder<'a>) -> &'a BasicBlock;
+ pub fn LLVMDisposeBuilder(Builder: &'a mut Builder<'a>);
+
+ // Metadata
+ pub fn LLVMSetCurrentDebugLocation(Builder: &Builder<'a>, L: Option<&'a Value>);
+ pub fn LLVMGetCurrentDebugLocation(Builder: &Builder<'a>) -> &'a Value;
+ pub fn LLVMSetInstDebugLocation(Builder: &Builder<'a>, Inst: &'a Value);
+
+ // Terminators
+ pub fn LLVMBuildRetVoid(B: &Builder<'a>) -> &'a Value;
+ pub fn LLVMBuildRet(B: &Builder<'a>, V: &'a Value) -> &'a Value;
+ pub fn LLVMBuildBr(B: &Builder<'a>, Dest: &'a BasicBlock) -> &'a Value;
+ pub fn LLVMBuildCondBr(B: &Builder<'a>,
+ If: &'a Value,
+ Then: &'a BasicBlock,
+ Else: &'a BasicBlock)
+ -> &'a Value;
+ pub fn LLVMBuildSwitch(B: &Builder<'a>,
+ V: &'a Value,
+ Else: &'a BasicBlock,
+ NumCases: c_uint)
+ -> &'a Value;
+ pub fn LLVMRustBuildInvoke(B: &Builder<'a>,
+ Fn: &'a Value,
+ Args: *const &'a Value,
+ NumArgs: c_uint,
+ Then: &'a BasicBlock,
+ Catch: &'a BasicBlock,
+ Bundle: Option<&OperandBundleDef<'a>>,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildLandingPad(B: &Builder<'a>,
+ Ty: &'a Type,
+ PersFn: &'a Value,
+ NumClauses: c_uint,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildResume(B: &Builder<'a>, Exn: &'a Value) -> &'a Value;
+ pub fn LLVMBuildUnreachable(B: &Builder<'a>) -> &'a Value;
+
+ pub fn LLVMRustBuildCleanupPad(B: &Builder<'a>,
+ ParentPad: Option<&'a Value>,
+ ArgCnt: c_uint,
+ Args: *const &'a Value,
+ Name: *const c_char)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildCleanupRet(B: &Builder<'a>,
+ CleanupPad: &'a Value,
+ UnwindBB: Option<&'a BasicBlock>)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildCatchPad(B: &Builder<'a>,
+ ParentPad: &'a Value,
+ ArgCnt: c_uint,
+ Args: *const &'a Value,
+ Name: *const c_char)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildCatchRet(
+ B: &Builder<'a>,
+ Pad: &'a Value,
+ BB: &'a BasicBlock,
+ ) -> Option<&'a Value>;
+ pub fn LLVMRustBuildCatchSwitch(Builder: &Builder<'a>,
+ ParentPad: Option<&'a Value>,
+ BB: Option<&'a BasicBlock>,
+ NumHandlers: c_uint,
+ Name: *const c_char)
+ -> Option<&'a Value>;
+ pub fn LLVMRustAddHandler(CatchSwitch: &'a Value, Handler: &'a BasicBlock);
+ pub fn LLVMSetPersonalityFn(Func: &'a Value, Pers: &'a Value);
+
+ // Add a case to the switch instruction
+ pub fn LLVMAddCase(Switch: &'a Value, OnVal: &'a Value, Dest: &'a BasicBlock);
+
+ // Add a clause to the landing pad instruction
+ pub fn LLVMAddClause(LandingPad: &'a Value, ClauseVal: &'a Value);
+
+ // Set the cleanup on a landing pad instruction
+ pub fn LLVMSetCleanup(LandingPad: &Value, Val: Bool);
+
+ // Arithmetic
+ pub fn LLVMBuildAdd(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildFAdd(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildSub(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildFSub(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildMul(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildFMul(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildUDiv(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildExactUDiv(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildSDiv(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildExactSDiv(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildFDiv(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildURem(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildSRem(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildFRem(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildShl(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildLShr(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildAShr(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildAnd(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildOr(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildXor(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildNeg(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value;
+ pub fn LLVMBuildFNeg(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value;
+ pub fn LLVMBuildNot(B: &Builder<'a>, V: &'a Value, Name: *const c_char) -> &'a Value;
+ pub fn LLVMRustSetHasUnsafeAlgebra(Instr: &Value);
+
+ // Memory
+ pub fn LLVMBuildAlloca(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value;
+ pub fn LLVMBuildLoad(B: &Builder<'a>, PointerVal: &'a Value, Name: *const c_char) -> &'a Value;
+
+ pub fn LLVMBuildStore(B: &Builder<'a>, Val: &'a Value, Ptr: &'a Value) -> &'a Value;
+
+ pub fn LLVMBuildGEP(B: &Builder<'a>,
+ Pointer: &'a Value,
+ Indices: *const &'a Value,
+ NumIndices: c_uint,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildInBoundsGEP(B: &Builder<'a>,
+ Pointer: &'a Value,
+ Indices: *const &'a Value,
+ NumIndices: c_uint,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildStructGEP(B: &Builder<'a>,
+ Pointer: &'a Value,
+ Idx: c_uint,
+ Name: *const c_char)
+ -> &'a Value;
+
+ // Casts
+ pub fn LLVMBuildTrunc(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildZExt(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildSExt(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildFPToUI(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildFPToSI(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildUIToFP(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildSIToFP(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildFPTrunc(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildFPExt(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildPtrToInt(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildIntToPtr(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildBitCast(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildPointerCast(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMRustBuildIntCast(B: &Builder<'a>,
+ Val: &'a Value,
+ DestTy: &'a Type,
+ IsSized: bool)
+ -> &'a Value;
+
+ // Comparisons
+ pub fn LLVMBuildICmp(B: &Builder<'a>,
+ Op: c_uint,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildFCmp(B: &Builder<'a>,
+ Op: c_uint,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+
+ // Miscellaneous instructions
+ pub fn LLVMBuildPhi(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value;
+ pub fn LLVMRustBuildCall(B: &Builder<'a>,
+ Fn: &'a Value,
+ Args: *const &'a Value,
+ NumArgs: c_uint,
+ Bundle: Option<&OperandBundleDef<'a>>,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildSelect(B: &Builder<'a>,
+ If: &'a Value,
+ Then: &'a Value,
+ Else: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildVAArg(B: &Builder<'a>,
+ list: &'a Value,
+ Ty: &'a Type,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildExtractElement(B: &Builder<'a>,
+ VecVal: &'a Value,
+ Index: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildInsertElement(B: &Builder<'a>,
+ VecVal: &'a Value,
+ EltVal: &'a Value,
+ Index: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildShuffleVector(B: &Builder<'a>,
+ V1: &'a Value,
+ V2: &'a Value,
+ Mask: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildExtractValue(B: &Builder<'a>,
+ AggVal: &'a Value,
+ Index: c_uint,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildInsertValue(B: &Builder<'a>,
+ AggVal: &'a Value,
+ EltVal: &'a Value,
+ Index: c_uint,
+ Name: *const c_char)
+ -> &'a Value;
+
+ pub fn LLVMRustBuildVectorReduceFAdd(B: &Builder<'a>,
+ Acc: &'a Value,
+ Src: &'a Value)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildVectorReduceFMul(B: &Builder<'a>,
+ Acc: &'a Value,
+ Src: &'a Value)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildVectorReduceAdd(B: &Builder<'a>,
+ Src: &'a Value)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildVectorReduceMul(B: &Builder<'a>,
+ Src: &'a Value)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildVectorReduceAnd(B: &Builder<'a>,
+ Src: &'a Value)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildVectorReduceOr(B: &Builder<'a>,
+ Src: &'a Value)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildVectorReduceXor(B: &Builder<'a>,
+ Src: &'a Value)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildVectorReduceMin(B: &Builder<'a>,
+ Src: &'a Value,
+ IsSigned: bool)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildVectorReduceMax(B: &Builder<'a>,
+ Src: &'a Value,
+ IsSigned: bool)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildVectorReduceFMin(B: &Builder<'a>,
+ Src: &'a Value,
+ IsNaN: bool)
+ -> Option<&'a Value>;
+ pub fn LLVMRustBuildVectorReduceFMax(B: &Builder<'a>,
+ Src: &'a Value,
+ IsNaN: bool)
+ -> Option<&'a Value>;
+
+ pub fn LLVMRustBuildMinNum(
+ B: &Builder<'a>,
+ LHS: &'a Value,
+ LHS: &'a Value,
+ ) -> Option<&'a Value>;
+ pub fn LLVMRustBuildMaxNum(
+ B: &Builder<'a>,
+ LHS: &'a Value,
+ LHS: &'a Value,
+ ) -> Option<&'a Value>;
+
+ // Atomic Operations
+ pub fn LLVMRustBuildAtomicLoad(B: &Builder<'a>,
+ PointerVal: &'a Value,
+ Name: *const c_char,
+ Order: AtomicOrdering)
+ -> &'a Value;
+
+ pub fn LLVMRustBuildAtomicStore(B: &Builder<'a>,
+ Val: &'a Value,
+ Ptr: &'a Value,
+ Order: AtomicOrdering)
+ -> &'a Value;
+
+ pub fn LLVMRustBuildAtomicCmpXchg(B: &Builder<'a>,
+ LHS: &'a Value,
+ CMP: &'a Value,
+ RHS: &'a Value,
+ Order: AtomicOrdering,
+ FailureOrder: AtomicOrdering,
+ Weak: Bool)
+ -> &'a Value;
+
+ pub fn LLVMBuildAtomicRMW(B: &Builder<'a>,
+ Op: AtomicRmwBinOp,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Order: AtomicOrdering,
+ SingleThreaded: Bool)
+ -> &'a Value;
+
+ pub fn LLVMRustBuildAtomicFence(B: &Builder,
+ Order: AtomicOrdering,
+ Scope: SynchronizationScope);
+
+ /// Writes a module to the specified path. Returns 0 on success.
+ pub fn LLVMWriteBitcodeToFile(M: &Module, Path: *const c_char) -> c_int;
+
+ /// Creates a pass manager.
+ pub fn LLVMCreatePassManager() -> &'a mut PassManager<'a>;
+
+ /// Creates a function-by-function pass manager
+ pub fn LLVMCreateFunctionPassManagerForModule(M: &'a Module) -> &'a mut PassManager<'a>;
+
+ /// Disposes a pass manager.
+ pub fn LLVMDisposePassManager(PM: &'a mut PassManager<'a>);
+
+ /// Runs a pass manager on a module.
+ pub fn LLVMRunPassManager(PM: &PassManager<'a>, M: &'a Module) -> Bool;
+
+ pub fn LLVMInitializePasses();
+
+ pub fn LLVMPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;
+ pub fn LLVMPassManagerBuilderDispose(PMB: &'static mut PassManagerBuilder);
+ pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: &PassManagerBuilder, Value: Bool);
+ pub fn LLVMPassManagerBuilderSetDisableUnrollLoops(PMB: &PassManagerBuilder, Value: Bool);
+ pub fn LLVMPassManagerBuilderUseInlinerWithThreshold(PMB: &PassManagerBuilder,
+ threshold: c_uint);
+ pub fn LLVMPassManagerBuilderPopulateModulePassManager(PMB: &PassManagerBuilder,
+ PM: &PassManager);
+
+ pub fn LLVMPassManagerBuilderPopulateFunctionPassManager(PMB: &PassManagerBuilder,
+ PM: &PassManager);
+ pub fn LLVMPassManagerBuilderPopulateLTOPassManager(PMB: &PassManagerBuilder,
+ PM: &PassManager,
+ Internalize: Bool,
+ RunInliner: Bool);
+ pub fn LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
+ PMB: &PassManagerBuilder,
+ PM: &PassManager) -> bool;
+
+ // Stuff that's in rustllvm/ because it's not upstream yet.
+
+ /// Opens an object file.
+ pub fn LLVMCreateObjectFile(
+ MemBuf: &'static mut MemoryBuffer,
+ ) -> Option<&'static mut ObjectFile>;
+ /// Closes an object file.
+ pub fn LLVMDisposeObjectFile(ObjFile: &'static mut ObjectFile);
+
+ /// Enumerates the sections in an object file.
+ pub fn LLVMGetSections(ObjFile: &'a ObjectFile) -> &'a mut SectionIterator<'a>;
+ /// Destroys a section iterator.
+ pub fn LLVMDisposeSectionIterator(SI: &'a mut SectionIterator<'a>);
+ /// Returns true if the section iterator is at the end of the section
+ /// list:
+ pub fn LLVMIsSectionIteratorAtEnd(ObjFile: &'a ObjectFile, SI: &SectionIterator<'a>) -> Bool;
+ /// Moves the section iterator to point to the next section.
+ pub fn LLVMMoveToNextSection(SI: &SectionIterator);
+ /// Returns the current section size.
+ pub fn LLVMGetSectionSize(SI: &SectionIterator) -> c_ulonglong;
+ /// Returns the current section contents as a string buffer.
+ pub fn LLVMGetSectionContents(SI: &SectionIterator) -> *const c_char;
+
+ /// Reads the given file and returns it as a memory buffer. Use
+ /// LLVMDisposeMemoryBuffer() to get rid of it.
+ pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(
+ Path: *const c_char,
+ ) -> Option<&'static mut MemoryBuffer>;
+
+ pub fn LLVMStartMultithreaded() -> Bool;
+
+ /// Returns a string describing the last error caused by an LLVMRust* call.
+ pub fn LLVMRustGetLastError() -> *const c_char;
+
+ /// Print the pass timings since static dtors aren't picking them up.
+ pub fn LLVMRustPrintPassTimings();
+
+ pub fn LLVMStructCreateNamed(C: &Context, Name: *const c_char) -> &Type;
+
+ pub fn LLVMStructSetBody(StructTy: &'a Type,
+ ElementTypes: *const &'a Type,
+ ElementCount: c_uint,
+ Packed: Bool);
+
+ /// Prepares inline assembly.
+ pub fn LLVMRustInlineAsm(Ty: &Type,
+ AsmString: *const c_char,
+ Constraints: *const c_char,
+ SideEffects: Bool,
+ AlignStack: Bool,
+ Dialect: AsmDialect)
+ -> &Value;
+
+ pub fn LLVMRustDebugMetadataVersion() -> u32;
+ pub fn LLVMRustVersionMajor() -> u32;
+ pub fn LLVMRustVersionMinor() -> u32;
+
+ pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32);
+
+ pub fn LLVMRustMetadataAsValue(C: &'a Context, MD: &'a Metadata) -> &'a Value;
+
+ pub fn LLVMRustDIBuilderCreate(M: &'a Module) -> &'a mut DIBuilder<'a>;
+
+ pub fn LLVMRustDIBuilderDispose(Builder: &'a mut DIBuilder<'a>);
+
+ pub fn LLVMRustDIBuilderFinalize(Builder: &DIBuilder);
+
+ pub fn LLVMRustDIBuilderCreateCompileUnit(Builder: &DIBuilder<'a>,
+ Lang: c_uint,
+ File: &'a DIFile,
+ Producer: *const c_char,
+ isOptimized: bool,
+ Flags: *const c_char,
+ RuntimeVer: c_uint,
+ SplitName: *const c_char)
+ -> &'a DIDescriptor;
+
+ pub fn LLVMRustDIBuilderCreateFile(Builder: &DIBuilder<'a>,
+ Filename: *const c_char,
+ Directory: *const c_char)
+ -> &'a DIFile;
+
+ pub fn LLVMRustDIBuilderCreateSubroutineType(Builder: &DIBuilder<'a>,
+ File: &'a DIFile,
+ ParameterTypes: &'a DIArray)
+ -> &'a DICompositeType;
+
+ pub fn LLVMRustDIBuilderCreateFunction(Builder: &DIBuilder<'a>,
+ Scope: &'a DIDescriptor,
+ Name: *const c_char,
+ LinkageName: *const c_char,
+ File: &'a DIFile,
+ LineNo: c_uint,
+ Ty: &'a DIType,
+ isLocalToUnit: bool,
+ isDefinition: bool,
+ ScopeLine: c_uint,
+ Flags: DIFlags,
+ isOptimized: bool,
+ Fn: &'a Value,
+ TParam: &'a DIArray,
+ Decl: Option<&'a DIDescriptor>)
+ -> &'a DISubprogram;
+
+ pub fn LLVMRustDIBuilderCreateBasicType(Builder: &DIBuilder<'a>,
+ Name: *const c_char,
+ SizeInBits: u64,
+ AlignInBits: u32,
+ Encoding: c_uint)
+ -> &'a DIBasicType;
+
+ pub fn LLVMRustDIBuilderCreatePointerType(Builder: &DIBuilder<'a>,
+ PointeeTy: &'a DIType,
+ SizeInBits: u64,
+ AlignInBits: u32,
+ Name: *const c_char)
+ -> &'a DIDerivedType;
+
+ pub fn LLVMRustDIBuilderCreateStructType(Builder: &DIBuilder<'a>,
+ Scope: Option<&'a DIDescriptor>,
+ Name: *const c_char,
+ File: &'a DIFile,
+ LineNumber: c_uint,
+ SizeInBits: u64,
+ AlignInBits: u32,
+ Flags: DIFlags,
+ DerivedFrom: Option<&'a DIType>,
+ Elements: &'a DIArray,
+ RunTimeLang: c_uint,
+ VTableHolder: Option<&'a DIType>,
+ UniqueId: *const c_char)
+ -> &'a DICompositeType;
+
+ pub fn LLVMRustDIBuilderCreateMemberType(Builder: &DIBuilder<'a>,
+ Scope: &'a DIDescriptor,
+ Name: *const c_char,
+ File: &'a DIFile,
+ LineNo: c_uint,
+ SizeInBits: u64,
+ AlignInBits: u32,
+ OffsetInBits: u64,
+ Flags: DIFlags,
+ Ty: &'a DIType)
+ -> &'a DIDerivedType;
+
+ pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: &DIBuilder<'a>,
+ Scope: &'a DIScope,
+ File: &'a DIFile,
+ Line: c_uint,
+ Col: c_uint)
+ -> &'a DILexicalBlock;
+
+ pub fn LLVMRustDIBuilderCreateLexicalBlockFile(Builder: &DIBuilder<'a>,
+ Scope: &'a DIScope,
+ File: &'a DIFile)
+ -> &'a DILexicalBlock;
+
+ pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: &DIBuilder<'a>,
+ Context: Option<&'a DIScope>,
+ Name: *const c_char,
+ LinkageName: *const c_char,
+ File: &'a DIFile,
+ LineNo: c_uint,
+ Ty: &'a DIType,
+ isLocalToUnit: bool,
+ Val: &'a Value,
+ Decl: Option<&'a DIDescriptor>,
+ AlignInBits: u32)
+ -> &'a DIGlobalVariable;
+
+ pub fn LLVMRustDIBuilderCreateVariable(Builder: &DIBuilder<'a>,
+ Tag: c_uint,
+ Scope: &'a DIDescriptor,
+ Name: *const c_char,
+ File: &'a DIFile,
+ LineNo: c_uint,
+ Ty: &'a DIType,
+ AlwaysPreserve: bool,
+ Flags: DIFlags,
+ ArgNo: c_uint,
+ AlignInBits: u32)
+ -> &'a DIVariable;
+
+ pub fn LLVMRustDIBuilderCreateArrayType(Builder: &DIBuilder<'a>,
+ Size: u64,
+ AlignInBits: u32,
+ Ty: &'a DIType,
+ Subscripts: &'a DIArray)
+ -> &'a DIType;
+
+ pub fn LLVMRustDIBuilderGetOrCreateSubrange(Builder: &DIBuilder<'a>,
+ Lo: i64,
+ Count: i64)
+ -> &'a DISubrange;
+
+ pub fn LLVMRustDIBuilderGetOrCreateArray(Builder: &DIBuilder<'a>,
+ Ptr: *const Option<&'a DIDescriptor>,
+ Count: c_uint)
+ -> &'a DIArray;
+
+ pub fn LLVMRustDIBuilderInsertDeclareAtEnd(Builder: &DIBuilder<'a>,
+ Val: &'a Value,
+ VarInfo: &'a DIVariable,
+ AddrOps: *const i64,
+ AddrOpsCount: c_uint,
+ DL: &'a Value,
+ InsertAtEnd: &'a BasicBlock)
+ -> &'a Value;
+
+ pub fn LLVMRustDIBuilderCreateEnumerator(Builder: &DIBuilder<'a>,
+ Name: *const c_char,
+ Val: u64)
+ -> &'a DIEnumerator;
+
+ pub fn LLVMRustDIBuilderCreateEnumerationType(Builder: &DIBuilder<'a>,
+ Scope: &'a DIScope,
+ Name: *const c_char,
+ File: &'a DIFile,
+ LineNumber: c_uint,
+ SizeInBits: u64,
+ AlignInBits: u32,
+ Elements: &'a DIArray,
+ ClassType: &'a DIType)
+ -> &'a DIType;
+
+ pub fn LLVMRustDIBuilderCreateUnionType(Builder: &DIBuilder<'a>,
+ Scope: &'a DIScope,
+ Name: *const c_char,
+ File: &'a DIFile,
+ LineNumber: c_uint,
+ SizeInBits: u64,
+ AlignInBits: u32,
+ Flags: DIFlags,
+ Elements: Option<&'a DIArray>,
+ RunTimeLang: c_uint,
+ UniqueId: *const c_char)
+ -> &'a DIType;
+
+ pub fn LLVMSetUnnamedAddr(GlobalVar: &Value, UnnamedAddr: Bool);
+
+ pub fn LLVMRustDIBuilderCreateTemplateTypeParameter(Builder: &DIBuilder<'a>,
+ Scope: Option<&'a DIScope>,
+ Name: *const c_char,
+ Ty: &'a DIType,
+ File: &'a DIFile,
+ LineNo: c_uint,
+ ColumnNo: c_uint)
+ -> &'a DITemplateTypeParameter;
+
+
+ pub fn LLVMRustDIBuilderCreateNameSpace(Builder: &DIBuilder<'a>,
+ Scope: Option<&'a DIScope>,
+ Name: *const c_char,
+ File: &'a DIFile,
+ LineNo: c_uint)
+ -> &'a DINameSpace;
+
+ pub fn LLVMRustDICompositeTypeSetTypeArray(Builder: &DIBuilder<'a>,
+ CompositeType: &'a DIType,
+ TypeArray: &'a DIArray);
+
+
+ pub fn LLVMRustDIBuilderCreateDebugLocation(Context: &'a Context,
+ Line: c_uint,
+ Column: c_uint,
+ Scope: &'a DIScope,
+ InlinedAt: Option<&'a Metadata>)
+ -> &'a Value;
+ pub fn LLVMRustDIBuilderCreateOpDeref() -> i64;
+ pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64;
+}
+
+#[allow(improper_ctypes)] // FIXME(#52456) needed for RustString.
+extern "C" {
+ pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
+ pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString);
+}
+
+extern "C" {
+ pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&Value>;
+ pub fn LLVMIsAConstantFP(value_ref: &Value) -> Option<&Value>;
+
+ pub fn LLVMRustPassKind(Pass: &Pass) -> PassKind;
+ pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> Option<&'static mut Pass>;
+ pub fn LLVMRustAddPass(PM: &PassManager, Pass: &'static mut Pass);
+
+ pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
+
+ pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine);
+ pub fn LLVMRustPrintTargetFeatures(T: &TargetMachine);
+
+ pub fn LLVMRustCreateTargetMachine(Triple: *const c_char,
+ CPU: *const c_char,
+ Features: *const c_char,
+ Model: CodeModel,
+ Reloc: RelocMode,
+ Level: CodeGenOptLevel,
+ UseSoftFP: bool,
+ PositionIndependentExecutable: bool,
+ FunctionSections: bool,
+ DataSections: bool,
+ TrapUnreachable: bool,
+ Singlethread: bool)
+ -> Option<&'static mut TargetMachine>;
+ pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
+ pub fn LLVMRustAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>, M: &'a Module);
+ pub fn LLVMRustAddBuilderLibraryInfo(PMB: &'a PassManagerBuilder,
+ M: &'a Module,
+ DisableSimplifyLibCalls: bool);
+ pub fn LLVMRustConfigurePassManagerBuilder(PMB: &PassManagerBuilder,
+ OptLevel: CodeGenOptLevel,
+ MergeFunctions: bool,
+ SLPVectorize: bool,
+ LoopVectorize: bool,
+ PrepareForThinLTO: bool,
+ PGOGenPath: *const c_char,
+ PGOUsePath: *const c_char);
+ pub fn LLVMRustAddLibraryInfo(PM: &PassManager<'a>,
+ M: &'a Module,
+ DisableSimplifyLibCalls: bool);
+ pub fn LLVMRustRunFunctionPassManager(PM: &PassManager<'a>, M: &'a Module);
+ pub fn LLVMRustWriteOutputFile(T: &'a TargetMachine,
+ PM: &PassManager<'a>,
+ M: &'a Module,
+ Output: *const c_char,
+ FileType: FileType)
+ -> LLVMRustResult;
+ pub fn LLVMRustPrintModule(PM: &PassManager<'a>,
+ M: &'a Module,
+ Output: *const c_char,
+ Demangle: extern fn(*const c_char,
+ size_t,
+ *mut c_char,
+ size_t) -> size_t);
+ pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char);
+ pub fn LLVMRustPrintPasses();
+ pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char);
+ pub fn LLVMRustAddAlwaysInlinePass(P: &PassManagerBuilder, AddLifetimes: bool);
+ pub fn LLVMRustRunRestrictionPass(M: &Module, syms: *const *const c_char, len: size_t);
+ pub fn LLVMRustMarkAllFunctionsNounwind(M: &Module);
+
+ pub fn LLVMRustOpenArchive(path: *const c_char) -> Option<&'static mut Archive>;
+ pub fn LLVMRustArchiveIteratorNew(AR: &'a Archive) -> &'a mut ArchiveIterator<'a>;
+ pub fn LLVMRustArchiveIteratorNext(
+ AIR: &ArchiveIterator<'a>,
+ ) -> Option<&'a mut ArchiveChild<'a>>;
+ pub fn LLVMRustArchiveChildName(ACR: &ArchiveChild, size: &mut size_t) -> *const c_char;
+ pub fn LLVMRustArchiveChildData(ACR: &ArchiveChild, size: &mut size_t) -> *const c_char;
+ pub fn LLVMRustArchiveChildFree(ACR: &'a mut ArchiveChild<'a>);
+ pub fn LLVMRustArchiveIteratorFree(AIR: &'a mut ArchiveIterator<'a>);
+ pub fn LLVMRustDestroyArchive(AR: &'static mut Archive);
+
+ pub fn LLVMRustGetSectionName(SI: &SectionIterator, data: &mut *const c_char) -> size_t;
+}
+
+#[allow(improper_ctypes)] // FIXME(#52456) needed for RustString.
+extern "C" {
+ pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
+}
+
+extern "C" {
+ pub fn LLVMContextSetDiagnosticHandler(C: &Context,
+ Handler: DiagnosticHandler,
+ DiagnosticContext: *mut c_void);
+}
+
+#[allow(improper_ctypes)] // FIXME(#52456) needed for RustString.
+extern "C" {
+ pub fn LLVMRustUnpackOptimizationDiagnostic(DI: &'a DiagnosticInfo,
+ pass_name_out: &RustString,
+ function_out: &mut Option<&'a Value>,
+ loc_line_out: &mut c_uint,
+ loc_column_out: &mut c_uint,
+ loc_filename_out: &RustString,
+ message_out: &RustString);
+}
+
+extern "C" {
+ pub fn LLVMRustUnpackInlineAsmDiagnostic(DI: &'a DiagnosticInfo,
+ cookie_out: &mut c_uint,
+ message_out: &mut Option<&'a Twine>,
+ instruction_out: &mut Option<&'a Value>);
+}
+
+#[allow(improper_ctypes)] // FIXME(#52456) needed for RustString.
+extern "C" {
+ pub fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString);
+}
+
+extern "C" {
+ pub fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind;
+
+ pub fn LLVMRustSetInlineAsmDiagnosticHandler(C: &Context,
+ H: InlineAsmDiagHandler,
+ CX: *mut c_void);
+}
+
+#[allow(improper_ctypes)] // FIXME(#52456) needed for RustString.
+extern "C" {
+ pub fn LLVMRustWriteSMDiagnosticToString(d: &SMDiagnostic, s: &RustString);
+}
+
+extern "C" {
+ pub fn LLVMRustWriteArchive(Dst: *const c_char,
+ NumMembers: size_t,
+ Members: *const &RustArchiveMember,
+ WriteSymbtab: bool,
+ Kind: ArchiveKind)
+ -> LLVMRustResult;
+ pub fn LLVMRustArchiveMemberNew(Filename: *const c_char,
+ Name: *const c_char,
+ Child: Option<&'a ArchiveChild>)
+ -> &'a mut RustArchiveMember<'a>;
+ pub fn LLVMRustArchiveMemberFree(Member: &'a mut RustArchiveMember<'a>);
+
+ pub fn LLVMRustSetDataLayoutFromTargetMachine(M: &'a Module, TM: &'a TargetMachine);
+
+ pub fn LLVMRustBuildOperandBundleDef(Name: *const c_char,
+ Inputs: *const &'a Value,
+ NumInputs: c_uint)
+ -> &'a mut OperandBundleDef<'a>;
+ pub fn LLVMRustFreeOperandBundleDef(Bundle: &'a mut OperandBundleDef<'a>);
+
+ pub fn LLVMRustPositionBuilderAtStart(B: &Builder<'a>, BB: &'a BasicBlock);
+
+ pub fn LLVMRustSetComdat(M: &'a Module, V: &'a Value, Name: *const c_char);
+ pub fn LLVMRustUnsetComdat(V: &Value);
+ pub fn LLVMRustSetModulePIELevel(M: &Module);
+ pub fn LLVMRustModuleBufferCreate(M: &Module) -> &'static mut ModuleBuffer;
+ pub fn LLVMRustModuleBufferPtr(p: &ModuleBuffer) -> *const u8;
+ pub fn LLVMRustModuleBufferLen(p: &ModuleBuffer) -> usize;
+ pub fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer);
+ pub fn LLVMRustModuleCost(M: &Module) -> u64;
+
+ pub fn LLVMRustThinLTOAvailable() -> bool;
+ pub fn LLVMRustPGOAvailable() -> bool;
+ pub fn LLVMRustThinLTOBufferCreate(M: &Module) -> &'static mut ThinLTOBuffer;
+ pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer);
+ pub fn LLVMRustThinLTOBufferPtr(M: &ThinLTOBuffer) -> *const c_char;
+ pub fn LLVMRustThinLTOBufferLen(M: &ThinLTOBuffer) -> size_t;
+ pub fn LLVMRustCreateThinLTOData(
+ Modules: *const ThinLTOModule,
+ NumModules: c_uint,
+ PreservedSymbols: *const *const c_char,
+ PreservedSymbolsLen: c_uint,
+ ) -> Option<&'static mut ThinLTOData>;
+ pub fn LLVMRustPrepareThinLTORename(
+ Data: &ThinLTOData,
+ Module: &Module,
+ ) -> bool;
+ pub fn LLVMRustPrepareThinLTOResolveWeak(
+ Data: &ThinLTOData,
+ Module: &Module,
+ ) -> bool;
+ pub fn LLVMRustPrepareThinLTOInternalize(
+ Data: &ThinLTOData,
+ Module: &Module,
+ ) -> bool;
+ pub fn LLVMRustPrepareThinLTOImport(
+ Data: &ThinLTOData,
+ Module: &Module,
+ ) -> bool;
+ pub fn LLVMRustFreeThinLTOData(Data: &'static mut ThinLTOData);
+ pub fn LLVMRustParseBitcodeForThinLTO(
+ Context: &Context,
+ Data: *const u8,
+ len: usize,
+ Identifier: *const c_char,
+ ) -> Option<&Module>;
+ pub fn LLVMRustThinLTOGetDICompileUnit(M: &Module,
+ CU1: &mut *mut c_void,
+ CU2: &mut *mut c_void);
+ pub fn LLVMRustThinLTOPatchDICompileUnit(M: &Module, CU: *mut c_void);
+
+ pub fn LLVMRustLinkerNew(M: &'a Module) -> &'a mut Linker<'a>;
+ pub fn LLVMRustLinkerAdd(linker: &Linker,
+ bytecode: *const c_char,
+ bytecode_len: usize) -> bool;
+ pub fn LLVMRustLinkerFree(linker: &'a mut Linker<'a>);
+}
--- /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.
+
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![deny(bare_trait_objects)]
+
+pub use self::IntPredicate::*;
+pub use self::RealPredicate::*;
+pub use self::AtomicRmwBinOp::*;
+pub use self::MetadataType::*;
+pub use self::CodeGenOptSize::*;
+pub use self::CallConv::*;
+pub use self::Linkage::*;
+
+use std::str::FromStr;
+use std::string::FromUtf8Error;
+use std::slice;
+use std::ffi::{CString, CStr};
+use std::cell::RefCell;
+use libc::{self, c_uint, c_char, size_t};
+
+pub mod archive_ro;
+pub mod diagnostic;
+mod ffi;
+
+pub use self::ffi::*;
+
+impl LLVMRustResult {
+ pub fn into_result(self) -> Result<(), ()> {
+ match self {
+ LLVMRustResult::Success => Ok(()),
+ LLVMRustResult::Failure => Err(()),
+ }
+ }
+}
+
+pub fn AddFunctionAttrStringValue(llfn: &'a Value,
+ idx: AttributePlace,
+ attr: &CStr,
+ value: &CStr) {
+ unsafe {
+ LLVMRustAddFunctionAttrStringValue(llfn,
+ idx.as_uint(),
+ attr.as_ptr(),
+ value.as_ptr())
+ }
+}
+
+#[derive(Copy, Clone)]
+pub enum AttributePlace {
+ ReturnValue,
+ Argument(u32),
+ Function,
+}
+
+impl AttributePlace {
+ pub fn as_uint(self) -> c_uint {
+ match self {
+ AttributePlace::ReturnValue => 0,
+ AttributePlace::Argument(i) => 1 + i,
+ AttributePlace::Function => !0,
+ }
+ }
+}
+
+#[derive(Copy, Clone, PartialEq)]
+#[repr(C)]
+pub enum CodeGenOptSize {
+ CodeGenOptSizeNone = 0,
+ CodeGenOptSizeDefault = 1,
+ CodeGenOptSizeAggressive = 2,
+}
+
+impl FromStr for ArchiveKind {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "gnu" => Ok(ArchiveKind::K_GNU),
+ "bsd" => Ok(ArchiveKind::K_BSD),
+ "coff" => Ok(ArchiveKind::K_COFF),
+ _ => Err(()),
+ }
+ }
+}
+
+#[repr(C)]
+pub struct RustString {
+ bytes: RefCell<Vec<u8>>,
+}
+
+/// Appending to a Rust string -- used by RawRustStringOstream.
+#[no_mangle]
+pub unsafe extern "C" fn LLVMRustStringWriteImpl(sr: &RustString,
+ ptr: *const c_char,
+ size: size_t) {
+ let slice = slice::from_raw_parts(ptr as *const u8, size as usize);
+
+ sr.bytes.borrow_mut().extend_from_slice(slice);
+}
+
+pub fn SetInstructionCallConv(instr: &'a Value, cc: CallConv) {
+ unsafe {
+ LLVMSetInstructionCallConv(instr, cc as c_uint);
+ }
+}
+pub fn SetFunctionCallConv(fn_: &'a Value, cc: CallConv) {
+ unsafe {
+ LLVMSetFunctionCallConv(fn_, cc as c_uint);
+ }
+}
+
+// Externally visible symbols that might appear in multiple codegen units need to appear in
+// their own comdat section so that the duplicates can be discarded at link time. This can for
+// example happen for generics when using multiple codegen units. This function simply uses the
+// value's name as the comdat value to make sure that it is in a 1-to-1 relationship to the
+// function.
+// For more details on COMDAT sections see e.g. http://www.airs.com/blog/archives/52
+pub fn SetUniqueComdat(llmod: &Module, val: &'a Value) {
+ unsafe {
+ LLVMRustSetComdat(llmod, val, LLVMGetValueName(val));
+ }
+}
+
+pub fn UnsetComdat(val: &'a Value) {
+ unsafe {
+ LLVMRustUnsetComdat(val);
+ }
+}
+
+pub fn SetUnnamedAddr(global: &'a Value, unnamed: bool) {
+ unsafe {
+ LLVMSetUnnamedAddr(global, unnamed as Bool);
+ }
+}
+
+pub fn set_thread_local(global: &'a Value, is_thread_local: bool) {
+ unsafe {
+ LLVMSetThreadLocal(global, is_thread_local as Bool);
+ }
+}
+pub fn set_thread_local_mode(global: &'a Value, mode: ThreadLocalMode) {
+ unsafe {
+ LLVMSetThreadLocalMode(global, mode);
+ }
+}
+
+impl Attribute {
+ pub fn apply_llfn(&self, idx: AttributePlace, llfn: &Value) {
+ unsafe { LLVMRustAddFunctionAttribute(llfn, idx.as_uint(), *self) }
+ }
+
+ pub fn apply_callsite(&self, idx: AttributePlace, callsite: &Value) {
+ unsafe { LLVMRustAddCallSiteAttribute(callsite, idx.as_uint(), *self) }
+ }
+
+ pub fn unapply_llfn(&self, idx: AttributePlace, llfn: &Value) {
+ unsafe { LLVMRustRemoveFunctionAttributes(llfn, idx.as_uint(), *self) }
+ }
+
+ pub fn toggle_llfn(&self, idx: AttributePlace, llfn: &Value, set: bool) {
+ if set {
+ self.apply_llfn(idx, llfn);
+ } else {
+ self.unapply_llfn(idx, llfn);
+ }
+ }
+}
+
+// Memory-managed interface to object files.
+
+pub struct ObjectFile {
+ pub llof: &'static mut ffi::ObjectFile,
+}
+
+unsafe impl Send for ObjectFile {}
+
+impl ObjectFile {
+ // This will take ownership of llmb
+ pub fn new(llmb: &'static mut MemoryBuffer) -> Option<ObjectFile> {
+ unsafe {
+ let llof = LLVMCreateObjectFile(llmb)?;
+ Some(ObjectFile { llof: llof })
+ }
+ }
+}
+
+impl Drop for ObjectFile {
+ fn drop(&mut self) {
+ unsafe {
+ LLVMDisposeObjectFile(&mut *(self.llof as *mut _));
+ }
+ }
+}
+
+// Memory-managed interface to section iterators.
+
+pub struct SectionIter<'a> {
+ pub llsi: &'a mut SectionIterator<'a>,
+}
+
+impl Drop for SectionIter<'a> {
+ fn drop(&mut self) {
+ unsafe {
+ LLVMDisposeSectionIterator(&mut *(self.llsi as *mut _));
+ }
+ }
+}
+
+pub fn mk_section_iter(llof: &'a ffi::ObjectFile) -> SectionIter<'a> {
+ unsafe { SectionIter { llsi: LLVMGetSections(llof) } }
+}
+
+/// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
+pub fn get_param(llfn: &'a Value, index: c_uint) -> &'a Value {
+ unsafe {
+ assert!(index < LLVMCountParams(llfn),
+ "out of bounds argument access: {} out of {} arguments", index, LLVMCountParams(llfn));
+ LLVMGetParam(llfn, index)
+ }
+}
+
+pub fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
+ let sr = RustString {
+ bytes: RefCell::new(Vec::new()),
+ };
+ f(&sr);
+ String::from_utf8(sr.bytes.into_inner())
+}
+
+pub fn twine_to_string(tr: &Twine) -> String {
+ unsafe {
+ build_string(|s| LLVMRustWriteTwineToString(tr, s))
+ .expect("got a non-UTF8 Twine from LLVM")
+ }
+}
+
+pub fn last_error() -> Option<String> {
+ unsafe {
+ let cstr = LLVMRustGetLastError();
+ if cstr.is_null() {
+ None
+ } else {
+ let err = CStr::from_ptr(cstr).to_bytes();
+ let err = String::from_utf8_lossy(err).to_string();
+ libc::free(cstr as *mut _);
+ Some(err)
+ }
+ }
+}
+
+pub struct OperandBundleDef<'a> {
+ pub raw: &'a mut ffi::OperandBundleDef<'a>,
+}
+
+impl OperandBundleDef<'a> {
+ pub fn new(name: &str, vals: &[&'a Value]) -> Self {
+ let name = CString::new(name).unwrap();
+ let def = unsafe {
+ LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint)
+ };
+ OperandBundleDef { raw: def }
+ }
+}
+
+impl Drop for OperandBundleDef<'a> {
+ fn drop(&mut self) {
+ unsafe {
+ LLVMRustFreeOperandBundleDef(&mut *(self.raw as *mut _));
+ }
+ }
+}
llvm::LLVMInitializePasses();
- llvm::initialize_available_targets();
+ ::rustc_llvm::initialize_available_targets();
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
llvm_args.as_ptr());
-> Result<MetadataRef, String> {
unsafe {
let buf = common::path2cstr(filename);
- let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr());
- if mb as isize == 0 {
- return Err(format!("error reading library: '{}'", filename.display()));
- }
+ let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr())
+ .ok_or_else(|| format!("error reading library: '{}'", filename.display()))?;
let of = ObjectFile::new(mb)
.map(|of| OwningRef::new(box of))
.ok_or_else(|| format!("provided path not an object file: '{}'",
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::ValueRef;
use abi::{FnType, FnTypeExt};
use callee;
use common::*;
use monomorphize;
use type_::Type;
use value::Value;
+
use rustc::ty::{self, Ty};
use rustc::ty::layout::HasDataLayout;
use debuginfo;
VirtualIndex(index as u64 + 3)
}
- pub fn get_fn(self, bx: &Builder<'a, 'tcx>,
- llvtable: ValueRef,
- fn_ty: &FnType<'tcx, Ty<'tcx>>) -> ValueRef {
+ pub fn get_fn(self, bx: &Builder<'a, 'll, 'tcx>,
+ llvtable: &'ll Value,
+ fn_ty: &FnType<'tcx, Ty<'tcx>>) -> &'ll Value {
// Load the data pointer from the object.
- debug!("get_fn({:?}, {:?})", Value(llvtable), self);
+ debug!("get_fn({:?}, {:?})", llvtable, self);
let llvtable = bx.pointercast(llvtable, fn_ty.llvm_type(bx.cx).ptr_to().ptr_to());
let ptr_align = bx.tcx().data_layout.pointer_align;
ptr
}
- pub fn get_usize(self, bx: &Builder<'a, 'tcx>, llvtable: ValueRef) -> ValueRef {
+ pub fn get_usize(self, bx: &Builder<'a, 'll, 'tcx>, llvtable: &'ll Value) -> &'ll Value {
// Load the data pointer from the object.
- debug!("get_int({:?}, {:?})", Value(llvtable), self);
+ debug!("get_int({:?}, {:?})", llvtable, self);
let llvtable = bx.pointercast(llvtable, Type::isize(bx.cx).ptr_to());
let usize_align = bx.tcx().data_layout.pointer_align;
/// The `trait_ref` encodes the erased self type. Hence if we are
/// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
/// `trait_ref` would map `T:Trait`.
-pub fn get_vtable<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
- ty: Ty<'tcx>,
- trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>)
- -> ValueRef
-{
+pub fn get_vtable(
+ cx: &CodegenCx<'ll, 'tcx>,
+ ty: Ty<'tcx>,
+ trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+) -> &'ll Value {
let tcx = cx.tcx;
debug!("get_vtable(ty={:?}, trait_ref={:?})", ty, trait_ref);
//! An analysis to determine which locals require allocas and
//! which do not.
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::{self, Location, TerminatorKind};
use type_of::LayoutLlvmExt;
use super::FunctionCx;
-pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector<mir::Local> {
+pub fn non_ssa_locals(fx: &FunctionCx<'a, 'll, 'tcx>) -> BitArray<mir::Local> {
let mir = fx.mir;
let mut analyzer = LocalAnalyzer::new(fx);
let layout = fx.cx.layout_of(ty);
if layout.is_llvm_immediate() {
// These sorts of types are immediates that we can store
- // in an ValueRef without an alloca.
+ // in an Value without an alloca.
} else if layout.is_llvm_scalar_pair() {
// We allow pairs and uses of any of their 2 fields.
} else {
analyzer.non_ssa_locals
}
-struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a> {
- fx: &'mir FunctionCx<'a, 'tcx>,
+struct LocalAnalyzer<'mir, 'a: 'mir, 'll: 'a, 'tcx: 'll> {
+ fx: &'mir FunctionCx<'a, 'll, 'tcx>,
dominators: Dominators<mir::BasicBlock>,
- non_ssa_locals: BitVector<mir::Local>,
+ non_ssa_locals: BitArray<mir::Local>,
// The location of the first visited direct assignment to each
// local, or an invalid location (out of bounds `block` index).
first_assignment: IndexVec<mir::Local, Location>
}
-impl<'mir, 'a, 'tcx> LocalAnalyzer<'mir, 'a, 'tcx> {
- fn new(fx: &'mir FunctionCx<'a, 'tcx>) -> LocalAnalyzer<'mir, 'a, 'tcx> {
+impl LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
+ fn new(fx: &'mir FunctionCx<'a, 'll, 'tcx>) -> Self {
let invalid_location =
mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location();
let mut analyzer = LocalAnalyzer {
fx,
dominators: fx.mir.dominators(),
- non_ssa_locals: BitVector::new(fx.mir.local_decls.len()),
+ non_ssa_locals: BitArray::new(fx.mir.local_decls.len()),
first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls)
};
}
}
-impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
+impl Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'll, 'tcx> {
fn visit_assign(&mut self,
block: mir::BasicBlock,
place: &mir::Place<'tcx>,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::{self, ValueRef, BasicBlockRef};
+use llvm::{self, BasicBlock};
use rustc::middle::lang_items;
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::ty::layout::{self, LayoutOf};
use monomorphize;
use type_of::LayoutLlvmExt;
use type_::Type;
+use value::Value;
use syntax::symbol::Symbol;
use syntax_pos::Pos;
use super::operand::OperandRef;
use super::operand::OperandValue::{Pair, Ref, Immediate};
-impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
+impl FunctionCx<'a, 'll, 'tcx> {
pub fn codegen_block(&mut self, bb: mir::BasicBlock) {
let mut bx = self.build_block(bb);
let data = &self.mir[bb];
}
fn codegen_terminator(&mut self,
- mut bx: Builder<'a, 'tcx>,
+ mut bx: Builder<'a, 'll, 'tcx>,
bb: mir::BasicBlock,
terminator: &mir::Terminator<'tcx>)
{
}
};
- let funclet_br = |this: &mut Self, bx: Builder, target: mir::BasicBlock| {
+ let funclet_br = |this: &mut Self, bx: Builder<'_, 'll, '_>, target: mir::BasicBlock| {
let (lltarget, is_cleanupret) = lltarget(this, target);
if is_cleanupret {
// micro-optimization: generate a `ret` rather than a jump
let do_call = |
this: &mut Self,
- bx: Builder<'a, 'tcx>,
+ bx: Builder<'a, 'll, 'tcx>,
fn_ty: FnType<'tcx, Ty<'tcx>>,
- fn_ptr: ValueRef,
- llargs: &[ValueRef],
- destination: Option<(ReturnDest<'tcx>, mir::BasicBlock)>,
+ fn_ptr: &'ll Value,
+ llargs: &[&'ll Value],
+ destination: Option<(ReturnDest<'ll, 'tcx>, mir::BasicBlock)>,
cleanup: Option<mir::BasicBlock>
| {
if let Some(cleanup) = cleanup {
}
let place = self.codegen_place(&bx, location);
- let mut args: &[_] = &[place.llval, place.llextra];
- args = &args[..1 + place.has_extra() as usize];
+ let (args1, args2);
+ let mut args = if let Some(llextra) = place.llextra {
+ args2 = [place.llval, llextra];
+ &args2[..]
+ } else {
+ args1 = [place.llval];
+ &args1[..]
+ };
let (drop_fn, fn_ty) = match ty.sty {
ty::TyDynamic(..) => {
let fn_ty = drop_fn.ty(bx.cx.tcx);
&sig,
);
let fn_ty = FnType::new_vtable(bx.cx, sig, &[]);
+ let vtable = args[1];
args = &args[..1];
- (meth::DESTRUCTOR.get_fn(&bx, place.llextra, &fn_ty), fn_ty)
+ (meth::DESTRUCTOR.get_fn(&bx, vtable, &fn_ty), fn_ty)
}
_ => {
(callee::get_fn(bx.cx, drop_fn),
}
fn codegen_argument(&mut self,
- bx: &Builder<'a, 'tcx>,
- op: OperandRef<'tcx>,
- llargs: &mut Vec<ValueRef>,
+ bx: &Builder<'a, 'll, 'tcx>,
+ op: OperandRef<'ll, 'tcx>,
+ llargs: &mut Vec<&'ll Value>,
arg: &ArgType<'tcx, Ty<'tcx>>) {
// Fill padding with undef value, where applicable.
if let Some(ty) = arg.pad {
}
fn codegen_arguments_untupled(&mut self,
- bx: &Builder<'a, 'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
operand: &mir::Operand<'tcx>,
- llargs: &mut Vec<ValueRef>,
+ llargs: &mut Vec<&'ll Value>,
args: &[ArgType<'tcx, Ty<'tcx>>]) {
let tuple = self.codegen_operand(bx, operand);
}
}
- fn get_personality_slot(&mut self, bx: &Builder<'a, 'tcx>) -> PlaceRef<'tcx> {
+ fn get_personality_slot(&mut self, bx: &Builder<'a, 'll, 'tcx>) -> PlaceRef<'ll, 'tcx> {
let cx = bx.cx;
if let Some(slot) = self.personality_slot {
slot
/// Return the landingpad wrapper around the given basic block
///
/// No-op in MSVC SEH scheme.
- fn landing_pad_to(&mut self, target_bb: mir::BasicBlock) -> BasicBlockRef {
+ fn landing_pad_to(&mut self, target_bb: mir::BasicBlock) -> &'ll BasicBlock {
if let Some(block) = self.landing_pads[target_bb] {
return block;
}
landing_pad
}
- fn landing_pad_uncached(&mut self, target_bb: BasicBlockRef) -> BasicBlockRef {
+ fn landing_pad_uncached(&mut self, target_bb: &'ll BasicBlock) -> &'ll BasicBlock {
if base::wants_msvc_seh(self.cx.sess()) {
span_bug!(self.mir.span, "landing pad was not inserted?")
}
bx.llbb()
}
- fn landing_pad_type(&self) -> Type {
+ fn landing_pad_type(&self) -> &'ll Type {
let cx = self.cx;
Type::struct_(cx, &[Type::i8p(cx), Type::i32(cx)], false)
}
- fn unreachable_block(&mut self) -> BasicBlockRef {
+ fn unreachable_block(&mut self) -> &'ll BasicBlock {
self.unreachable_block.unwrap_or_else(|| {
let bl = self.new_block("unreachable");
bl.unreachable();
})
}
- pub fn new_block(&self, name: &str) -> Builder<'a, 'tcx> {
+ pub fn new_block(&self, name: &str) -> Builder<'a, 'll, 'tcx> {
Builder::new_block(self.cx, self.llfn, name)
}
- pub fn build_block(&self, bb: mir::BasicBlock) -> Builder<'a, 'tcx> {
+ pub fn build_block(&self, bb: mir::BasicBlock) -> Builder<'a, 'll, 'tcx> {
let bx = Builder::with_cx(self.cx);
bx.position_at_end(self.blocks[bb]);
bx
}
- fn make_return_dest(&mut self, bx: &Builder<'a, 'tcx>,
+ fn make_return_dest(&mut self, bx: &Builder<'a, 'll, 'tcx>,
dest: &mir::Place<'tcx>, fn_ret: &ArgType<'tcx, Ty<'tcx>>,
- llargs: &mut Vec<ValueRef>, is_intrinsic: bool)
- -> ReturnDest<'tcx> {
+ llargs: &mut Vec<&'ll Value>, is_intrinsic: bool)
+ -> ReturnDest<'ll, 'tcx> {
// If the return is ignored, we can just return a do-nothing ReturnDest
if fn_ret.is_ignore() {
return ReturnDest::Nothing;
}
}
- fn codegen_transmute(&mut self, bx: &Builder<'a, 'tcx>,
+ fn codegen_transmute(&mut self, bx: &Builder<'a, 'll, 'tcx>,
src: &mir::Operand<'tcx>,
dst: &mir::Place<'tcx>) {
if let mir::Place::Local(index) = *dst {
}
}
- fn codegen_transmute_into(&mut self, bx: &Builder<'a, 'tcx>,
+ fn codegen_transmute_into(&mut self, bx: &Builder<'a, 'll, 'tcx>,
src: &mir::Operand<'tcx>,
- dst: PlaceRef<'tcx>) {
+ dst: PlaceRef<'ll, 'tcx>) {
let src = self.codegen_operand(bx, src);
let llty = src.layout.llvm_type(bx.cx);
let cast_ptr = bx.pointercast(dst.llval, llty.ptr_to());
// Stores the return value of a function call into it's final location.
fn store_return(&mut self,
- bx: &Builder<'a, 'tcx>,
- dest: ReturnDest<'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
+ dest: ReturnDest<'ll, 'tcx>,
ret_ty: &ArgType<'tcx, Ty<'tcx>>,
- llval: ValueRef) {
+ llval: &'ll Value) {
use self::ReturnDest::*;
match dest {
}
}
-enum ReturnDest<'tcx> {
+enum ReturnDest<'ll, 'tcx> {
// Do nothing, the return value is indirect or ignored
Nothing,
// Store the return value to the pointer
- Store(PlaceRef<'tcx>),
+ Store(PlaceRef<'ll, 'tcx>),
// Stores an indirect return value to an operand local place
- IndirectOperand(PlaceRef<'tcx>, mir::Local),
+ IndirectOperand(PlaceRef<'ll, 'tcx>, mir::Local),
// Stores a direct return value to an operand local place
DirectOperand(mir::Local)
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::{self, ValueRef};
+use llvm;
use rustc::mir::interpret::ConstEvalErr;
use rustc_mir::interpret::{read_target_uint, const_val_field};
use rustc::hir::def_id::DefId;
use type_::Type;
use syntax::ast::Mutability;
use syntax::codemap::Span;
+use value::Value;
use super::super::callee;
use super::FunctionCx;
-pub fn scalar_to_llvm(cx: &CodegenCx,
- cv: Scalar,
- layout: &layout::Scalar,
- llty: Type) -> ValueRef {
+pub fn scalar_to_llvm(
+ cx: &CodegenCx<'ll, '_>,
+ cv: Scalar,
+ layout: &layout::Scalar,
+ llty: &'ll Type,
+) -> &'ll Value {
let bitsize = if layout.is_bool() { 1 } else { layout.value.size(cx).bits() };
match cv {
- Scalar::Bits { defined, .. } if (defined as u64) < bitsize || defined == 0 => {
- C_undef(Type::ix(cx, bitsize))
+ Scalar::Bits { size: 0, .. } => {
+ assert_eq!(0, layout.value.size(cx).bytes());
+ C_undef(Type::ix(cx, 0))
},
- Scalar::Bits { bits, .. } => {
+ Scalar::Bits { bits, size } => {
+ assert_eq!(size as u64, layout.value.size(cx).bytes());
let llval = C_uint_big(Type::ix(cx, bitsize), bits);
if layout.value == layout::Pointer {
- unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) }
+ unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
} else {
consts::bitcast(llval, llty)
}
1,
) };
if layout.value != layout::Pointer {
- unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) }
+ unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
} else {
consts::bitcast(llval, llty)
}
}
}
-pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
+pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
let layout = cx.data_layout();
let pointer_size = layout.pointer_size.bytes() as usize;
C_struct(cx, &llvals, true)
}
-pub fn codegen_static_initializer<'a, 'tcx>(
- cx: &CodegenCx<'a, 'tcx>,
+pub fn codegen_static_initializer(
+ cx: &CodegenCx<'ll, 'tcx>,
def_id: DefId,
-) -> Result<(ValueRef, &'tcx Allocation), Lrc<ConstEvalErr<'tcx>>> {
+) -> Result<(&'ll Value, &'tcx Allocation), Lrc<ConstEvalErr<'tcx>>> {
let instance = ty::Instance::mono(cx.tcx, def_id);
let cid = GlobalId {
instance,
Ok((const_alloc_to_llvm(cx, alloc), alloc))
}
-impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
+impl FunctionCx<'a, 'll, 'tcx> {
fn fully_evaluate(
&mut self,
- bx: &Builder<'a, 'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
constant: &'tcx ty::Const<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
match constant.val {
pub fn eval_mir_constant(
&mut self,
- bx: &Builder<'a, 'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
constant: &mir::Constant<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
let c = self.monomorphize(&constant.literal);
/// process constant containing SIMD shuffle indices
pub fn simd_shuffle_indices(
&mut self,
- bx: &Builder<'a, 'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
span: Span,
ty: Ty<'tcx>,
constant: Result<&'tcx ty::Const<'tcx>, Lrc<ConstEvalErr<'tcx>>>,
- ) -> (ValueRef, Ty<'tcx>) {
+ ) -> (&'ll Value, Ty<'tcx>) {
constant
.and_then(|c| {
let field_ty = c.ty.builtin_index().unwrap();
ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()),
ref other => bug!("invalid simd shuffle type: {}", other),
};
- let values: Result<Vec<ValueRef>, Lrc<_>> = (0..fields).map(|field| {
+ let values: Result<Vec<_>, Lrc<_>> = (0..fields).map(|field| {
let field = const_val_field(
bx.tcx(),
ty::ParamEnv::reveal_all(),
mir::Field::new(field as usize),
c,
)?;
- if let Some(prim) = field.to_scalar() {
+ if let Some(prim) = field.val.try_to_scalar() {
let layout = bx.cx.layout_of(field_ty);
let scalar = match layout.abi {
layout::Abi::Scalar(ref x) => x,
use common::{C_i32, C_null};
use libc::c_uint;
-use llvm::{self, ValueRef, BasicBlockRef};
+use llvm::{self, BasicBlock};
use llvm::debuginfo::DIScope;
use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts};
use rustc::ty::layout::{LayoutOf, TyLayout};
use rustc::mir::{self, Mir};
use rustc::ty::subst::Substs;
-use rustc::session::config::FullDebugInfo;
+use rustc::session::config::DebugInfo;
use base;
use builder::Builder;
use common::{CodegenCx, Funclet};
use monomorphize::Instance;
use abi::{ArgTypeExt, FnType, FnTypeExt, PassMode};
use type_::Type;
+use value::Value;
use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span};
use syntax::symbol::keywords;
use std::iter;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
pub use self::constant::codegen_static_initializer;
use self::operand::{OperandRef, OperandValue};
/// Master context for codegenning from MIR.
-pub struct FunctionCx<'a, 'tcx:'a> {
+pub struct FunctionCx<'a, 'll: 'a, 'tcx: 'll> {
instance: Instance<'tcx>,
mir: &'a mir::Mir<'tcx>,
- debug_context: debuginfo::FunctionDebugContext,
+ debug_context: FunctionDebugContext<'ll>,
- llfn: ValueRef,
+ llfn: &'ll Value,
- cx: &'a CodegenCx<'a, 'tcx>,
+ cx: &'a CodegenCx<'ll, 'tcx>,
fn_ty: FnType<'tcx, Ty<'tcx>>,
/// don't really care about it very much. Anyway, this value
/// contains an alloca into which the personality is stored and
/// then later loaded when generating the DIVERGE_BLOCK.
- personality_slot: Option<PlaceRef<'tcx>>,
+ personality_slot: Option<PlaceRef<'ll, 'tcx>>,
/// A `Block` for each MIR `BasicBlock`
- blocks: IndexVec<mir::BasicBlock, BasicBlockRef>,
+ blocks: IndexVec<mir::BasicBlock, &'ll BasicBlock>,
/// The funclet status of each basic block
cleanup_kinds: IndexVec<mir::BasicBlock, analyze::CleanupKind>,
/// When targeting MSVC, this stores the cleanup info for each funclet
/// BB. This is initialized as we compute the funclets' head block in RPO.
- funclets: &'a IndexVec<mir::BasicBlock, Option<Funclet>>,
+ funclets: &'a IndexVec<mir::BasicBlock, Option<Funclet<'ll>>>,
/// This stores the landing-pad block for a given BB, computed lazily on GNU
/// and eagerly on MSVC.
- landing_pads: IndexVec<mir::BasicBlock, Option<BasicBlockRef>>,
+ landing_pads: IndexVec<mir::BasicBlock, Option<&'ll BasicBlock>>,
/// Cached unreachable block
- unreachable_block: Option<BasicBlockRef>,
+ unreachable_block: Option<&'ll BasicBlock>,
/// The location where each MIR arg/var/tmp/ret is stored. This is
/// usually an `PlaceRef` representing an alloca, but not always:
///
/// Avoiding allocs can also be important for certain intrinsics,
/// notably `expect`.
- locals: IndexVec<mir::Local, LocalRef<'tcx>>,
+ locals: IndexVec<mir::Local, LocalRef<'ll, 'tcx>>,
/// Debug information for MIR scopes.
- scopes: IndexVec<mir::SourceScope, debuginfo::MirDebugScope>,
+ scopes: IndexVec<mir::SourceScope, debuginfo::MirDebugScope<'ll>>,
/// If this function is being monomorphized, this contains the type substitutions used.
param_substs: &'tcx Substs<'tcx>,
}
-impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
+impl FunctionCx<'a, 'll, 'tcx> {
pub fn monomorphize<T>(&self, value: &T) -> T
where T: TypeFoldable<'tcx>
{
)
}
- pub fn set_debug_loc(&mut self, bx: &Builder, source_info: mir::SourceInfo) {
+ pub fn set_debug_loc(&mut self, bx: &Builder<'_, 'll, '_>, source_info: mir::SourceInfo) {
let (scope, span) = self.debug_loc(source_info);
debuginfo::set_source_location(&self.debug_context, bx, scope, span);
}
- pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> (DIScope, Span) {
+ pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> (Option<&'ll DIScope>, Span) {
// Bail out if debug info emission is not enabled.
match self.debug_context {
FunctionDebugContext::DebugInfoDisabled |
// corresponding to span's containing source scope. If so, we need to create a DIScope
// "extension" into that file.
fn scope_metadata_for_loc(&self, scope_id: mir::SourceScope, pos: BytePos)
- -> llvm::debuginfo::DIScope {
+ -> Option<&'ll DIScope> {
let scope_metadata = self.scopes[scope_id].scope_metadata;
if pos < self.scopes[scope_id].file_start_pos ||
pos >= self.scopes[scope_id].file_end_pos {
let cm = self.cx.sess().codemap();
let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate;
- debuginfo::extend_scope_to_file(self.cx,
- scope_metadata,
+ Some(debuginfo::extend_scope_to_file(self.cx,
+ scope_metadata.unwrap(),
&cm.lookup_char_pos(pos).file,
- defining_crate)
+ defining_crate))
} else {
scope_metadata
}
}
}
-enum LocalRef<'tcx> {
- Place(PlaceRef<'tcx>),
- Operand(Option<OperandRef<'tcx>>),
+enum LocalRef<'ll, 'tcx> {
+ Place(PlaceRef<'ll, 'tcx>),
+ Operand(Option<OperandRef<'ll, 'tcx>>),
}
-impl<'a, 'tcx> LocalRef<'tcx> {
- fn new_operand(cx: &CodegenCx<'a, 'tcx>, layout: TyLayout<'tcx>) -> LocalRef<'tcx> {
+impl LocalRef<'ll, 'tcx> {
+ fn new_operand(cx: &CodegenCx<'ll, 'tcx>, layout: TyLayout<'tcx>) -> LocalRef<'ll, 'tcx> {
if layout.is_zst() {
// Zero-size temporaries aren't always initialized, which
// doesn't matter because they don't contain data, but
///////////////////////////////////////////////////////////////////////////
-pub fn codegen_mir<'a, 'tcx: 'a>(
- cx: &'a CodegenCx<'a, 'tcx>,
- llfn: ValueRef,
+pub fn codegen_mir(
+ cx: &'a CodegenCx<'ll, 'tcx>,
+ llfn: &'ll Value,
mir: &'a Mir<'tcx>,
instance: Instance<'tcx>,
sig: ty::FnSig<'tcx>,
// Allocate a `Block` for every basic block, except
// the start block, if nothing loops back to it.
let reentrant_start_block = !mir.predecessors_for(mir::START_BLOCK).is_empty();
- let block_bxs: IndexVec<mir::BasicBlock, BasicBlockRef> =
+ let block_bxs: IndexVec<mir::BasicBlock, &'ll BasicBlock> =
mir.basic_blocks().indices().map(|bb| {
if bb == mir::START_BLOCK && !reentrant_start_block {
bx.llbb()
if let Some(name) = decl.name {
// User variable
let debug_scope = fx.scopes[decl.visibility_scope];
- let dbg = debug_scope.is_valid() && bx.sess().opts.debuginfo == FullDebugInfo;
+ let dbg = debug_scope.is_valid() && bx.sess().opts.debuginfo == DebugInfo::Full;
if !memory_locals.contains(local) && !dbg {
debug!("alloc: {:?} ({}) -> operand", local, name);
span: decl.source_info.span,
scope: decl.visibility_scope,
});
- declare_local(&bx, &fx.debug_context, name, layout.ty, scope,
+ declare_local(&bx, &fx.debug_context, name, layout.ty, scope.unwrap(),
VariableAccess::DirectVariable { alloca: place.llval },
VariableKind::LocalVariable, span);
}
debuginfo::start_emitting_source_locations(&fx.debug_context);
let rpo = traversal::reverse_postorder(&mir);
- let mut visited = BitVector::new(mir.basic_blocks().len());
+ let mut visited = BitArray::new(mir.basic_blocks().len());
// Codegen the body of each block using reverse postorder
for (bb, _) in rpo {
}
}
-fn create_funclets<'a, 'tcx>(
+fn create_funclets(
mir: &'a Mir<'tcx>,
- bx: &Builder<'a, 'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
cleanup_kinds: &IndexVec<mir::BasicBlock, CleanupKind>,
- block_bxs: &IndexVec<mir::BasicBlock, BasicBlockRef>)
- -> (IndexVec<mir::BasicBlock, Option<BasicBlockRef>>,
- IndexVec<mir::BasicBlock, Option<Funclet>>)
+ block_bxs: &IndexVec<mir::BasicBlock, &'ll BasicBlock>)
+ -> (IndexVec<mir::BasicBlock, Option<&'ll BasicBlock>>,
+ IndexVec<mir::BasicBlock, Option<Funclet<'ll>>>)
{
block_bxs.iter_enumerated().zip(cleanup_kinds).map(|((bb, &llbb), cleanup_kind)| {
match *cleanup_kind {
}).unzip()
}
-/// Produce, for each argument, a `ValueRef` pointing at the
+/// Produce, for each argument, a `Value` pointing at the
/// argument's value. As arguments are places, these are always
/// indirect.
-fn arg_local_refs<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
- fx: &FunctionCx<'a, 'tcx>,
- scopes: &IndexVec<mir::SourceScope, debuginfo::MirDebugScope>,
- memory_locals: &BitVector<mir::Local>)
- -> Vec<LocalRef<'tcx>> {
+fn arg_local_refs(
+ bx: &Builder<'a, 'll, 'tcx>,
+ fx: &FunctionCx<'a, 'll, 'tcx>,
+ scopes: &IndexVec<mir::SourceScope, debuginfo::MirDebugScope<'ll>>,
+ memory_locals: &BitArray<mir::Local>,
+) -> Vec<LocalRef<'ll, 'tcx>> {
let mir = fx.mir;
let tcx = bx.tcx();
let mut idx = 0;
// Get the argument scope, if it exists and if we need it.
let arg_scope = scopes[mir::OUTERMOST_SOURCE_SCOPE];
- let arg_scope = if arg_scope.is_valid() && bx.sess().opts.debuginfo == FullDebugInfo {
- Some(arg_scope.scope_metadata)
+ let arg_scope = if bx.sess().opts.debuginfo == DebugInfo::Full {
+ arg_scope.scope_metadata
} else {
None
};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::ValueRef;
use rustc::mir::interpret::ConstEvalErr;
use rustc::mir;
-use rustc::mir::interpret::ConstValue;
+use rustc::mir::interpret::{ConstValue, ScalarMaybeUndef};
use rustc::ty;
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
use rustc_data_structures::indexed_vec::Idx;
use type_of::LayoutLlvmExt;
use std::fmt;
-use std::ptr;
use super::{FunctionCx, LocalRef};
use super::constant::scalar_to_llvm;
/// The representation of a Rust value. The enum variant is in fact
/// uniquely determined by the value's type, but is kept as a
/// safety check.
-#[derive(Copy, Clone)]
-pub enum OperandValue {
+#[derive(Copy, Clone, Debug)]
+pub enum OperandValue<'ll> {
/// A reference to the actual operand. The data is guaranteed
/// to be valid for the operand's lifetime.
- Ref(ValueRef, Align),
+ Ref(&'ll Value, Align),
/// A single LLVM value.
- Immediate(ValueRef),
+ Immediate(&'ll Value),
/// A pair of immediate LLVM values. Used by fat pointers too.
- Pair(ValueRef, ValueRef)
-}
-
-impl fmt::Debug for OperandValue {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- OperandValue::Ref(r, align) => {
- write!(f, "Ref({:?}, {:?})", Value(r), align)
- }
- OperandValue::Immediate(i) => {
- write!(f, "Immediate({:?})", Value(i))
- }
- OperandValue::Pair(a, b) => {
- write!(f, "Pair({:?}, {:?})", Value(a), Value(b))
- }
- }
- }
+ Pair(&'ll Value, &'ll Value)
}
/// An `OperandRef` is an "SSA" reference to a Rust value, along with
/// directly is sure to cause problems -- use `OperandRef::store`
/// instead.
#[derive(Copy, Clone)]
-pub struct OperandRef<'tcx> {
+pub struct OperandRef<'ll, 'tcx> {
// The value.
- pub val: OperandValue,
+ pub val: OperandValue<'ll>,
// The layout of value, based on its Rust type.
pub layout: TyLayout<'tcx>,
}
-impl<'tcx> fmt::Debug for OperandRef<'tcx> {
+impl fmt::Debug for OperandRef<'ll, 'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "OperandRef({:?} @ {:?})", self.val, self.layout)
}
}
-impl<'a, 'tcx> OperandRef<'tcx> {
- pub fn new_zst(cx: &CodegenCx<'a, 'tcx>,
- layout: TyLayout<'tcx>) -> OperandRef<'tcx> {
+impl OperandRef<'ll, 'tcx> {
+ pub fn new_zst(cx: &CodegenCx<'ll, 'tcx>,
+ layout: TyLayout<'tcx>) -> OperandRef<'ll, 'tcx> {
assert!(layout.is_zst());
OperandRef {
val: OperandValue::Immediate(C_undef(layout.immediate_llvm_type(cx))),
}
}
- pub fn from_const(bx: &Builder<'a, 'tcx>,
+ pub fn from_const(bx: &Builder<'a, 'll, 'tcx>,
val: &'tcx ty::Const<'tcx>)
- -> Result<OperandRef<'tcx>, Lrc<ConstEvalErr<'tcx>>> {
+ -> Result<OperandRef<'ll, 'tcx>, Lrc<ConstEvalErr<'tcx>>> {
let layout = bx.cx.layout_of(val.ty);
if layout.is_zst() {
a_scalar,
layout.scalar_pair_element_llvm_type(bx.cx, 0, true),
);
- let b_llval = scalar_to_llvm(
- bx.cx,
- b,
- b_scalar,
- layout.scalar_pair_element_llvm_type(bx.cx, 1, true),
- );
+ let b_layout = layout.scalar_pair_element_llvm_type(bx.cx, 1, true);
+ let b_llval = match b {
+ ScalarMaybeUndef::Scalar(b) => scalar_to_llvm(
+ bx.cx,
+ b,
+ b_scalar,
+ b_layout,
+ ),
+ ScalarMaybeUndef::Undef => C_undef(b_layout),
+ };
OperandValue::Pair(a_llval, b_llval)
},
ConstValue::ByRef(alloc, offset) => {
/// Asserts that this operand refers to a scalar and returns
/// a reference to its value.
- pub fn immediate(self) -> ValueRef {
+ pub fn immediate(self) -> &'ll Value {
match self.val {
OperandValue::Immediate(s) => s,
_ => bug!("not immediate: {:?}", self)
}
}
- pub fn deref(self, cx: &CodegenCx<'a, 'tcx>) -> PlaceRef<'tcx> {
+ pub fn deref(self, cx: &CodegenCx<'ll, 'tcx>) -> PlaceRef<'ll, 'tcx> {
let projected_ty = self.layout.ty.builtin_deref(true)
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)).ty;
let (llptr, llextra) = match self.val {
- OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()),
- OperandValue::Pair(llptr, llextra) => (llptr, llextra),
+ OperandValue::Immediate(llptr) => (llptr, None),
+ OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self)
};
let layout = cx.layout_of(projected_ty);
/// If this operand is a `Pair`, we return an aggregate with the two values.
/// For other cases, see `immediate`.
- pub fn immediate_or_packed_pair(self, bx: &Builder<'a, 'tcx>) -> ValueRef {
+ pub fn immediate_or_packed_pair(self, bx: &Builder<'a, 'll, 'tcx>) -> &'ll Value {
if let OperandValue::Pair(a, b) = self.val {
let llty = self.layout.llvm_type(bx.cx);
debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}",
}
/// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`.
- pub fn from_immediate_or_packed_pair(bx: &Builder<'a, 'tcx>,
- llval: ValueRef,
+ pub fn from_immediate_or_packed_pair(bx: &Builder<'a, 'll, 'tcx>,
+ llval: &'ll Value,
layout: TyLayout<'tcx>)
- -> OperandRef<'tcx> {
+ -> OperandRef<'ll, 'tcx> {
let val = if let layout::Abi::ScalarPair(ref a, ref b) = layout.abi {
debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}",
llval, layout);
OperandRef { val, layout }
}
- pub fn extract_field(&self, bx: &Builder<'a, 'tcx>, i: usize) -> OperandRef<'tcx> {
+ pub fn extract_field(&self, bx: &Builder<'a, 'll, 'tcx>, i: usize) -> OperandRef<'ll, 'tcx> {
let field = self.layout.field(bx.cx, i);
let offset = self.layout.fields.offset(i);
}
}
-impl<'a, 'tcx> OperandValue {
- pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
+impl OperandValue<'ll> {
+ pub fn store(self, bx: &Builder<'a, 'll, 'tcx>, dest: PlaceRef<'ll, 'tcx>) {
self.store_with_flags(bx, dest, MemFlags::empty());
}
- pub fn volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
+ pub fn volatile_store(self, bx: &Builder<'a, 'll, 'tcx>, dest: PlaceRef<'ll, 'tcx>) {
self.store_with_flags(bx, dest, MemFlags::VOLATILE);
}
- pub fn unaligned_volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
+ pub fn unaligned_volatile_store(self, bx: &Builder<'a, 'll, 'tcx>, dest: PlaceRef<'ll, 'tcx>) {
self.store_with_flags(bx, dest, MemFlags::VOLATILE | MemFlags::UNALIGNED);
}
- pub fn nontemporal_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
+ pub fn nontemporal_store(self, bx: &Builder<'a, 'll, 'tcx>, dest: PlaceRef<'ll, 'tcx>) {
self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL);
}
- fn store_with_flags(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, flags: MemFlags) {
+ fn store_with_flags(
+ self,
+ bx: &Builder<'a, 'll, 'tcx>,
+ dest: PlaceRef<'ll, 'tcx>,
+ flags: MemFlags,
+ ) {
debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest);
// Avoid generating stores of zero-sized values, because the only way to have a zero-sized
// value is through `undef`, and store itself is useless.
}
}
-impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
+impl FunctionCx<'a, 'll, 'tcx> {
fn maybe_codegen_consume_direct(&mut self,
- bx: &Builder<'a, 'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
place: &mir::Place<'tcx>)
- -> Option<OperandRef<'tcx>>
+ -> Option<OperandRef<'ll, 'tcx>>
{
debug!("maybe_codegen_consume_direct(place={:?})", place);
}
pub fn codegen_consume(&mut self,
- bx: &Builder<'a, 'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
place: &mir::Place<'tcx>)
- -> OperandRef<'tcx>
+ -> OperandRef<'ll, 'tcx>
{
debug!("codegen_consume(place={:?})", place);
}
pub fn codegen_operand(&mut self,
- bx: &Builder<'a, 'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
operand: &mir::Operand<'tcx>)
- -> OperandRef<'tcx>
+ -> OperandRef<'ll, 'tcx>
{
debug!("codegen_operand(operand={:?})", operand);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::{self, ValueRef, LLVMConstInBoundsGEP};
+use llvm::{self, LLVMConstInBoundsGEP};
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, Size};
use rustc::mir;
use glue;
use mir::constant::const_alloc_to_llvm;
-use std::ptr;
-
use super::{FunctionCx, LocalRef};
use super::operand::{OperandRef, OperandValue};
#[derive(Copy, Clone, Debug)]
-pub struct PlaceRef<'tcx> {
+pub struct PlaceRef<'ll, 'tcx> {
/// Pointer to the contents of the place
- pub llval: ValueRef,
+ pub llval: &'ll Value,
/// This place's extra data if it is unsized, or null
- pub llextra: ValueRef,
+ pub llextra: Option<&'ll Value>,
/// Monomorphized type of this place, including variant information
pub layout: TyLayout<'tcx>,
pub align: Align,
}
-impl<'a, 'tcx> PlaceRef<'tcx> {
- pub fn new_sized(llval: ValueRef,
- layout: TyLayout<'tcx>,
- align: Align)
- -> PlaceRef<'tcx> {
+impl PlaceRef<'ll, 'tcx> {
+ pub fn new_sized(
+ llval: &'ll Value,
+ layout: TyLayout<'tcx>,
+ align: Align,
+ ) -> PlaceRef<'ll, 'tcx> {
PlaceRef {
llval,
- llextra: ptr::null_mut(),
+ llextra: None,
layout,
align
}
}
pub fn from_const_alloc(
- bx: &Builder<'a, 'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
layout: TyLayout<'tcx>,
alloc: &mir::interpret::Allocation,
offset: Size,
- ) -> PlaceRef<'tcx> {
+ ) -> PlaceRef<'ll, 'tcx> {
let init = const_alloc_to_llvm(bx.cx, alloc);
let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str");
PlaceRef::new_sized(llval, layout, alloc.align)
}
- pub fn alloca(bx: &Builder<'a, 'tcx>, layout: TyLayout<'tcx>, name: &str)
- -> PlaceRef<'tcx> {
+ pub fn alloca(bx: &Builder<'a, 'll, 'tcx>, layout: TyLayout<'tcx>, name: &str)
+ -> PlaceRef<'ll, 'tcx> {
debug!("alloca({:?}: {:?})", name, layout);
let tmp = bx.alloca(layout.llvm_type(bx.cx), name, layout.align);
Self::new_sized(tmp, layout, layout.align)
}
- pub fn len(&self, cx: &CodegenCx<'a, 'tcx>) -> ValueRef {
+ pub fn len(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Value {
if let layout::FieldPlacement::Array { count, .. } = self.layout.fields {
if self.layout.is_unsized() {
- assert!(self.has_extra());
assert_eq!(count, 0);
- self.llextra
+ self.llextra.unwrap()
} else {
C_usize(cx, count)
}
}
}
- pub fn has_extra(&self) -> bool {
- !self.llextra.is_null()
- }
-
- pub fn load(&self, bx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> {
+ pub fn load(&self, bx: &Builder<'a, 'll, 'tcx>) -> OperandRef<'ll, 'tcx> {
debug!("PlaceRef::load: {:?}", self);
- assert!(!self.has_extra());
+ assert_eq!(self.llextra, None);
if self.layout.is_zst() {
return OperandRef::new_zst(bx.cx, self.layout);
};
let val = if self.layout.is_llvm_immediate() {
- let mut const_llval = ptr::null_mut();
+ let mut const_llval = None;
unsafe {
- let global = llvm::LLVMIsAGlobalVariable(self.llval);
- if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True {
- const_llval = llvm::LLVMGetInitializer(global);
+ if let Some(global) = llvm::LLVMIsAGlobalVariable(self.llval) {
+ if llvm::LLVMIsGlobalConstant(global) == llvm::True {
+ const_llval = llvm::LLVMGetInitializer(global);
+ }
}
}
-
- let llval = if !const_llval.is_null() {
- const_llval
- } else {
+ let llval = const_llval.unwrap_or_else(|| {
let load = bx.load(self.llval, self.align);
if let layout::Abi::Scalar(ref scalar) = self.layout.abi {
scalar_load_metadata(load, scalar);
}
load
- };
+ });
OperandValue::Immediate(base::to_immediate(bx, llval, self.layout))
} else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi {
let load = |i, scalar: &layout::Scalar| {
}
/// Access a field, at a point when the value's case is known.
- pub fn project_field(self, bx: &Builder<'a, 'tcx>, ix: usize) -> PlaceRef<'tcx> {
+ pub fn project_field(self, bx: &Builder<'a, 'll, 'tcx>, ix: usize) -> PlaceRef<'ll, 'tcx> {
let cx = bx.cx;
let field = self.layout.field(cx, ix);
let offset = self.layout.fields.offset(ix);
llextra: if cx.type_has_metadata(field.ty) {
self.llextra
} else {
- ptr::null_mut()
+ None
},
layout: field,
align,
// * known alignment - sized types, [T], str or a foreign type
// * packed struct - there is no alignment padding
match field.ty.sty {
- _ if !self.has_extra() => {
+ _ if self.llextra.is_none() => {
debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
- ix, Value(self.llval));
+ ix, self.llval);
return simple();
}
_ if !field.is_unsized() => return simple(),
let offset = bx.and(bx.add(unaligned_offset, align_sub_1),
bx.neg(unsized_align));
- debug!("struct_field_ptr: DST field offset: {:?}", Value(offset));
+ debug!("struct_field_ptr: DST field offset: {:?}", offset);
// Cast and adjust pointer
let byte_ptr = bx.pointercast(self.llval, Type::i8p(cx));
}
/// Obtain the actual discriminant of a value.
- pub fn codegen_get_discr(self, bx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef {
+ pub fn codegen_get_discr(self, bx: &Builder<'a, 'll, 'tcx>, cast_to: Ty<'tcx>) -> &'ll Value {
let cast_to = bx.cx.layout_of(cast_to).immediate_llvm_type(bx.cx);
if self.layout.abi == layout::Abi::Uninhabited {
return C_undef(cast_to);
/// Set the discriminant for a new value of the given case of the given
/// representation.
- pub fn codegen_set_discr(&self, bx: &Builder<'a, 'tcx>, variant_index: usize) {
+ pub fn codegen_set_discr(&self, bx: &Builder<'a, 'll, 'tcx>, variant_index: usize) {
if self.layout.for_variant(bx.cx, variant_index).abi == layout::Abi::Uninhabited {
return;
}
}
}
- pub fn project_index(&self, bx: &Builder<'a, 'tcx>, llindex: ValueRef)
- -> PlaceRef<'tcx> {
+ pub fn project_index(&self, bx: &Builder<'a, 'll, 'tcx>, llindex: &'ll Value)
+ -> PlaceRef<'ll, 'tcx> {
PlaceRef {
llval: bx.inbounds_gep(self.llval, &[C_usize(bx.cx, 0), llindex]),
- llextra: ptr::null_mut(),
+ llextra: None,
layout: self.layout.field(bx.cx, 0),
align: self.align
}
}
- pub fn project_downcast(&self, bx: &Builder<'a, 'tcx>, variant_index: usize)
- -> PlaceRef<'tcx> {
+ pub fn project_downcast(&self, bx: &Builder<'a, 'll, 'tcx>, variant_index: usize)
+ -> PlaceRef<'ll, 'tcx> {
let mut downcast = *self;
downcast.layout = self.layout.for_variant(bx.cx, variant_index);
downcast
}
- pub fn storage_live(&self, bx: &Builder<'a, 'tcx>) {
+ pub fn storage_live(&self, bx: &Builder<'a, 'll, 'tcx>) {
bx.lifetime_start(self.llval, self.layout.size);
}
- pub fn storage_dead(&self, bx: &Builder<'a, 'tcx>) {
+ pub fn storage_dead(&self, bx: &Builder<'a, 'll, 'tcx>) {
bx.lifetime_end(self.llval, self.layout.size);
}
}
-impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
+impl FunctionCx<'a, 'll, 'tcx> {
pub fn codegen_place(&mut self,
- bx: &Builder<'a, 'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
place: &mir::Place<'tcx>)
- -> PlaceRef<'tcx> {
+ -> PlaceRef<'ll, 'tcx> {
debug!("codegen_place(place={:?})", place);
let cx = bx.cx;
subslice.layout = bx.cx.layout_of(self.monomorphize(&projected_ty));
if subslice.layout.is_unsized() {
- assert!(cg_base.has_extra());
- subslice.llextra = bx.sub(cg_base.llextra,
- C_usize(bx.cx, (from as u64) + (to as u64)));
+ subslice.llextra = Some(bx.sub(cg_base.llextra.unwrap(),
+ C_usize(bx.cx, (from as u64) + (to as u64))));
}
// Cast the place pointer type to the new
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use llvm::{self, ValueRef};
+use llvm;
use rustc::ty::{self, Ty};
use rustc::ty::cast::{CastTy, IntTy};
use rustc::ty::layout::{self, LayoutOf};
use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef;
-impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
+impl FunctionCx<'a, 'll, 'tcx> {
pub fn codegen_rvalue(&mut self,
- bx: Builder<'a, 'tcx>,
- dest: PlaceRef<'tcx>,
+ bx: Builder<'a, 'll, 'tcx>,
+ dest: PlaceRef<'ll, 'tcx>,
rvalue: &mir::Rvalue<'tcx>)
- -> Builder<'a, 'tcx>
+ -> Builder<'a, 'll, 'tcx>
{
debug!("codegen_rvalue(dest.llval={:?}, rvalue={:?})",
- Value(dest.llval), rvalue);
+ dest.llval, rvalue);
match *rvalue {
mir::Rvalue::Use(ref operand) => {
}
pub fn codegen_rvalue_operand(&mut self,
- bx: Builder<'a, 'tcx>,
+ bx: Builder<'a, 'll, 'tcx>,
rvalue: &mir::Rvalue<'tcx>)
- -> (Builder<'a, 'tcx>, OperandRef<'tcx>)
+ -> (Builder<'a, 'll, 'tcx>, OperandRef<'ll, 'tcx>)
{
assert!(self.rvalue_creates_operand(rvalue), "cannot codegen {:?} to operand", rvalue);
let val = if !bx.cx.type_has_metadata(ty) {
OperandValue::Immediate(cg_place.llval)
} else {
- OperandValue::Pair(cg_place.llval, cg_place.llextra)
+ OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
};
(bx, OperandRef {
val,
}
}
- fn evaluate_array_len(&mut self,
- bx: &Builder<'a, 'tcx>,
- place: &mir::Place<'tcx>) -> ValueRef
- {
+ fn evaluate_array_len(
+ &mut self,
+ bx: &Builder<'a, 'll, 'tcx>,
+ place: &mir::Place<'tcx>,
+ ) -> &'ll Value {
// ZST are passed as operands and require special handling
// because codegen_place() panics if Local is operand.
if let mir::Place::Local(index) = *place {
return cg_value.len(bx.cx);
}
- pub fn codegen_scalar_binop(&mut self,
- bx: &Builder<'a, 'tcx>,
- op: mir::BinOp,
- lhs: ValueRef,
- rhs: ValueRef,
- input_ty: Ty<'tcx>) -> ValueRef {
+ pub fn codegen_scalar_binop(
+ &mut self,
+ bx: &Builder<'a, 'll, 'tcx>,
+ op: mir::BinOp,
+ lhs: &'ll Value,
+ rhs: &'ll Value,
+ input_ty: Ty<'tcx>,
+ ) -> &'ll Value {
let is_float = input_ty.is_fp();
let is_signed = input_ty.is_signed();
let is_nil = input_ty.is_nil();
}
}
- pub fn codegen_fat_ptr_binop(&mut self,
- bx: &Builder<'a, 'tcx>,
- op: mir::BinOp,
- lhs_addr: ValueRef,
- lhs_extra: ValueRef,
- rhs_addr: ValueRef,
- rhs_extra: ValueRef,
- _input_ty: Ty<'tcx>)
- -> ValueRef {
+ pub fn codegen_fat_ptr_binop(
+ &mut self,
+ bx: &Builder<'a, 'll, 'tcx>,
+ op: mir::BinOp,
+ lhs_addr: &'ll Value,
+ lhs_extra: &'ll Value,
+ rhs_addr: &'ll Value,
+ rhs_extra: &'ll Value,
+ _input_ty: Ty<'tcx>,
+ ) -> &'ll Value {
match op {
mir::BinOp::Eq => {
bx.and(
}
pub fn codegen_scalar_checked_binop(&mut self,
- bx: &Builder<'a, 'tcx>,
+ bx: &Builder<'a, 'll, 'tcx>,
op: mir::BinOp,
- lhs: ValueRef,
- rhs: ValueRef,
- input_ty: Ty<'tcx>) -> OperandValue {
+ lhs: &'ll Value,
+ rhs: &'ll Value,
+ input_ty: Ty<'tcx>) -> OperandValue<'ll> {
// This case can currently arise only from functions marked
// with #[rustc_inherit_overflow_checks] and inlined from
// another crate (mostly core::num generic/#[inline] fns),
Add, Sub, Mul
}
-fn get_overflow_intrinsic(oop: OverflowOp, bx: &Builder, ty: Ty) -> ValueRef {
+fn get_overflow_intrinsic(oop: OverflowOp, bx: &Builder<'_, 'll, '_>, ty: Ty) -> &'ll Value {
use syntax::ast::IntTy::*;
use syntax::ast::UintTy::*;
use rustc::ty::{TyInt, TyUint};
let tcx = bx.tcx();
let new_sty = match ty.sty {
- TyInt(Isize) => match &tcx.sess.target.target.target_pointer_width[..] {
- "16" => TyInt(I16),
- "32" => TyInt(I32),
- "64" => TyInt(I64),
- _ => panic!("unsupported target word size")
- },
- TyUint(Usize) => match &tcx.sess.target.target.target_pointer_width[..] {
- "16" => TyUint(U16),
- "32" => TyUint(U32),
- "64" => TyUint(U64),
- _ => panic!("unsupported target word size")
- },
+ TyInt(Isize) => TyInt(tcx.sess.target.isize_ty),
+ TyUint(Usize) => TyUint(tcx.sess.target.usize_ty),
ref t @ TyUint(_) | ref t @ TyInt(_) => t.clone(),
_ => panic!("tried to get overflow intrinsic for op applied to non-int type")
};
bx.cx.get_intrinsic(&name)
}
-fn cast_int_to_float(bx: &Builder,
+fn cast_int_to_float(bx: &Builder<'_, 'll, '_>,
signed: bool,
- x: ValueRef,
- int_ty: Type,
- float_ty: Type) -> ValueRef {
+ x: &'ll Value,
+ int_ty: &'ll Type,
+ float_ty: &'ll Type) -> &'ll Value {
// Most integer types, even i128, fit into [-f32::MAX, f32::MAX] after rounding.
// It's only u128 -> f32 that can cause overflows (i.e., should yield infinity).
// LLVM's uitofp produces undef in those cases, so we manually check for that case.
}
}
-fn cast_float_to_int(bx: &Builder,
+fn cast_float_to_int(bx: &Builder<'_, 'll, '_>,
signed: bool,
- x: ValueRef,
- float_ty: Type,
- int_ty: Type) -> ValueRef {
+ x: &'ll Value,
+ float_ty: &'ll Type,
+ int_ty: &'ll Type) -> &'ll Value {
let fptosui_result = if signed {
bx.fptosi(x, int_ty)
} else {
// On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
// we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
// This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
- fn compute_clamp_bounds<F: Float>(signed: bool, int_ty: Type) -> (u128, u128) {
+ fn compute_clamp_bounds<F: Float>(signed: bool, int_ty: &Type) -> (u128, u128) {
let rounded_min = F::from_i128_r(int_min(signed, int_ty), Round::TowardZero);
assert_eq!(rounded_min.status, Status::OK);
let rounded_max = F::from_u128_r(int_max(signed, int_ty), Round::TowardZero);
assert!(rounded_max.value.is_finite());
(rounded_min.value.to_bits(), rounded_max.value.to_bits())
}
- fn int_max(signed: bool, int_ty: Type) -> u128 {
+ fn int_max(signed: bool, int_ty: &Type) -> u128 {
let shift_amount = 128 - int_ty.int_width();
if signed {
i128::MAX as u128 >> shift_amount
u128::MAX >> shift_amount
}
}
- fn int_min(signed: bool, int_ty: Type) -> i128 {
+ fn int_min(signed: bool, int_ty: &Type) -> i128 {
if signed {
i128::MIN >> (128 - int_ty.int_width())
} else {
use super::FunctionCx;
use super::LocalRef;
-impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
+impl FunctionCx<'a, 'll, 'tcx> {
pub fn codegen_statement(&mut self,
- bx: Builder<'a, 'tcx>,
+ bx: Builder<'a, 'll, 'tcx>,
statement: &mir::Statement<'tcx>)
- -> Builder<'a, 'tcx> {
+ -> Builder<'a, 'll, 'tcx> {
debug!("codegen_statement(statement={:?})", statement);
self.set_debug_loc(&bx, statement.source_info);
#![allow(non_upper_case_globals)]
+pub use llvm::Type;
+
use llvm;
-use llvm::{ContextRef, TypeRef, Bool, False, True, TypeKind};
-use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
+use llvm::{Bool, False, True, TypeKind};
use context::CodegenCx;
use std::ffi::CString;
use std::fmt;
-use std::mem;
-use std::ptr;
use libc::c_uint;
-#[derive(Clone, Copy, PartialEq)]
-#[repr(C)]
-pub struct Type {
- rf: TypeRef
+impl PartialEq for Type {
+ fn eq(&self, other: &Self) -> bool {
+ self as *const _ == other as *const _
+ }
}
impl fmt::Debug for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&llvm::build_string(|s| unsafe {
- llvm::LLVMRustWriteTypeToString(self.to_ref(), s);
+ llvm::LLVMRustWriteTypeToString(self, s);
}).expect("non-UTF8 type description from LLVM"))
}
}
-macro_rules! ty {
- ($e:expr) => ( Type::from_ref(unsafe { $e }))
-}
-
-/// Wrapper for LLVM TypeRef
impl Type {
- #[inline(always)]
- pub fn from_ref(r: TypeRef) -> Type {
- Type {
- rf: r
+ pub fn void(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMVoidTypeInContext(cx.llcx)
}
}
- #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
- pub fn to_ref(&self) -> TypeRef {
- self.rf
- }
-
- pub fn to_ref_slice(slice: &[Type]) -> &[TypeRef] {
- unsafe { mem::transmute(slice) }
- }
-
- pub fn void(cx: &CodegenCx) -> Type {
- ty!(llvm::LLVMVoidTypeInContext(cx.llcx))
+ pub fn metadata(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMRustMetadataTypeInContext(cx.llcx)
+ }
}
- pub fn metadata(cx: &CodegenCx) -> Type {
- ty!(llvm::LLVMRustMetadataTypeInContext(cx.llcx))
+ pub fn i1(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMInt1TypeInContext(cx.llcx)
+ }
}
- pub fn i1(cx: &CodegenCx) -> Type {
- ty!(llvm::LLVMInt1TypeInContext(cx.llcx))
+ pub fn i8(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMInt8TypeInContext(cx.llcx)
+ }
}
- pub fn i8(cx: &CodegenCx) -> Type {
- ty!(llvm::LLVMInt8TypeInContext(cx.llcx))
+ pub fn i8_llcx(llcx: &llvm::Context) -> &Type {
+ unsafe {
+ llvm::LLVMInt8TypeInContext(llcx)
+ }
}
- pub fn i8_llcx(llcx: ContextRef) -> Type {
- ty!(llvm::LLVMInt8TypeInContext(llcx))
+ pub fn i16(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMInt16TypeInContext(cx.llcx)
+ }
}
- pub fn i16(cx: &CodegenCx) -> Type {
- ty!(llvm::LLVMInt16TypeInContext(cx.llcx))
+ pub fn i32(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMInt32TypeInContext(cx.llcx)
+ }
}
- pub fn i32(cx: &CodegenCx) -> Type {
- ty!(llvm::LLVMInt32TypeInContext(cx.llcx))
+ pub fn i64(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMInt64TypeInContext(cx.llcx)
+ }
}
- pub fn i64(cx: &CodegenCx) -> Type {
- ty!(llvm::LLVMInt64TypeInContext(cx.llcx))
+ pub fn i128(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMIntTypeInContext(cx.llcx, 128)
+ }
}
- pub fn i128(cx: &CodegenCx) -> Type {
- ty!(llvm::LLVMIntTypeInContext(cx.llcx, 128))
+ // Creates an integer type with the given number of bits, e.g. i24
+ pub fn ix(cx: &CodegenCx<'ll, '_>, num_bits: u64) -> &'ll Type {
+ unsafe {
+ llvm::LLVMIntTypeInContext(cx.llcx, num_bits as c_uint)
+ }
}
// Creates an integer type with the given number of bits, e.g. i24
- pub fn ix(cx: &CodegenCx, num_bits: u64) -> Type {
- ty!(llvm::LLVMIntTypeInContext(cx.llcx, num_bits as c_uint))
+ pub fn ix_llcx(llcx: &llvm::Context, num_bits: u64) -> &Type {
+ unsafe {
+ llvm::LLVMIntTypeInContext(llcx, num_bits as c_uint)
+ }
}
- pub fn f32(cx: &CodegenCx) -> Type {
- ty!(llvm::LLVMFloatTypeInContext(cx.llcx))
+ pub fn f32(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMFloatTypeInContext(cx.llcx)
+ }
}
- pub fn f64(cx: &CodegenCx) -> Type {
- ty!(llvm::LLVMDoubleTypeInContext(cx.llcx))
+ pub fn f64(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMDoubleTypeInContext(cx.llcx)
+ }
}
- pub fn bool(cx: &CodegenCx) -> Type {
+ pub fn bool(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
Type::i8(cx)
}
- pub fn char(cx: &CodegenCx) -> Type {
+ pub fn char(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
Type::i32(cx)
}
- pub fn i8p(cx: &CodegenCx) -> Type {
+ pub fn i8p(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
Type::i8(cx).ptr_to()
}
- pub fn i8p_llcx(llcx: ContextRef) -> Type {
+ pub fn i8p_llcx(llcx: &llvm::Context) -> &Type {
Type::i8_llcx(llcx).ptr_to()
}
- pub fn isize(cx: &CodegenCx) -> Type {
- match &cx.tcx.sess.target.target.target_pointer_width[..] {
- "16" => Type::i16(cx),
- "32" => Type::i32(cx),
- "64" => Type::i64(cx),
- tws => bug!("Unsupported target word size for int: {}", tws),
- }
+ pub fn isize(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ cx.isize_ty
}
- pub fn c_int(cx: &CodegenCx) -> Type {
+ pub fn c_int(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
match &cx.tcx.sess.target.target.target_c_int_width[..] {
"16" => Type::i16(cx),
"32" => Type::i32(cx),
}
}
- pub fn int_from_ty(cx: &CodegenCx, t: ast::IntTy) -> Type {
+ pub fn int_from_ty(cx: &CodegenCx<'ll, '_>, t: ast::IntTy) -> &'ll Type {
match t {
ast::IntTy::Isize => cx.isize_ty,
ast::IntTy::I8 => Type::i8(cx),
}
}
- pub fn uint_from_ty(cx: &CodegenCx, t: ast::UintTy) -> Type {
+ pub fn uint_from_ty(cx: &CodegenCx<'ll, '_>, t: ast::UintTy) -> &'ll Type {
match t {
ast::UintTy::Usize => cx.isize_ty,
ast::UintTy::U8 => Type::i8(cx),
}
}
- pub fn float_from_ty(cx: &CodegenCx, t: ast::FloatTy) -> Type {
+ pub fn float_from_ty(cx: &CodegenCx<'ll, '_>, t: ast::FloatTy) -> &'ll Type {
match t {
ast::FloatTy::F32 => Type::f32(cx),
ast::FloatTy::F64 => Type::f64(cx),
}
}
- pub fn func(args: &[Type], ret: &Type) -> Type {
- let slice: &[TypeRef] = Type::to_ref_slice(args);
- ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
- args.len() as c_uint, False))
+ pub fn func(args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
+ unsafe {
+ llvm::LLVMFunctionType(ret, args.as_ptr(),
+ args.len() as c_uint, False)
+ }
}
- pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
- let slice: &[TypeRef] = Type::to_ref_slice(args);
- ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
- args.len() as c_uint, True))
+ pub fn variadic_func(args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
+ unsafe {
+ llvm::LLVMFunctionType(ret, args.as_ptr(),
+ args.len() as c_uint, True)
+ }
}
- pub fn struct_(cx: &CodegenCx, els: &[Type], packed: bool) -> Type {
- let els: &[TypeRef] = Type::to_ref_slice(els);
- ty!(llvm::LLVMStructTypeInContext(cx.llcx, els.as_ptr(),
+ pub fn struct_(cx: &CodegenCx<'ll, '_>, els: &[&'ll Type], packed: bool) -> &'ll Type {
+ unsafe {
+ llvm::LLVMStructTypeInContext(cx.llcx, els.as_ptr(),
els.len() as c_uint,
- packed as Bool))
+ packed as Bool)
+ }
}
- pub fn named_struct(cx: &CodegenCx, name: &str) -> Type {
+ pub fn named_struct(cx: &CodegenCx<'ll, '_>, name: &str) -> &'ll Type {
let name = CString::new(name).unwrap();
- ty!(llvm::LLVMStructCreateNamed(cx.llcx, name.as_ptr()))
+ unsafe {
+ llvm::LLVMStructCreateNamed(cx.llcx, name.as_ptr())
+ }
}
- pub fn array(ty: &Type, len: u64) -> Type {
- ty!(llvm::LLVMRustArrayType(ty.to_ref(), len))
+ pub fn array(ty: &Type, len: u64) -> &Type {
+ unsafe {
+ llvm::LLVMRustArrayType(ty, len)
+ }
}
- pub fn vector(ty: &Type, len: u64) -> Type {
- ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
+ pub fn vector(ty: &Type, len: u64) -> &Type {
+ unsafe {
+ llvm::LLVMVectorType(ty, len as c_uint)
+ }
}
pub fn kind(&self) -> TypeKind {
unsafe {
- llvm::LLVMRustGetTypeKind(self.to_ref())
+ llvm::LLVMRustGetTypeKind(self)
}
}
- pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
- let slice: &[TypeRef] = Type::to_ref_slice(els);
+ pub fn set_struct_body(&'ll self, els: &[&'ll Type], packed: bool) {
unsafe {
- llvm::LLVMStructSetBody(self.to_ref(), slice.as_ptr(),
+ llvm::LLVMStructSetBody(self, els.as_ptr(),
els.len() as c_uint, packed as Bool)
}
}
- pub fn ptr_to(&self) -> Type {
- ty!(llvm::LLVMPointerType(self.to_ref(), 0))
+ pub fn ptr_to(&self) -> &Type {
+ unsafe {
+ llvm::LLVMPointerType(self, 0)
+ }
}
- pub fn element_type(&self) -> Type {
+ pub fn element_type(&self) -> &Type {
unsafe {
- Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
+ llvm::LLVMGetElementType(self)
}
}
/// Return the number of elements in `self` if it is a LLVM vector type.
pub fn vector_length(&self) -> usize {
unsafe {
- llvm::LLVMGetVectorSize(self.to_ref()) as usize
+ llvm::LLVMGetVectorSize(self) as usize
}
}
- pub fn func_params(&self) -> Vec<Type> {
+ pub fn func_params(&self) -> Vec<&Type> {
unsafe {
- let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as usize;
- let mut args = vec![Type { rf: ptr::null_mut() }; n_args];
- llvm::LLVMGetParamTypes(self.to_ref(),
- args.as_mut_ptr() as *mut TypeRef);
+ let n_args = llvm::LLVMCountParamTypes(self) as usize;
+ let mut args = Vec::with_capacity(n_args);
+ llvm::LLVMGetParamTypes(self, args.as_mut_ptr());
+ args.set_len(n_args);
args
}
}
pub fn float_width(&self) -> usize {
match self.kind() {
- Float => 32,
- Double => 64,
- X86_FP80 => 80,
- FP128 | PPC_FP128 => 128,
+ TypeKind::Float => 32,
+ TypeKind::Double => 64,
+ TypeKind::X86_FP80 => 80,
+ TypeKind::FP128 | TypeKind::PPC_FP128 => 128,
_ => bug!("llvm_float_width called on a non-float type")
}
}
/// Retrieve the bit width of the integer type `self`.
pub fn int_width(&self) -> u64 {
unsafe {
- llvm::LLVMGetIntTypeWidth(self.to_ref()) as u64
+ llvm::LLVMGetIntTypeWidth(self) as u64
}
}
- pub fn from_integer(cx: &CodegenCx, i: layout::Integer) -> Type {
+ pub fn from_integer(cx: &CodegenCx<'ll, '_>, i: layout::Integer) -> &'ll Type {
use rustc::ty::layout::Integer::*;
match i {
I8 => Type::i8(cx),
/// Return a LLVM type that has at most the required alignment,
/// as a conservative approximation for unknown pointee types.
- pub fn pointee_for_abi_align(cx: &CodegenCx, align: Align) -> Type {
+ pub fn pointee_for_abi_align(cx: &CodegenCx<'ll, '_>, align: Align) -> &'ll Type {
// FIXME(eddyb) We could find a better approximation if ity.align < align.
let ity = layout::Integer::approximate_abi_align(cx, align);
Type::from_integer(cx, ity)
/// Return a LLVM type that has at most the required alignment,
/// and exactly the required size, as a best-effort padding array.
- pub fn padding_filler(cx: &CodegenCx, size: Size, align: Align) -> Type {
+ pub fn padding_filler(cx: &CodegenCx<'ll, '_>, size: Size, align: Align) -> &'ll Type {
let unit = layout::Integer::approximate_abi_align(cx, align);
let size = size.bytes();
let unit_size = unit.size().bytes();
assert_eq!(size % unit_size, 0);
- Type::array(&Type::from_integer(cx, unit), size / unit_size)
+ Type::array(Type::from_integer(cx, unit), size / unit_size)
}
- pub fn x86_mmx(cx: &CodegenCx) -> Type {
- ty!(llvm::LLVMX86MMXTypeInContext(cx.llcx))
+ pub fn x86_mmx(cx: &CodegenCx<'ll, '_>) -> &'ll Type {
+ unsafe {
+ llvm::LLVMX86MMXTypeInContext(cx.llcx)
+ }
}
}
fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
layout: TyLayout<'tcx>,
- defer: &mut Option<(Type, TyLayout<'tcx>)>)
- -> Type {
+ defer: &mut Option<(&'a Type, TyLayout<'tcx>)>)
+ -> &'a Type {
match layout.abi {
layout::Abi::Scalar(_) => bug!("handled elsewhere"),
layout::Abi::Vector { ref element, count } => {
return Type::x86_mmx(cx)
} else {
let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO);
- return Type::vector(&element, count);
+ return Type::vector(element, count);
}
}
layout::Abi::ScalarPair(..) => {
}
}
layout::FieldPlacement::Array { count, .. } => {
- Type::array(&layout.field(cx, 0).llvm_type(cx), count)
+ Type::array(layout.field(cx, 0).llvm_type(cx), count)
}
layout::FieldPlacement::Arbitrary { .. } => {
match name {
fn struct_llfields<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
layout: TyLayout<'tcx>)
- -> (Vec<Type>, bool) {
+ -> (Vec<&'a Type>, bool) {
debug!("struct_llfields: {:#?}", layout);
let field_count = layout.fields.count();
let mut packed = false;
let mut offset = Size::ZERO;
let mut prev_align = layout.align;
- let mut result: Vec<Type> = Vec::with_capacity(1 + field_count * 2);
+ let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2);
for i in layout.fields.index_by_increasing_offset() {
let field = layout.field(cx, i);
packed |= layout.align.abi() < field.align.abi();
pub trait LayoutLlvmExt<'tcx> {
fn is_llvm_immediate(&self) -> bool;
fn is_llvm_scalar_pair<'a>(&self) -> bool;
- fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type;
- fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type;
+ fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type;
+ fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type;
fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>,
- scalar: &layout::Scalar, offset: Size) -> Type;
+ scalar: &layout::Scalar, offset: Size) -> &'a Type;
fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>,
- index: usize, immediate: bool) -> Type;
+ index: usize, immediate: bool) -> &'a Type;
fn llvm_field_index(&self, index: usize) -> u64;
fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size)
-> Option<PointeeInfo>;
/// with the inner-most trailing unsized field using the "minimal unit"
/// of that field's type - this is useful for taking the address of
/// that field and ensuring the struct has the right alignment.
- fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type {
+ fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type {
if let layout::Abi::Scalar(ref scalar) = self.abi {
// Use a different cache for scalars because pointers to DSTs
// can be either fat or thin (data pointers of fat pointers).
cx.lltypes.borrow_mut().insert((self.ty, variant_index), llty);
- if let Some((mut llty, layout)) = defer {
+ if let Some((llty, layout)) = defer {
let (llfields, packed) = struct_llfields(cx, layout);
llty.set_struct_body(&llfields, packed)
}
llty
}
- fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type {
+ fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type {
if let layout::Abi::Scalar(ref scalar) = self.abi {
if scalar.is_bool() {
return Type::i1(cx);
}
fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>,
- scalar: &layout::Scalar, offset: Size) -> Type {
+ scalar: &layout::Scalar, offset: Size) -> &'a Type {
match scalar.value {
layout::Int(i, _) => Type::from_integer(cx, i),
layout::Float(FloatTy::F32) => Type::f32(cx),
}
fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>,
- index: usize, immediate: bool) -> Type {
+ index: usize, immediate: bool) -> &'a Type {
// HACK(eddyb) special-case fat pointers until LLVM removes
// pointee types, to avoid bitcasting every `OperandRef::deref`.
match self.ty.sty {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+pub use llvm::Value;
+
use llvm;
use std::fmt;
+use std::hash::{Hash, Hasher};
+
+impl PartialEq for Value {
+ fn eq(&self, other: &Self) -> bool {
+ self as *const _ == other as *const _
+ }
+}
+
+impl Eq for Value {}
+
+impl Hash for Value {
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ (self as *const Self).hash(hasher);
+ }
+}
-#[derive(Copy, Clone, PartialEq)]
-pub struct Value(pub llvm::ValueRef);
impl fmt::Debug for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&llvm::build_string(|s| unsafe {
- llvm::LLVMRustWriteValueToString(self.0, s);
+ llvm::LLVMRustWriteValueToString(self, s);
}).expect("nun-UTF8 value description from LLVM"))
}
}
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_mir = { path = "../librustc_mir" }
rustc_incremental = { path = "../librustc_incremental" }
+rustc_metadata_utils = { path = "../librustc_metadata_utils" }
fn init(&self, sess: &Session) {
for cty in sess.opts.crate_types.iter() {
match *cty {
- CrateType::CrateTypeRlib | CrateType::CrateTypeDylib |
- CrateType::CrateTypeExecutable => {},
+ CrateType::Rlib | CrateType::Dylib | CrateType::Executable => {},
_ => {
- sess.parse_sess.span_diagnostic.warn(
+ sess.diagnostic().warn(
&format!("LLVM unsupported, so output type {} is not supported", cty)
);
},
let ongoing_codegen = ongoing_codegen.downcast::<OngoingCodegen>()
.expect("Expected MetadataOnlyCodegenBackend's OngoingCodegen, found Box<dyn Any>");
for &crate_type in sess.opts.crate_types.iter() {
- if crate_type != CrateType::CrateTypeRlib && crate_type != CrateType::CrateTypeDylib {
+ if crate_type != CrateType::Rlib &&
+ crate_type != CrateType::Dylib {
continue;
}
let output_name =
out_filename(sess, crate_type, &outputs, &ongoing_codegen.crate_name.as_str());
let mut compressed = ongoing_codegen.metadata_version.clone();
- let metadata = if crate_type == CrateType::CrateTypeDylib {
+ let metadata = if crate_type == CrateType::Dylib {
DeflateEncoder::new(&mut compressed, Compression::fast())
.write_all(&ongoing_codegen.metadata.raw_data)
.unwrap();
}
sess.abort_if_errors();
- if !sess.opts.crate_types.contains(&CrateType::CrateTypeRlib)
- && !sess.opts.crate_types.contains(&CrateType::CrateTypeDylib)
+ if !sess.opts.crate_types.contains(&CrateType::Rlib)
+ && !sess.opts.crate_types.contains(&CrateType::Dylib)
{
sess.fatal("Executables are not supported by the metadata-only backend.");
}
extern crate syntax;
extern crate syntax_pos;
#[macro_use] extern crate rustc_data_structures;
+extern crate rustc_metadata_utils;
use rustc::ty::TyCtxt;
use rustc::session::config::{self, OutputFilenames, Input, OutputType};
use rustc::session::Session;
-use rustc::middle::cstore::{self, LinkMeta};
+use rustc::middle::cstore::LinkMeta;
use rustc::hir::svh::Svh;
use std::path::{Path, PathBuf};
use syntax::{ast, attr};
use syntax_pos::Span;
+use rustc_metadata_utils::validate_crate_name;
pub fn out_filename(sess: &Session,
crate_type: config::CrateType,
attrs: &[ast::Attribute],
input: &Input) -> String {
let validate = |s: String, span: Option<Span>| {
- cstore::validate_crate_name(sess, &s, span);
+ validate_crate_name(sess, &s, span);
s
};
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
match crate_type {
- config::CrateTypeRlib => {
+ config::CrateType::Rlib => {
outputs.out_directory.join(&format!("lib{}.rlib", libname))
}
- config::CrateTypeCdylib |
- config::CrateTypeProcMacro |
- config::CrateTypeDylib => {
+ config::CrateType::Cdylib |
+ config::CrateType::ProcMacro |
+ config::CrateType::Dylib => {
let (prefix, suffix) = (&sess.target.target.options.dll_prefix,
&sess.target.target.options.dll_suffix);
outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
suffix))
}
- config::CrateTypeStaticlib => {
+ config::CrateType::Staticlib => {
let (prefix, suffix) = (&sess.target.target.options.staticlib_prefix,
&sess.target.target.options.staticlib_suffix);
outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
suffix))
}
- config::CrateTypeExecutable => {
+ config::CrateType::Executable => {
let suffix = &sess.target.target.options.exe_suffix;
let out_filename = outputs.path(OutputType::Exe);
if suffix.is_empty() {
/// Default crate type is used when crate type isn't provided neither
/// through cmd line arguments nor through crate attributes
///
-/// It is CrateTypeExecutable for all platforms but iOS as there is no
+/// It is CrateType::Executable for all platforms but iOS as there is no
/// way to run iOS binaries anyway without jailbreaking and
/// interaction with Rust code through static library is the only
/// option for now
pub fn default_output_for_target(sess: &Session) -> config::CrateType {
if !sess.target.target.options.executables {
- config::CrateTypeStaticlib
+ config::CrateType::Staticlib
} else {
- config::CrateTypeExecutable
+ config::CrateType::Executable
}
}
pub fn invalid_output_for_target(sess: &Session,
crate_type: config::CrateType) -> bool {
match crate_type {
- config::CrateTypeCdylib |
- config::CrateTypeDylib |
- config::CrateTypeProcMacro => {
+ config::CrateType::Cdylib |
+ config::CrateType::Dylib |
+ config::CrateType::ProcMacro => {
if !sess.target.target.options.dynamic_linking {
return true
}
}
if sess.target.target.options.only_cdylib {
match crate_type {
- config::CrateTypeProcMacro | config::CrateTypeDylib => return true,
+ config::CrateType::ProcMacro | config::CrateType::Dylib => return true,
_ => {}
}
}
if !sess.target.target.options.executables {
- if crate_type == config::CrateTypeExecutable {
+ if crate_type == config::CrateType::Executable {
return true
}
}
if avoid_cross_crate_conflicts {
let instantiating_crate = if is_generic {
- if !def_id.is_local() && tcx.share_generics() {
+ if !def_id.is_local() && tcx.sess.opts.share_generics() {
// If we are re-using a monomorphization from another crate,
// we have to compute the symbol hash accordingly.
let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id);
// except according to those terms.
use indexed_vec::{Idx, IndexVec};
-use std::iter::FromIterator;
use std::marker::PhantomData;
type Word = u128;
const WORD_BITS: usize = 128;
-/// A very simple BitVector type.
+/// A very simple BitArray type.
+///
+/// It does not support resizing after creation; use `BitVector` for that.
#[derive(Clone, Debug, PartialEq)]
-pub struct BitVector<C: Idx> {
+pub struct BitArray<C: Idx> {
data: Vec<Word>,
marker: PhantomData<C>,
}
+#[derive(Clone, Debug, PartialEq)]
+pub struct BitVector<C: Idx> {
+ data: BitArray<C>,
+}
+
impl<C: Idx> BitVector<C> {
+ pub fn grow(&mut self, num_bits: C) {
+ self.data.grow(num_bits)
+ }
+
+ pub fn new() -> BitVector<C> {
+ BitVector {
+ data: BitArray::new(0),
+ }
+ }
+
+ pub fn with_capacity(bits: usize) -> BitVector<C> {
+ BitVector {
+ data: BitArray::new(bits),
+ }
+ }
+
+ /// Returns true if the bit has changed.
+ #[inline]
+ pub fn insert(&mut self, bit: C) -> bool {
+ self.grow(bit);
+ self.data.insert(bit)
+ }
+
#[inline]
- pub fn new(num_bits: usize) -> BitVector<C> {
+ pub fn contains(&self, bit: C) -> bool {
+ let (word, mask) = word_mask(bit);
+ if let Some(word) = self.data.data.get(word) {
+ (word & mask) != 0
+ } else {
+ false
+ }
+ }
+}
+
+impl<C: Idx> BitArray<C> {
+ // Do not make this method public, instead switch your use case to BitVector.
+ #[inline]
+ fn grow(&mut self, num_bits: C) {
let num_words = words(num_bits);
- BitVector {
+ if self.data.len() <= num_words {
+ self.data.resize(num_words + 1, 0)
+ }
+ }
+
+ #[inline]
+ pub fn new(num_bits: usize) -> BitArray<C> {
+ let num_words = words(num_bits);
+ BitArray {
data: vec![0; num_words],
marker: PhantomData,
}
///
/// The two vectors must have the same length.
#[inline]
- pub fn contains_all(&self, other: &BitVector<C>) -> bool {
+ pub fn contains_all(&self, other: &BitArray<C>) -> bool {
assert_eq!(self.data.len(), other.data.len());
self.data.iter().zip(&other.data).all(|(a, b)| (a & b) == *b)
}
}
#[inline]
- pub fn merge(&mut self, all: &BitVector<C>) -> bool {
+ pub fn merge(&mut self, all: &BitArray<C>) -> bool {
assert!(self.data.len() == all.data.len());
let mut changed = false;
for (i, j) in self.data.iter_mut().zip(&all.data) {
changed
}
- #[inline]
- pub fn grow(&mut self, num_bits: C) {
- let num_words = words(num_bits);
- if self.data.len() < num_words {
- self.data.resize(num_words, 0)
- }
- }
-
/// Iterates over indexes of set bits in a sorted order
#[inline]
- pub fn iter<'a>(&'a self) -> BitVectorIter<'a, C> {
- BitVectorIter {
+ pub fn iter<'a>(&'a self) -> BitIter<'a, C> {
+ BitIter {
iter: self.data.iter(),
current: 0,
idx: 0,
}
}
-pub struct BitVectorIter<'a, C: Idx> {
+pub struct BitIter<'a, C: Idx> {
iter: ::std::slice::Iter<'a, Word>,
current: Word,
idx: usize,
marker: PhantomData<C>
}
-impl<'a, C: Idx> Iterator for BitVectorIter<'a, C> {
+impl<'a, C: Idx> Iterator for BitIter<'a, C> {
type Item = C;
fn next(&mut self) -> Option<C> {
while self.current == 0 {
}
}
-impl<C: Idx> FromIterator<bool> for BitVector<C> {
- fn from_iter<I>(iter: I) -> BitVector<C>
- where
- I: IntoIterator<Item = bool>,
- {
- let iter = iter.into_iter();
- let (len, _) = iter.size_hint();
- // Make the minimum length for the bitvector WORD_BITS bits since that's
- // the smallest non-zero size anyway.
- let len = if len < WORD_BITS { WORD_BITS } else { len };
- let mut bv = BitVector::new(len);
- for (idx, val) in iter.enumerate() {
- if idx > len {
- bv.grow(C::new(idx));
- }
- if val {
- bv.insert(C::new(idx));
- }
- }
-
- bv
- }
-}
-
/// A "bit matrix" is basically a matrix of booleans represented as
/// one gigantic bitvector. In other words, it is as if you have
/// `rows` bitvectors, each of length `columns`.
/// Iterates through all the columns set to true in a given row of
/// the matrix.
- pub fn iter<'a>(&'a self, row: R) -> BitVectorIter<'a, C> {
+ pub fn iter<'a>(&'a self, row: R) -> BitIter<'a, C> {
let (start, end) = self.range(row);
- BitVectorIter {
+ BitIter {
iter: self.vector[start..end].iter(),
current: 0,
idx: 0,
C: Idx,
{
columns: usize,
- vector: IndexVec<R, BitVector<C>>,
+ vector: IndexVec<R, BitArray<C>>,
}
impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
fn ensure_row(&mut self, row: R) {
let columns = self.columns;
self.vector
- .ensure_contains_elem(row, || BitVector::new(columns));
+ .ensure_contains_elem(row, || BitArray::new(columns));
}
/// Sets the cell at `(row, column)` to true. Put another way, insert
}
/// Merge a row, `from`, into the `into` row.
- pub fn merge_into(&mut self, into: R, from: &BitVector<C>) -> bool {
+ pub fn merge_into(&mut self, into: R, from: &BitArray<C>) -> bool {
self.ensure_row(into);
self.vector[into].merge(from)
}
}
/// Iterates through each row and the accompanying bit set.
- pub fn iter_enumerated<'a>(&'a self) -> impl Iterator<Item = (R, &'a BitVector<C>)> + 'a {
+ pub fn iter_enumerated<'a>(&'a self) -> impl Iterator<Item = (R, &'a BitArray<C>)> + 'a {
self.vector.iter_enumerated()
}
- pub fn row(&self, row: R) -> Option<&BitVector<C>> {
+ pub fn row(&self, row: R) -> Option<&BitArray<C>> {
self.vector.get(row)
}
}
#[test]
fn bitvec_iter_works() {
- let mut bitvec: BitVector<usize> = BitVector::new(100);
+ let mut bitvec: BitArray<usize> = BitArray::new(100);
bitvec.insert(1);
bitvec.insert(10);
bitvec.insert(19);
#[test]
fn bitvec_iter_works_2() {
- let mut bitvec: BitVector<usize> = BitVector::new(319);
+ let mut bitvec: BitArray<usize> = BitArray::new(319);
bitvec.insert(0);
bitvec.insert(127);
bitvec.insert(191);
#[test]
fn union_two_vecs() {
- let mut vec1: BitVector<usize> = BitVector::new(65);
- let mut vec2: BitVector<usize> = BitVector::new(65);
+ let mut vec1: BitArray<usize> = BitArray::new(65);
+ let mut vec2: BitArray<usize> = BitArray::new(65);
assert!(vec1.insert(3));
assert!(!vec1.insert(3));
assert!(vec2.insert(5));
#[test]
fn grow() {
- let mut vec1: BitVector<usize> = BitVector::new(65);
+ let mut vec1: BitVector<usize> = BitVector::with_capacity(65);
for index in 0..65 {
assert!(vec1.insert(index));
assert!(!vec1.insert(index));
//! the field `next_edge`). Each of those fields is an array that should
//! be indexed by the direction (see the type `Direction`).
-use bitvec::BitVector;
+use bitvec::BitArray;
use std::fmt::Debug;
use std::usize;
use snapshot_vec::{SnapshotVec, SnapshotVecDelegate};
direction: Direction,
entry_node: NodeIndex,
) -> Vec<NodeIndex> {
- let mut visited = BitVector::new(self.len_nodes());
+ let mut visited = BitArray::new(self.len_nodes());
let mut stack = vec![];
let mut result = Vec::with_capacity(self.len_nodes());
let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| {
{
graph: &'g Graph<N, E>,
stack: Vec<NodeIndex>,
- visited: BitVector<usize>,
+ visited: BitArray<usize>,
direction: Direction,
}
start_node: NodeIndex,
direction: Direction,
) -> Self {
- let mut visited = BitVector::new(graph.len_nodes());
+ let mut visited = BitArray::new(graph.len_nodes());
visited.insert(start_node.node_id());
DepthFirstTraversal {
graph,
fn extend<I: IntoIterator<Item=A::Element>>(&mut self, iter: I) {
let iter = iter.into_iter();
self.reserve(iter.size_hint().0);
- for el in iter {
- self.push(el);
+ match self.0 {
+ AccumulateVec::Heap(ref mut vec) => vec.extend(iter),
+ _ => iter.for_each(|el| self.push(el))
}
}
}
})
}
}
+
+#[cfg(test)]
+mod tests {
+ extern crate test;
+ use self::test::Bencher;
+
+ use super::*;
+
+ #[bench]
+ fn fill_small_vec_1_10_with_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 1]> = SmallVec::with_capacity(10);
+
+ sv.extend(0..10);
+ })
+ }
+
+ #[bench]
+ fn fill_small_vec_1_10_wo_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 1]> = SmallVec::new();
+
+ sv.extend(0..10);
+ })
+ }
+
+ #[bench]
+ fn fill_small_vec_8_10_with_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 8]> = SmallVec::with_capacity(10);
+
+ sv.extend(0..10);
+ })
+ }
+
+ #[bench]
+ fn fill_small_vec_8_10_wo_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 8]> = SmallVec::new();
+
+ sv.extend(0..10);
+ })
+ }
+
+ #[bench]
+ fn fill_small_vec_32_10_with_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 32]> = SmallVec::with_capacity(10);
+
+ sv.extend(0..10);
+ })
+ }
+
+ #[bench]
+ fn fill_small_vec_32_10_wo_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 32]> = SmallVec::new();
+
+ sv.extend(0..10);
+ })
+ }
+
+ #[bench]
+ fn fill_small_vec_1_50_with_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 1]> = SmallVec::with_capacity(50);
+
+ sv.extend(0..50);
+ })
+ }
+
+ #[bench]
+ fn fill_small_vec_1_50_wo_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 1]> = SmallVec::new();
+
+ sv.extend(0..50);
+ })
+ }
+
+ #[bench]
+ fn fill_small_vec_8_50_with_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 8]> = SmallVec::with_capacity(50);
+
+ sv.extend(0..50);
+ })
+ }
+
+ #[bench]
+ fn fill_small_vec_8_50_wo_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 8]> = SmallVec::new();
+
+ sv.extend(0..50);
+ })
+ }
+
+ #[bench]
+ fn fill_small_vec_32_50_with_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 32]> = SmallVec::with_capacity(50);
+
+ sv.extend(0..50);
+ })
+ }
+
+ #[bench]
+ fn fill_small_vec_32_50_wo_cap(b: &mut Bencher) {
+ b.iter(|| {
+ let mut sv: SmallVec<[usize; 32]> = SmallVec::new();
+
+ sv.extend(0..50);
+ })
+ }
+}
#[inline]
pub fn insert(&mut self, data: T) {
- let current_head = mem::replace(&mut self.head, None);
-
- if let Some(current_head) = current_head {
- let current_head = Box::new(current_head);
- self.head = Some(Element {
- data,
- next: Some(current_head)
- });
- } else {
- self.head = Some(Element {
- data,
- next: None,
- })
- }
+ self.head = Some(Element {
+ data,
+ next: mem::replace(&mut self.head, None).map(Box::new),
+ });
}
#[inline]
pub fn remove(&mut self, data: &T) -> bool {
- let remove_head = if let Some(ref mut head) = self.head {
- if head.data == *data {
- Some(mem::replace(&mut head.next, None))
- } else {
- None
+ self.head = match self.head {
+ Some(ref mut head) if head.data == *data => {
+ mem::replace(&mut head.next, None).map(|x| *x)
}
- } else {
- return false
+ Some(ref mut head) => return head.remove_next(data),
+ None => return false,
};
-
- if let Some(remove_head) = remove_head {
- if let Some(next) = remove_head {
- self.head = Some(*next);
- } else {
- self.head = None;
- }
- return true
- }
-
- self.head.as_mut().unwrap().remove_next(data)
+ true
}
#[inline]
#[cfg(test)]
mod test {
use super::*;
+ extern crate test;
+ use self::test::Bencher;
#[test]
fn test_contains_and_insert() {
assert_eq!(list.len(), 0);
}
+
+ #[bench]
+ fn bench_insert_empty(b: &mut Bencher) {
+ b.iter(|| {
+ let mut list = TinyList::new();
+ list.insert(1);
+ })
+ }
+
+ #[bench]
+ fn bench_insert_one(b: &mut Bencher) {
+ b.iter(|| {
+ let mut list = TinyList::new_single(0);
+ list.insert(1);
+ })
+ }
+
+ #[bench]
+ fn bench_remove_empty(b: &mut Bencher) {
+ b.iter(|| {
+ TinyList::new().remove(&1)
+ });
+ }
+
+ #[bench]
+ fn bench_remove_unknown(b: &mut Bencher) {
+ b.iter(|| {
+ TinyList::new_single(0).remove(&1)
+ });
+ }
+
+ #[bench]
+ fn bench_remove_one(b: &mut Bencher) {
+ b.iter(|| {
+ TinyList::new_single(1).remove(&1)
+ });
+ }
}
use rustc::session::search_paths::PathKind;
use rustc::lint;
use rustc::middle::{self, reachable, resolve_lifetime, stability};
-use rustc::middle::cstore::CrateStoreDyn;
use rustc::middle::privacy::AccessLevels;
use rustc::ty::{self, AllArenas, Resolutions, TyCtxt};
use rustc::traits;
use rustc::util::common::{install_panic_hook, time, ErrorReported};
+use rustc::util::profiling::ProfileCategory;
use rustc_allocator as allocator;
use rustc_borrowck as borrowck;
use rustc_incremental;
sess.print_perf_stats();
}
+ if sess.opts.debugging_opts.self_profile {
+ sess.print_profiler_results();
+
+ if sess.opts.debugging_opts.profile_json {
+ sess.save_json_results();
+ }
+ }
+
controller_entry_point!(
compilation_done,
sess,
codegen_backend: &dyn (::CodegenBackend),
matches: &::getopts::Matches,
sess: &Session,
- cstore: &dyn (::CrateStore),
+ cstore: &CStore,
input: &Input,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
profile::begin(sess);
}
+ sess.profiler(|p| p.start_activity(ProfileCategory::Parsing));
let krate = time(sess, "parsing", || match *input {
Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess),
Input::Str {
ref name,
} => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess),
})?;
+ sess.profiler(|p| p.end_activity(ProfileCategory::Parsing));
sess.diagnostic().set_continue_after_error(true);
pub hir_forest: hir_map::Forest,
}
-pub struct InnerExpansionResult<'a> {
+pub struct InnerExpansionResult<'a, 'b: 'a> {
pub expanded_crate: ast::Crate,
- pub resolver: Resolver<'a>,
+ pub resolver: Resolver<'a, 'b>,
pub hir_forest: hir_map::Forest,
}
/// Same as phase_2_configure_and_expand, but doesn't let you keep the resolver
/// around
-pub fn phase_2_configure_and_expand_inner<'a, F>(
+pub fn phase_2_configure_and_expand_inner<'a, 'b: 'a, F>(
sess: &'a Session,
cstore: &'a CStore,
mut krate: ast::Crate,
addl_plugins: Option<Vec<String>>,
make_glob_map: MakeGlobMap,
resolver_arenas: &'a ResolverArenas<'a>,
- crate_loader: &'a mut CrateLoader,
+ crate_loader: &'a mut CrateLoader<'b>,
after_expand: F,
-) -> Result<InnerExpansionResult<'a>, CompileIncomplete>
+) -> Result<InnerExpansionResult<'a, 'b>, CompileIncomplete>
where
F: FnOnce(&ast::Crate) -> CompileResult,
{
syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote);
// Expand all macros
+ sess.profiler(|p| p.start_activity(ProfileCategory::Expansion));
krate = time(sess, "expansion", || {
// Windows dlls do not have rpaths, so they don't know how to find their
// dependencies. It's up to us to tell the system where to find all the
}
krate
});
+ sess.profiler(|p| p.end_activity(ProfileCategory::Expansion));
krate = time(sess, "maybe building test harness", || {
syntax::test::modify_for_testing(
krate = time(sess, "maybe creating a macro crate", || {
let crate_types = sess.crate_types.borrow();
let num_crate_types = crate_types.len();
- let is_proc_macro_crate = crate_types.contains(&config::CrateTypeProcMacro);
+ let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro);
let is_test_crate = sess.opts.test;
syntax_ext::proc_macro_registrar::modify(
&sess.parse_sess,
// Unresolved macros might be due to mistyped `#[macro_use]`,
// so abort after checking for unknown attributes. (#49074)
if resolver.found_unresolved_macro {
- sess.parse_sess.span_diagnostic.abort_if_errors();
+ sess.diagnostic().abort_if_errors();
}
// Lower ast -> hir.
codegen_backend: &dyn CodegenBackend,
control: &CompileController,
sess: &'tcx Session,
- cstore: &'tcx CrateStoreDyn,
+ cstore: &'tcx CStore,
hir_map: hir_map::Map<'tcx>,
mut analysis: ty::CrateAnalysis,
resolutions: Resolutions,
::rustc::middle::dependency_format::calculate(tcx)
});
+ tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen));
let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx));
+ tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen));
if tcx.sess.profile_queries() {
profile::dump(&tcx.sess, "profile_queries".to_string())
}
.filter_map(|a| {
if a.check_name("crate_type") {
match a.value_str() {
- Some(ref n) if *n == "rlib" => Some(config::CrateTypeRlib),
- Some(ref n) if *n == "dylib" => Some(config::CrateTypeDylib),
- Some(ref n) if *n == "cdylib" => Some(config::CrateTypeCdylib),
+ Some(ref n) if *n == "rlib" => Some(config::CrateType::Rlib),
+ Some(ref n) if *n == "dylib" => Some(config::CrateType::Dylib),
+ Some(ref n) if *n == "cdylib" => Some(config::CrateType::Cdylib),
Some(ref n) if *n == "lib" => Some(config::default_lib_output()),
- Some(ref n) if *n == "staticlib" => Some(config::CrateTypeStaticlib),
- Some(ref n) if *n == "proc-macro" => Some(config::CrateTypeProcMacro),
- Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
+ Some(ref n) if *n == "staticlib" => Some(config::CrateType::Staticlib),
+ Some(ref n) if *n == "proc-macro" => Some(config::CrateType::ProcMacro),
+ Some(ref n) if *n == "bin" => Some(config::CrateType::Executable),
Some(_) => {
session.buffer_lint(
lint::builtin::UNKNOWN_CRATE_TYPES,
// If we're generating a test executable, then ignore all other output
// styles at all other locations
if session.opts.test {
- return vec![config::CrateTypeExecutable];
+ return vec![config::CrateType::Executable];
}
// Only check command line flags if present. If no types are specified by
let is_exe = session
.crate_types
.borrow()
- .contains(&config::CrateTypeExecutable);
+ .contains(&config::CrateType::Executable);
hasher.write(if is_exe { b"exe" } else { b"lib" });
CrateDisambiguator::from(hasher.finish())
use rustc::session::{early_error, early_warn};
use rustc::lint::Lint;
use rustc::lint;
-use rustc::middle::cstore::CrateStore;
use rustc_metadata::locator;
use rustc_metadata::cstore::CStore;
use rustc_metadata::dynamic_lib::DynamicLibrary;
_: &dyn CodegenBackend,
_: &getopts::Matches,
_: &Session,
- _: &dyn CrateStore,
+ _: &CStore,
_: &Input,
_: &Option<PathBuf>,
_: &Option<PathBuf>)
codegen_backend: &dyn CodegenBackend,
matches: &getopts::Matches,
sess: &Session,
- cstore: &dyn CrateStore,
+ cstore: &CStore,
input: &Input,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>)
impl RustcDefaultCalls {
pub fn list_metadata(sess: &Session,
- cstore: &dyn CrateStore,
+ cstore: &CStore,
matches: &getopts::Matches,
input: &Input)
-> Compilation {
let mut v = Vec::new();
locator::list_file_metadata(&sess.target.target,
path,
- cstore.metadata_loader(),
+ &*cstore.metadata_loader,
&mut v)
.unwrap();
println!("{}", String::from_utf8(v).unwrap());
use rustc::ty::{self, TyCtxt, Resolutions, AllArenas};
use rustc::cfg;
use rustc::cfg::graphviz::LabelledCFG;
-use rustc::middle::cstore::CrateStoreDyn;
use rustc::session::Session;
use rustc::session::config::{Input, OutputFilenames};
use rustc_borrowck as borrowck;
use rustc_borrowck::graphviz as borrowck_dot;
+use rustc_metadata::cstore::CStore;
use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
}
fn call_with_pp_support_hir<'tcx, A, F>(&self,
sess: &'tcx Session,
- cstore: &'tcx CrateStoreDyn,
+ cstore: &'tcx CStore,
hir_map: &hir_map::Map<'tcx>,
analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
}
pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
- cstore: &'tcx CrateStoreDyn,
+ cstore: &'tcx CStore,
hir_map: &hir_map::Map<'tcx>,
analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
// with a different callback than the standard driver, so that isn't easy.
// Instead, we call that function ourselves.
fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
- cstore: &'a CrateStoreDyn,
+ cstore: &'a CStore,
hir_map: &hir_map::Map<'tcx>,
analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
where F: FnOnce(Env)
{
syntax::with_globals(|| {
- let mut options = config::basic_options();
+ let mut options = config::Options::default();
options.debugging_opts.verbose = true;
options.unstable_features = UnstableFeatures::Allow;
pub struct DiagnosticBuilder<'a> {
pub handler: &'a Handler,
diagnostic: Diagnostic,
+ allow_suggestions: bool,
}
/// In general, the `DiagnosticBuilder` uses deref to allow access to
msg: &str,
suggestions: Vec<String>)
-> &mut Self);
- forward!(pub fn span_suggestion_with_applicability(&mut self,
- sp: Span,
- msg: &str,
- suggestion: String,
- applicability: Applicability)
- -> &mut Self);
- forward!(pub fn span_suggestions_with_applicability(&mut self,
- sp: Span,
- msg: &str,
- suggestions: Vec<String>,
- applicability: Applicability)
- -> &mut Self);
- forward!(pub fn span_suggestion_short_with_applicability(&mut self,
- sp: Span,
- msg: &str,
- suggestion: String,
- applicability: Applicability)
- -> &mut Self);
+ pub fn span_suggestion_with_applicability(&mut self,
+ sp: Span,
+ msg: &str,
+ suggestion: String,
+ applicability: Applicability)
+ -> &mut Self {
+ if !self.allow_suggestions {
+ return self
+ }
+ self.diagnostic.span_suggestion_with_applicability(
+ sp,
+ msg,
+ suggestion,
+ applicability,
+ );
+ self
+ }
+
+ pub fn span_suggestions_with_applicability(&mut self,
+ sp: Span,
+ msg: &str,
+ suggestions: Vec<String>,
+ applicability: Applicability)
+ -> &mut Self {
+ if !self.allow_suggestions {
+ return self
+ }
+ self.diagnostic.span_suggestions_with_applicability(
+ sp,
+ msg,
+ suggestions,
+ applicability,
+ );
+ self
+ }
+
+ pub fn span_suggestion_short_with_applicability(&mut self,
+ sp: Span,
+ msg: &str,
+ suggestion: String,
+ applicability: Applicability)
+ -> &mut Self {
+ if !self.allow_suggestions {
+ return self
+ }
+ self.diagnostic.span_suggestion_short_with_applicability(
+ sp,
+ msg,
+ suggestion,
+ applicability,
+ );
+ self
+ }
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
+ pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
+ self.allow_suggestions = allow;
+ self
+ }
+
/// Convenience function for internal use, clients should use one of the
/// struct_* methods on Handler.
pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
/// diagnostic.
pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic)
-> DiagnosticBuilder<'a> {
- DiagnosticBuilder { handler, diagnostic }
+ DiagnosticBuilder {
+ handler,
+ diagnostic,
+ allow_suggestions: true,
+ }
}
}
let msg = "denote infinite loops with `loop { ... }`";
let condition_span = cx.tcx.sess.codemap().def_span(e.span);
let mut err = cx.struct_span_lint(WHILE_TRUE, condition_span, msg);
- err.span_suggestion_short(condition_span, "use `loop`", "loop".to_owned());
+ err.span_suggestion_short_with_applicability(
+ condition_span,
+ "use `loop`",
+ "loop".to_owned(),
+ Applicability::MachineApplicable
+ );
err.emit();
}
}
fieldpat.span,
&format!("the `{}:` in this pattern is redundant", ident));
let subspan = cx.tcx.sess.codemap().span_through_char(fieldpat.span, ':');
- err.span_suggestion_short(subspan, "remove this", ident.to_string());
+ err.span_suggestion_short_with_applicability(
+ subspan,
+ "remove this",
+ ident.to_string(),
+ Applicability::MachineApplicable
+ );
err.emit();
}
}
| "i8" | "i16" | "i32" | "i64" | "i128" | "isize" => {
// if the literal could have been a valid `repr` arg,
// suggest the correct syntax
- warn.span_suggestion(
+ warn.span_suggestion_with_applicability(
attr.span,
"give `repr` a hint",
repr_str(&lit.as_str()),
+ Applicability::MachineApplicable
);
suggested = true;
}
let msg = format!("use of deprecated attribute `{}`: {}. See {}",
name, reason, link);
let mut err = cx.struct_span_lint(DEPRECATED, attr.span, &msg);
- err.span_suggestion_short(attr.span, "remove this attribute", "".to_owned());
+ err.span_suggestion_short_with_applicability(
+ attr.span,
+ "remove this attribute",
+ "".to_owned(),
+ Applicability::MachineApplicable
+ );
err.emit();
}
return;
}
};
if let Some(replacement) = suggestion {
- err.span_suggestion(vis.span, "try making it public", replacement);
+ err.span_suggestion_with_applicability(
+ vis.span,
+ "try making it public",
+ replacement,
+ Applicability::MachineApplicable
+ );
}
};
it.span,
"functions generic over \
types must be mangled");
- err.span_suggestion_short(no_mangle_attr.span,
- "remove this attribute",
- "".to_owned());
+ err.span_suggestion_short_with_applicability(
+ no_mangle_attr.span,
+ "remove this attribute",
+ "".to_owned(),
+ // Use of `#[no_mangle]` suggests FFI intent; correct
+ // fix may be to monomorphize source by hand
+ Applicability::MaybeIncorrect
+ );
err.emit();
break;
}
.unwrap_or(0) as u32;
// `const` is 5 chars
let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
- err.span_suggestion(const_span,
- "try a static value",
- "pub static".to_owned());
+ err.span_suggestion_with_applicability(
+ const_span,
+ "try a static value",
+ "pub static".to_owned(),
+ Applicability::MachineApplicable
+ );
err.emit();
}
}
fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) {
let def_id = cx.tcx.hir.body_owner_def_id(body_id);
- let param_env = cx.tcx.param_env(def_id);
+ let is_static = cx.tcx.is_static(def_id).is_some();
+ let param_env = if is_static {
+ // Use the same param_env as `codegen_static_initializer`, to reuse the cache.
+ ty::ParamEnv::reveal_all()
+ } else {
+ cx.tcx.param_env(def_id)
+ };
let cid = ::rustc::mir::interpret::GlobalId {
instance: ty::Instance::mono(cx.tcx, def_id),
promoted: None
match cx.tcx.const_eval(param_env.and(cid)) {
Ok(val) => validate_const(cx.tcx, val, param_env, cid, what),
Err(err) => {
- // errors for statics are already reported directly in the query
- if cx.tcx.is_static(def_id).is_none() {
+ // errors for statics are already reported directly in the query, avoid duplicates
+ if !is_static {
let span = cx.tcx.def_span(def_id);
err.report_as_lint(
cx.tcx.at(span),
use rustc::lint::builtin::{
BARE_TRAIT_OBJECTS,
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
- MACRO_USE_EXTERN_CRATE,
ELIDED_LIFETIMES_IN_PATHS,
parser::QUESTION_MARK_MACRO_SEP
};
add_lint_group!(sess,
"rust_2018_idioms",
BARE_TRAIT_OBJECTS,
- UNREACHABLE_PUB,
UNUSED_EXTERN_CRATES,
- MACRO_USE_EXTERN_CRATE,
- ELIDED_LIFETIMES_IN_PATHS,
- ELLIPSIS_INCLUSIVE_RANGE_PATTERNS);
+ ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
+ ELIDED_LIFETIMES_IN_PATHS
+
+ // FIXME(#52665, #47816) not always applicable and not all
+ // macros are ready for this yet.
+ // UNREACHABLE_PUB,
+
+ // FIXME macro crates are not up for this yet, too much
+ // breakage is seen if we try to encourage this lint.
+ // MACRO_USE_EXTERN_CRATE,
+ );
// Guidelines for creating a future incompatibility lint:
//
use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
use syntax::{ast, attr};
+use syntax::errors::Applicability;
use rustc_target::spec::abi::Abi;
use syntax_pos::Span;
use syntax::codemap;
OVERFLOWING_LITERALS,
parent_expr.span,
"only u8 can be cast into char");
- err.span_suggestion(parent_expr.span,
- &"use a char literal instead",
- format!("'\\u{{{:X}}}'", lit_val));
+ err.span_suggestion_with_applicability(
+ parent_expr.span,
+ &"use a char literal instead",
+ format!("'\\u{{{:X}}}'", lit_val),
+ Applicability::MachineApplicable
+ );
err.emit();
return
}
{
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
let (sans_suffix, _) = repr_str.split_at(pos);
- err.span_suggestion(
+ err.span_suggestion_with_applicability(
expr.span,
&format!("consider using `{}` instead", sugg_ty),
format!("{}{}", sans_suffix, sugg_ty),
+ Applicability::MachineApplicable
);
} else {
err.help(&format!("consider using `{}` instead", sugg_ty));
use syntax::ast;
use syntax::attr;
+use syntax::errors::Applicability;
use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType};
use syntax::print::pprust;
use syntax::symbol::keywords;
_ => false,
}
}).to_owned();
- err.span_suggestion_short(value.span,
- "remove these parentheses",
- parens_removed);
+ err.span_suggestion_short_with_applicability(
+ value.span,
+ "remove these parentheses",
+ parens_removed,
+ Applicability::MachineApplicable
+ );
err.emit();
}
}
static-libstdcpp = []
emscripten = []
-[dependencies]
-bitflags = "1.0"
-libc = "0.2"
-rustc_cratesio_shim = { path = "../librustc_cratesio_shim" }
-
[build-dependencies]
build_helper = { path = "../build_helper" }
cc = "1.0.1"
+++ /dev/null
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A wrapper around LLVM's archive (.a) code
-
-use ArchiveRef;
-
-use std::ffi::CString;
-use std::marker;
-use std::path::Path;
-use std::slice;
-use std::str;
-
-pub struct ArchiveRO {
- ptr: ArchiveRef,
-}
-
-unsafe impl Send for ArchiveRO {}
-
-pub struct Iter<'a> {
- archive: &'a ArchiveRO,
- ptr: ::ArchiveIteratorRef,
-}
-
-pub struct Child<'a> {
- ptr: ::ArchiveChildRef,
- _data: marker::PhantomData<&'a ArchiveRO>,
-}
-
-impl ArchiveRO {
- /// Opens a static archive for read-only purposes. This is more optimized
- /// than the `open` method because it uses LLVM's internal `Archive` class
- /// rather than shelling out to `ar` for everything.
- ///
- /// If this archive is used with a mutable method, then an error will be
- /// raised.
- pub fn open(dst: &Path) -> Result<ArchiveRO, String> {
- return unsafe {
- let s = path2cstr(dst);
- let ar = ::LLVMRustOpenArchive(s.as_ptr());
- if ar.is_null() {
- Err(::last_error().unwrap_or("failed to open archive".to_string()))
- } else {
- Ok(ArchiveRO { ptr: ar })
- }
- };
-
- #[cfg(unix)]
- fn path2cstr(p: &Path) -> CString {
- use std::os::unix::prelude::*;
- use std::ffi::OsStr;
- let p: &OsStr = p.as_ref();
- CString::new(p.as_bytes()).unwrap()
- }
- #[cfg(windows)]
- fn path2cstr(p: &Path) -> CString {
- CString::new(p.to_str().unwrap()).unwrap()
- }
- }
-
- pub fn raw(&self) -> ArchiveRef {
- self.ptr
- }
-
- pub fn iter(&self) -> Iter {
- unsafe {
- Iter {
- ptr: ::LLVMRustArchiveIteratorNew(self.ptr),
- archive: self,
- }
- }
- }
-}
-
-impl Drop for ArchiveRO {
- fn drop(&mut self) {
- unsafe {
- ::LLVMRustDestroyArchive(self.ptr);
- }
- }
-}
-
-impl<'a> Iterator for Iter<'a> {
- type Item = Result<Child<'a>, String>;
-
- fn next(&mut self) -> Option<Result<Child<'a>, String>> {
- let ptr = unsafe { ::LLVMRustArchiveIteratorNext(self.ptr) };
- if ptr.is_null() {
- ::last_error().map(Err)
- } else {
- Some(Ok(Child {
- ptr,
- _data: marker::PhantomData,
- }))
- }
- }
-}
-
-impl<'a> Drop for Iter<'a> {
- fn drop(&mut self) {
- unsafe {
- ::LLVMRustArchiveIteratorFree(self.ptr);
- }
- }
-}
-
-impl<'a> Child<'a> {
- pub fn name(&self) -> Option<&'a str> {
- unsafe {
- let mut name_len = 0;
- let name_ptr = ::LLVMRustArchiveChildName(self.ptr, &mut name_len);
- if name_ptr.is_null() {
- None
- } else {
- let name = slice::from_raw_parts(name_ptr as *const u8, name_len as usize);
- str::from_utf8(name).ok().map(|s| s.trim())
- }
- }
- }
-
- pub fn data(&self) -> &'a [u8] {
- unsafe {
- let mut data_len = 0;
- let data_ptr = ::LLVMRustArchiveChildData(self.ptr, &mut data_len);
- if data_ptr.is_null() {
- panic!("failed to read data from archive child");
- }
- slice::from_raw_parts(data_ptr as *const u8, data_len as usize)
- }
- }
-
- pub fn raw(&self) -> ::ArchiveChildRef {
- self.ptr
- }
-}
-
-impl<'a> Drop for Child<'a> {
- fn drop(&mut self) {
- unsafe {
- ::LLVMRustArchiveChildFree(self.ptr);
- }
- }
-}
optional_components.push("hexagon");
}
+ if major > 6 {
+ optional_components.push("riscv");
+ }
+
// FIXME: surely we don't need all these components, right? Stuff like mcjit
// or interpreter the compiler itself never uses.
let required_components = &["ipo",
if target.contains("windows-gnu") {
println!("cargo:rustc-link-lib=static-nobundle=gcc_s");
println!("cargo:rustc-link-lib=static-nobundle=pthread");
+ println!("cargo:rustc-link-lib=dylib=uuid");
}
}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! LLVM diagnostic reports.
-
-pub use self::OptimizationDiagnosticKind::*;
-pub use self::Diagnostic::*;
-
-use libc::c_uint;
-use std::ptr;
-
-use {DiagnosticInfoRef, TwineRef, ValueRef};
-
-#[derive(Copy, Clone)]
-pub enum OptimizationDiagnosticKind {
- OptimizationRemark,
- OptimizationMissed,
- OptimizationAnalysis,
- OptimizationAnalysisFPCommute,
- OptimizationAnalysisAliasing,
- OptimizationFailure,
- OptimizationRemarkOther,
-}
-
-impl OptimizationDiagnosticKind {
- pub fn describe(self) -> &'static str {
- match self {
- OptimizationRemark | OptimizationRemarkOther => "remark",
- OptimizationMissed => "missed",
- OptimizationAnalysis => "analysis",
- OptimizationAnalysisFPCommute => "floating-point",
- OptimizationAnalysisAliasing => "aliasing",
- OptimizationFailure => "failure",
- }
- }
-}
-
-pub struct OptimizationDiagnostic {
- pub kind: OptimizationDiagnosticKind,
- pub pass_name: String,
- pub function: ValueRef,
- pub line: c_uint,
- pub column: c_uint,
- pub filename: String,
- pub message: String,
-}
-
-impl OptimizationDiagnostic {
- unsafe fn unpack(kind: OptimizationDiagnosticKind,
- di: DiagnosticInfoRef)
- -> OptimizationDiagnostic {
- let mut function = ptr::null_mut();
- let mut line = 0;
- let mut column = 0;
-
- let mut message = None;
- let mut filename = None;
- let pass_name = super::build_string(|pass_name|
- message = super::build_string(|message|
- filename = super::build_string(|filename|
- super::LLVMRustUnpackOptimizationDiagnostic(di,
- pass_name,
- &mut function,
- &mut line,
- &mut column,
- filename,
- message)
- )
- )
- );
-
- let mut filename = filename.unwrap_or(String::new());
- if filename.is_empty() {
- filename.push_str("<unknown file>");
- }
-
- OptimizationDiagnostic {
- kind,
- pass_name: pass_name.expect("got a non-UTF8 pass name from LLVM"),
- function,
- line,
- column,
- filename,
- message: message.expect("got a non-UTF8 OptimizationDiagnostic message from LLVM")
- }
- }
-}
-
-#[derive(Copy, Clone)]
-pub struct InlineAsmDiagnostic {
- pub cookie: c_uint,
- pub message: TwineRef,
- pub instruction: ValueRef,
-}
-
-impl InlineAsmDiagnostic {
- unsafe fn unpack(di: DiagnosticInfoRef) -> InlineAsmDiagnostic {
-
- let mut opt = InlineAsmDiagnostic {
- cookie: 0,
- message: ptr::null_mut(),
- instruction: ptr::null_mut(),
- };
-
- super::LLVMRustUnpackInlineAsmDiagnostic(di,
- &mut opt.cookie,
- &mut opt.message,
- &mut opt.instruction);
-
- opt
- }
-}
-
-pub enum Diagnostic {
- Optimization(OptimizationDiagnostic),
- InlineAsm(InlineAsmDiagnostic),
- PGO(DiagnosticInfoRef),
-
- /// LLVM has other types that we do not wrap here.
- UnknownDiagnostic(DiagnosticInfoRef),
-}
-
-impl Diagnostic {
- pub unsafe fn unpack(di: DiagnosticInfoRef) -> Diagnostic {
- use super::DiagnosticKind as Dk;
- let kind = super::LLVMRustGetDiagInfoKind(di);
-
- match kind {
- Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpack(di)),
-
- Dk::OptimizationRemark => {
- Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di))
- }
- Dk::OptimizationRemarkOther => {
- Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di))
- }
- Dk::OptimizationRemarkMissed => {
- Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di))
- }
-
- Dk::OptimizationRemarkAnalysis => {
- Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di))
- }
-
- Dk::OptimizationRemarkAnalysisFPCommute => {
- Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisFPCommute, di))
- }
-
- Dk::OptimizationRemarkAnalysisAliasing => {
- Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisAliasing, di))
- }
-
- Dk::OptimizationFailure => {
- Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di))
- }
-
- Dk::PGOProfile => {
- PGO(di)
- }
-
- _ => UnknownDiagnostic(di),
- }
- }
-}
+++ /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.
-
-// FIXME: Rename 'DIGlobalVariable' to 'DIGlobalVariableExpression'
-// once support for LLVM 3.9 is dropped.
-//
-// This method was changed in this LLVM patch:
-// https://reviews.llvm.org/D26769
-
-use debuginfo::{DIBuilderRef, DIDescriptor, DIFile, DILexicalBlock, DISubprogram, DIType,
- DIBasicType, DIDerivedType, DICompositeType, DIScope, DIVariable,
- DIGlobalVariable, DIArray, DISubrange, DITemplateTypeParameter, DIEnumerator,
- DINameSpace, DIFlags};
-
-use libc::{c_uint, c_int, size_t, c_char};
-use libc::{c_longlong, c_ulonglong, c_void};
-
-use RustStringRef;
-
-pub type Opcode = u32;
-pub type Bool = c_uint;
-
-pub const True: Bool = 1 as Bool;
-pub const False: Bool = 0 as Bool;
-
-#[derive(Copy, Clone, PartialEq)]
-#[repr(C)]
-pub enum LLVMRustResult {
- Success,
- Failure,
-}
-// Consts for the LLVM CallConv type, pre-cast to usize.
-
-/// LLVM CallingConv::ID. Should we wrap this?
-#[derive(Copy, Clone, PartialEq, Debug)]
-#[repr(C)]
-pub enum CallConv {
- CCallConv = 0,
- FastCallConv = 8,
- ColdCallConv = 9,
- X86StdcallCallConv = 64,
- X86FastcallCallConv = 65,
- ArmAapcsCallConv = 67,
- Msp430Intr = 69,
- X86_ThisCall = 70,
- PtxKernel = 71,
- X86_64_SysV = 78,
- X86_64_Win64 = 79,
- X86_VectorCall = 80,
- X86_Intr = 83,
- AmdGpuKernel = 91,
-}
-
-/// LLVMRustLinkage
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-#[repr(C)]
-pub enum Linkage {
- ExternalLinkage = 0,
- AvailableExternallyLinkage = 1,
- LinkOnceAnyLinkage = 2,
- LinkOnceODRLinkage = 3,
- WeakAnyLinkage = 4,
- WeakODRLinkage = 5,
- AppendingLinkage = 6,
- InternalLinkage = 7,
- PrivateLinkage = 8,
- ExternalWeakLinkage = 9,
- CommonLinkage = 10,
-}
-
-// LLVMRustVisibility
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-#[repr(C)]
-pub enum Visibility {
- Default = 0,
- Hidden = 1,
- Protected = 2,
-}
-
-/// LLVMDiagnosticSeverity
-#[derive(Copy, Clone, Debug)]
-#[repr(C)]
-pub enum DiagnosticSeverity {
- Error = 0,
- Warning = 1,
- Remark = 2,
- Note = 3,
-}
-
-/// LLVMDLLStorageClass
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum DLLStorageClass {
- Default = 0,
- DllImport = 1, // Function to be imported from DLL.
- DllExport = 2, // Function to be accessible from DLL.
-}
-
-/// Matches LLVMRustAttribute in rustllvm.h
-/// Semantically a subset of the C++ enum llvm::Attribute::AttrKind,
-/// though it is not ABI compatible (since it's a C++ enum)
-#[repr(C)]
-#[derive(Copy, Clone, Debug)]
-pub enum Attribute {
- AlwaysInline = 0,
- ByVal = 1,
- Cold = 2,
- InlineHint = 3,
- MinSize = 4,
- Naked = 5,
- NoAlias = 6,
- NoCapture = 7,
- NoInline = 8,
- NonNull = 9,
- NoRedZone = 10,
- NoReturn = 11,
- NoUnwind = 12,
- OptimizeForSize = 13,
- ReadOnly = 14,
- SExt = 15,
- StructRet = 16,
- UWTable = 17,
- ZExt = 18,
- InReg = 19,
- SanitizeThread = 20,
- SanitizeAddress = 21,
- SanitizeMemory = 22,
-}
-
-/// LLVMIntPredicate
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum IntPredicate {
- IntEQ = 32,
- IntNE = 33,
- IntUGT = 34,
- IntUGE = 35,
- IntULT = 36,
- IntULE = 37,
- IntSGT = 38,
- IntSGE = 39,
- IntSLT = 40,
- IntSLE = 41,
-}
-
-/// LLVMRealPredicate
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum RealPredicate {
- RealPredicateFalse = 0,
- RealOEQ = 1,
- RealOGT = 2,
- RealOGE = 3,
- RealOLT = 4,
- RealOLE = 5,
- RealONE = 6,
- RealORD = 7,
- RealUNO = 8,
- RealUEQ = 9,
- RealUGT = 10,
- RealUGE = 11,
- RealULT = 12,
- RealULE = 13,
- RealUNE = 14,
- RealPredicateTrue = 15,
-}
-
-/// LLVMTypeKind
-#[derive(Copy, Clone, PartialEq, Debug)]
-#[repr(C)]
-pub enum TypeKind {
- Void = 0,
- Half = 1,
- Float = 2,
- Double = 3,
- X86_FP80 = 4,
- FP128 = 5,
- PPC_FP128 = 6,
- Label = 7,
- Integer = 8,
- Function = 9,
- Struct = 10,
- Array = 11,
- Pointer = 12,
- Vector = 13,
- Metadata = 14,
- X86_MMX = 15,
- Token = 16,
-}
-
-/// LLVMAtomicRmwBinOp
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum AtomicRmwBinOp {
- AtomicXchg = 0,
- AtomicAdd = 1,
- AtomicSub = 2,
- AtomicAnd = 3,
- AtomicNand = 4,
- AtomicOr = 5,
- AtomicXor = 6,
- AtomicMax = 7,
- AtomicMin = 8,
- AtomicUMax = 9,
- AtomicUMin = 10,
-}
-
-/// LLVMAtomicOrdering
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum AtomicOrdering {
- NotAtomic = 0,
- Unordered = 1,
- Monotonic = 2,
- // Consume = 3, // Not specified yet.
- Acquire = 4,
- Release = 5,
- AcquireRelease = 6,
- SequentiallyConsistent = 7,
-}
-
-/// LLVMRustSynchronizationScope
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum SynchronizationScope {
- Other,
- SingleThread,
- CrossThread,
-}
-
-/// LLVMRustFileType
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum FileType {
- Other,
- AssemblyFile,
- ObjectFile,
-}
-
-/// LLVMMetadataType
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum MetadataType {
- MD_dbg = 0,
- MD_tbaa = 1,
- MD_prof = 2,
- MD_fpmath = 3,
- MD_range = 4,
- MD_tbaa_struct = 5,
- MD_invariant_load = 6,
- MD_alias_scope = 7,
- MD_noalias = 8,
- MD_nontemporal = 9,
- MD_mem_parallel_loop_access = 10,
- MD_nonnull = 11,
-}
-
-/// LLVMRustAsmDialect
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum AsmDialect {
- Other,
- Att,
- Intel,
-}
-
-/// LLVMRustCodeGenOptLevel
-#[derive(Copy, Clone, PartialEq)]
-#[repr(C)]
-pub enum CodeGenOptLevel {
- Other,
- None,
- Less,
- Default,
- Aggressive,
-}
-
-/// LLVMRelocMode
-#[derive(Copy, Clone, PartialEq)]
-#[repr(C)]
-pub enum RelocMode {
- Default,
- Static,
- PIC,
- DynamicNoPic,
- ROPI,
- RWPI,
- ROPI_RWPI,
-}
-
-/// LLVMRustCodeModel
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum CodeModel {
- Other,
- Small,
- Kernel,
- Medium,
- Large,
- None,
-}
-
-/// LLVMRustDiagnosticKind
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum DiagnosticKind {
- Other,
- InlineAsm,
- StackSize,
- DebugMetadataVersion,
- SampleProfile,
- OptimizationRemark,
- OptimizationRemarkMissed,
- OptimizationRemarkAnalysis,
- OptimizationRemarkAnalysisFPCommute,
- OptimizationRemarkAnalysisAliasing,
- OptimizationRemarkOther,
- OptimizationFailure,
- PGOProfile,
-}
-
-/// LLVMRustArchiveKind
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum ArchiveKind {
- Other,
- K_GNU,
- K_BSD,
- K_COFF,
-}
-
-/// LLVMRustPassKind
-#[derive(Copy, Clone, PartialEq, Debug)]
-#[repr(C)]
-pub enum PassKind {
- Other,
- Function,
- Module,
-}
-
-/// LLVMRustThinLTOData
-pub enum ThinLTOData {}
-
-/// LLVMRustThinLTOBuffer
-pub enum ThinLTOBuffer {}
-
-/// LLVMRustThinLTOModule
-#[repr(C)]
-pub struct ThinLTOModule {
- pub identifier: *const c_char,
- pub data: *const u8,
- pub len: usize,
-}
-
-/// LLVMThreadLocalMode
-#[derive(Copy, Clone)]
-#[repr(C)]
-pub enum ThreadLocalMode {
- NotThreadLocal,
- GeneralDynamic,
- LocalDynamic,
- InitialExec,
- LocalExec
-}
-
-// Opaque pointer types
-#[allow(missing_copy_implementations)]
-pub enum Module_opaque {}
-pub type ModuleRef = *mut Module_opaque;
-#[allow(missing_copy_implementations)]
-pub enum Context_opaque {}
-pub type ContextRef = *mut Context_opaque;
-#[allow(missing_copy_implementations)]
-pub enum Type_opaque {}
-pub type TypeRef = *mut Type_opaque;
-#[allow(missing_copy_implementations)]
-pub enum Value_opaque {}
-pub type ValueRef = *mut Value_opaque;
-#[allow(missing_copy_implementations)]
-pub enum Metadata_opaque {}
-pub type MetadataRef = *mut Metadata_opaque;
-#[allow(missing_copy_implementations)]
-pub enum BasicBlock_opaque {}
-pub type BasicBlockRef = *mut BasicBlock_opaque;
-#[allow(missing_copy_implementations)]
-pub enum Builder_opaque {}
-pub type BuilderRef = *mut Builder_opaque;
-#[allow(missing_copy_implementations)]
-pub enum ExecutionEngine_opaque {}
-pub type ExecutionEngineRef = *mut ExecutionEngine_opaque;
-#[allow(missing_copy_implementations)]
-pub enum MemoryBuffer_opaque {}
-pub type MemoryBufferRef = *mut MemoryBuffer_opaque;
-#[allow(missing_copy_implementations)]
-pub enum PassManager_opaque {}
-pub type PassManagerRef = *mut PassManager_opaque;
-#[allow(missing_copy_implementations)]
-pub enum PassManagerBuilder_opaque {}
-pub type PassManagerBuilderRef = *mut PassManagerBuilder_opaque;
-#[allow(missing_copy_implementations)]
-pub enum Use_opaque {}
-pub type UseRef = *mut Use_opaque;
-#[allow(missing_copy_implementations)]
-pub enum TargetData_opaque {}
-pub type TargetDataRef = *mut TargetData_opaque;
-#[allow(missing_copy_implementations)]
-pub enum ObjectFile_opaque {}
-pub type ObjectFileRef = *mut ObjectFile_opaque;
-#[allow(missing_copy_implementations)]
-pub enum SectionIterator_opaque {}
-pub type SectionIteratorRef = *mut SectionIterator_opaque;
-#[allow(missing_copy_implementations)]
-pub enum Pass_opaque {}
-pub type PassRef = *mut Pass_opaque;
-#[allow(missing_copy_implementations)]
-pub enum TargetMachine_opaque {}
-pub type TargetMachineRef = *mut TargetMachine_opaque;
-pub enum Archive_opaque {}
-pub type ArchiveRef = *mut Archive_opaque;
-pub enum ArchiveIterator_opaque {}
-pub type ArchiveIteratorRef = *mut ArchiveIterator_opaque;
-pub enum ArchiveChild_opaque {}
-pub type ArchiveChildRef = *mut ArchiveChild_opaque;
-#[allow(missing_copy_implementations)]
-pub enum Twine_opaque {}
-pub type TwineRef = *mut Twine_opaque;
-#[allow(missing_copy_implementations)]
-pub enum DiagnosticInfo_opaque {}
-pub type DiagnosticInfoRef = *mut DiagnosticInfo_opaque;
-#[allow(missing_copy_implementations)]
-pub enum DebugLoc_opaque {}
-pub type DebugLocRef = *mut DebugLoc_opaque;
-#[allow(missing_copy_implementations)]
-pub enum SMDiagnostic_opaque {}
-pub type SMDiagnosticRef = *mut SMDiagnostic_opaque;
-#[allow(missing_copy_implementations)]
-pub enum RustArchiveMember_opaque {}
-pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque;
-#[allow(missing_copy_implementations)]
-pub enum OperandBundleDef_opaque {}
-pub type OperandBundleDefRef = *mut OperandBundleDef_opaque;
-#[allow(missing_copy_implementations)]
-pub enum Linker_opaque {}
-pub type LinkerRef = *mut Linker_opaque;
-
-pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void);
-pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint);
-
-
-pub mod debuginfo {
- use super::MetadataRef;
-
- #[allow(missing_copy_implementations)]
- pub enum DIBuilder_opaque {}
- pub type DIBuilderRef = *mut DIBuilder_opaque;
-
- pub type DIDescriptor = MetadataRef;
- pub type DIScope = DIDescriptor;
- pub type DILocation = DIDescriptor;
- pub type DIFile = DIScope;
- pub type DILexicalBlock = DIScope;
- pub type DISubprogram = DIScope;
- pub type DINameSpace = DIScope;
- pub type DIType = DIDescriptor;
- pub type DIBasicType = DIType;
- pub type DIDerivedType = DIType;
- pub type DICompositeType = DIDerivedType;
- pub type DIVariable = DIDescriptor;
- pub type DIGlobalVariable = DIDescriptor;
- pub type DIArray = DIDescriptor;
- pub type DISubrange = DIDescriptor;
- pub type DIEnumerator = DIDescriptor;
- pub type DITemplateTypeParameter = DIDescriptor;
-
- // These values **must** match with LLVMRustDIFlags!!
- bitflags! {
- #[repr(C)]
- #[derive(Default)]
- pub struct DIFlags: ::libc::uint32_t {
- const FlagZero = 0;
- const FlagPrivate = 1;
- const FlagProtected = 2;
- const FlagPublic = 3;
- const FlagFwdDecl = (1 << 2);
- const FlagAppleBlock = (1 << 3);
- const FlagBlockByrefStruct = (1 << 4);
- const FlagVirtual = (1 << 5);
- const FlagArtificial = (1 << 6);
- const FlagExplicit = (1 << 7);
- const FlagPrototyped = (1 << 8);
- const FlagObjcClassComplete = (1 << 9);
- const FlagObjectPointer = (1 << 10);
- const FlagVector = (1 << 11);
- const FlagStaticMember = (1 << 12);
- const FlagLValueReference = (1 << 13);
- const FlagRValueReference = (1 << 14);
- const FlagExternalTypeRef = (1 << 15);
- const FlagIntroducedVirtual = (1 << 18);
- const FlagBitField = (1 << 19);
- const FlagNoReturn = (1 << 20);
- const FlagMainSubprogram = (1 << 21);
- }
- }
-}
-
-pub enum ModuleBuffer {}
-
-// This annotation is primarily needed for MSVC where attributes like
-// dllimport/dllexport are applied and need to be correct for everything to
-// link successfully. The #[link] annotation here says "these symbols are
-// included statically" which means that they're all exported with dllexport
-// and from the rustc_llvm dynamic library. Otherwise the rustc_codegen_llvm dynamic
-// library would not be able to access these symbols.
-#[link(name = "rustllvm", kind = "static")]
-extern "C" {
- // Create and destroy contexts.
- pub fn LLVMRustContextCreate(shouldDiscardNames: bool) -> ContextRef;
- pub fn LLVMContextDispose(C: ContextRef);
- pub fn LLVMGetMDKindIDInContext(C: ContextRef, Name: *const c_char, SLen: c_uint) -> c_uint;
-
- // Create and destroy modules.
- pub fn LLVMModuleCreateWithNameInContext(ModuleID: *const c_char, C: ContextRef) -> ModuleRef;
- pub fn LLVMGetModuleContext(M: ModuleRef) -> ContextRef;
- pub fn LLVMCloneModule(M: ModuleRef) -> ModuleRef;
- pub fn LLVMDisposeModule(M: ModuleRef);
-
- /// Data layout. See Module::getDataLayout.
- pub fn LLVMGetDataLayout(M: ModuleRef) -> *const c_char;
- pub fn LLVMSetDataLayout(M: ModuleRef, Triple: *const c_char);
-
- /// See Module::dump.
- pub fn LLVMDumpModule(M: ModuleRef);
-
- /// See Module::setModuleInlineAsm.
- pub fn LLVMSetModuleInlineAsm(M: ModuleRef, Asm: *const c_char);
- pub fn LLVMRustAppendModuleInlineAsm(M: ModuleRef, Asm: *const c_char);
-
- /// See llvm::LLVMTypeKind::getTypeID.
- pub fn LLVMRustGetTypeKind(Ty: TypeRef) -> TypeKind;
-
- // Operations on integer types
- pub fn LLVMInt1TypeInContext(C: ContextRef) -> TypeRef;
- pub fn LLVMInt8TypeInContext(C: ContextRef) -> TypeRef;
- pub fn LLVMInt16TypeInContext(C: ContextRef) -> TypeRef;
- pub fn LLVMInt32TypeInContext(C: ContextRef) -> TypeRef;
- pub fn LLVMInt64TypeInContext(C: ContextRef) -> TypeRef;
- pub fn LLVMIntTypeInContext(C: ContextRef, NumBits: c_uint) -> TypeRef;
-
- pub fn LLVMGetIntTypeWidth(IntegerTy: TypeRef) -> c_uint;
-
- // Operations on real types
- pub fn LLVMFloatTypeInContext(C: ContextRef) -> TypeRef;
- pub fn LLVMDoubleTypeInContext(C: ContextRef) -> TypeRef;
-
- // Operations on function types
- pub fn LLVMFunctionType(ReturnType: TypeRef,
- ParamTypes: *const TypeRef,
- ParamCount: c_uint,
- IsVarArg: Bool)
- -> TypeRef;
- pub fn LLVMGetReturnType(FunctionTy: TypeRef) -> TypeRef;
- pub fn LLVMCountParamTypes(FunctionTy: TypeRef) -> c_uint;
- pub fn LLVMGetParamTypes(FunctionTy: TypeRef, Dest: *mut TypeRef);
-
- // Operations on struct types
- pub fn LLVMStructTypeInContext(C: ContextRef,
- ElementTypes: *const TypeRef,
- ElementCount: c_uint,
- Packed: Bool)
- -> TypeRef;
- pub fn LLVMIsPackedStruct(StructTy: TypeRef) -> Bool;
-
- // Operations on array, pointer, and vector types (sequence types)
- pub fn LLVMRustArrayType(ElementType: TypeRef, ElementCount: u64) -> TypeRef;
- pub fn LLVMPointerType(ElementType: TypeRef, AddressSpace: c_uint) -> TypeRef;
- pub fn LLVMVectorType(ElementType: TypeRef, ElementCount: c_uint) -> TypeRef;
-
- pub fn LLVMGetElementType(Ty: TypeRef) -> TypeRef;
- pub fn LLVMGetVectorSize(VectorTy: TypeRef) -> c_uint;
-
- // Operations on other types
- pub fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef;
- pub fn LLVMX86MMXTypeInContext(C: ContextRef) -> TypeRef;
- pub fn LLVMRustMetadataTypeInContext(C: ContextRef) -> TypeRef;
-
- // Operations on all values
- pub fn LLVMTypeOf(Val: ValueRef) -> TypeRef;
- pub fn LLVMGetValueName(Val: ValueRef) -> *const c_char;
- pub fn LLVMSetValueName(Val: ValueRef, Name: *const c_char);
- pub fn LLVMReplaceAllUsesWith(OldVal: ValueRef, NewVal: ValueRef);
- pub fn LLVMSetMetadata(Val: ValueRef, KindID: c_uint, Node: ValueRef);
-
- // Operations on Uses
- pub fn LLVMGetFirstUse(Val: ValueRef) -> UseRef;
- pub fn LLVMGetNextUse(U: UseRef) -> UseRef;
- pub fn LLVMGetUser(U: UseRef) -> ValueRef;
-
- // Operations on Users
- pub fn LLVMGetOperand(Val: ValueRef, Index: c_uint) -> ValueRef;
-
- // Operations on constants of any type
- pub fn LLVMConstNull(Ty: TypeRef) -> ValueRef;
- pub fn LLVMConstICmp(Pred: IntPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef;
- pub fn LLVMConstFCmp(Pred: RealPredicate, V1: ValueRef, V2: ValueRef) -> ValueRef;
- pub fn LLVMGetUndef(Ty: TypeRef) -> ValueRef;
-
- // Operations on metadata
- pub fn LLVMMDStringInContext(C: ContextRef, Str: *const c_char, SLen: c_uint) -> ValueRef;
- pub fn LLVMMDNodeInContext(C: ContextRef, Vals: *const ValueRef, Count: c_uint) -> ValueRef;
- pub fn LLVMAddNamedMetadataOperand(M: ModuleRef, Name: *const c_char, Val: ValueRef);
-
- // Operations on scalar constants
- pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) -> ValueRef;
- pub fn LLVMConstIntOfArbitraryPrecision(IntTy: TypeRef, Wn: c_uint, Ws: *const u64) -> ValueRef;
- pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong;
- pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong;
- pub fn LLVMRustConstInt128Get(ConstantVal: ValueRef, SExt: bool,
- high: *mut u64, low: *mut u64) -> bool;
- pub fn LLVMConstRealGetDouble (ConstantVal: ValueRef, losesInfo: *mut Bool) -> f64;
-
-
- // Operations on composite constants
- pub fn LLVMConstStringInContext(C: ContextRef,
- Str: *const c_char,
- Length: c_uint,
- DontNullTerminate: Bool)
- -> ValueRef;
- pub fn LLVMConstStructInContext(C: ContextRef,
- ConstantVals: *const ValueRef,
- Count: c_uint,
- Packed: Bool)
- -> ValueRef;
-
- pub fn LLVMConstArray(ElementTy: TypeRef,
- ConstantVals: *const ValueRef,
- Length: c_uint)
- -> ValueRef;
- pub fn LLVMConstVector(ScalarConstantVals: *const ValueRef, Size: c_uint) -> ValueRef;
-
- // Constant expressions
- pub fn LLVMSizeOf(Ty: TypeRef) -> ValueRef;
- pub fn LLVMConstNeg(ConstantVal: ValueRef) -> ValueRef;
- pub fn LLVMConstFNeg(ConstantVal: ValueRef) -> ValueRef;
- pub fn LLVMConstNot(ConstantVal: ValueRef) -> ValueRef;
- pub fn LLVMConstAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstFAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstSub(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstFSub(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstMul(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstFMul(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstUDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstSDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstFDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstURem(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstSRem(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstFRem(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstAnd(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstOr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstXor(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) -> ValueRef;
- pub fn LLVMConstGEP(
- ConstantVal: ValueRef,
- ConstantIndices: *const ValueRef,
- NumIndices: c_uint,
- ) -> ValueRef;
- pub fn LLVMConstInBoundsGEP(
- ConstantVal: ValueRef,
- ConstantIndices: *const ValueRef,
- NumIndices: c_uint,
- ) -> ValueRef;
- pub fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
- pub fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
- pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
- pub fn LLVMConstSIToFP(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
- pub fn LLVMConstFPToUI(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
- pub fn LLVMConstFPToSI(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
- pub fn LLVMConstPtrToInt(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
- pub fn LLVMConstIntToPtr(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
- pub fn LLVMConstBitCast(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
- pub fn LLVMConstPointerCast(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
- pub fn LLVMConstIntCast(ConstantVal: ValueRef, ToType: TypeRef, isSigned: Bool) -> ValueRef;
- pub fn LLVMConstFPCast(ConstantVal: ValueRef, ToType: TypeRef) -> ValueRef;
- pub fn LLVMConstExtractValue(AggConstant: ValueRef,
- IdxList: *const c_uint,
- NumIdx: c_uint)
- -> ValueRef;
- pub fn LLVMConstInlineAsm(Ty: TypeRef,
- AsmString: *const c_char,
- Constraints: *const c_char,
- HasSideEffects: Bool,
- IsAlignStack: Bool)
- -> ValueRef;
-
-
- // Operations on global variables, functions, and aliases (globals)
- pub fn LLVMGetGlobalParent(Global: ValueRef) -> ModuleRef;
- pub fn LLVMIsDeclaration(Global: ValueRef) -> Bool;
- pub fn LLVMRustGetLinkage(Global: ValueRef) -> Linkage;
- pub fn LLVMRustSetLinkage(Global: ValueRef, RustLinkage: Linkage);
- pub fn LLVMGetSection(Global: ValueRef) -> *const c_char;
- pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char);
- pub fn LLVMRustGetVisibility(Global: ValueRef) -> Visibility;
- pub fn LLVMRustSetVisibility(Global: ValueRef, Viz: Visibility);
- pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint;
- pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint);
- pub fn LLVMSetDLLStorageClass(V: ValueRef, C: DLLStorageClass);
-
-
- // Operations on global variables
- pub fn LLVMIsAGlobalVariable(GlobalVar: ValueRef) -> ValueRef;
- pub fn LLVMAddGlobal(M: ModuleRef, Ty: TypeRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMGetNamedGlobal(M: ModuleRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMRustGetOrInsertGlobal(M: ModuleRef, Name: *const c_char, T: TypeRef) -> ValueRef;
- pub fn LLVMGetFirstGlobal(M: ModuleRef) -> ValueRef;
- pub fn LLVMGetNextGlobal(GlobalVar: ValueRef) -> ValueRef;
- pub fn LLVMDeleteGlobal(GlobalVar: ValueRef);
- pub fn LLVMGetInitializer(GlobalVar: ValueRef) -> ValueRef;
- pub fn LLVMSetInitializer(GlobalVar: ValueRef, ConstantVal: ValueRef);
- pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool);
- pub fn LLVMSetThreadLocalMode(GlobalVar: ValueRef, Mode: ThreadLocalMode);
- pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool;
- pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool);
- pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMSetTailCall(CallInst: ValueRef, IsTailCall: Bool);
-
- // Operations on functions
- pub fn LLVMAddFunction(M: ModuleRef, Name: *const c_char, FunctionTy: TypeRef) -> ValueRef;
- pub fn LLVMGetNamedFunction(M: ModuleRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMGetFirstFunction(M: ModuleRef) -> ValueRef;
- pub fn LLVMGetNextFunction(Fn: ValueRef) -> ValueRef;
- pub fn LLVMRustGetOrInsertFunction(M: ModuleRef,
- Name: *const c_char,
- FunctionTy: TypeRef)
- -> ValueRef;
- pub fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: c_uint);
- pub fn LLVMRustAddAlignmentAttr(Fn: ValueRef, index: c_uint, bytes: u32);
- pub fn LLVMRustAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: u64);
- pub fn LLVMRustAddDereferenceableOrNullAttr(Fn: ValueRef, index: c_uint, bytes: u64);
- pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, attr: Attribute);
- pub fn LLVMRustAddFunctionAttrStringValue(Fn: ValueRef,
- index: c_uint,
- Name: *const c_char,
- Value: *const c_char);
- pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, index: c_uint, attr: Attribute);
-
- // Operations on parameters
- pub fn LLVMCountParams(Fn: ValueRef) -> c_uint;
- pub fn LLVMGetParam(Fn: ValueRef, Index: c_uint) -> ValueRef;
-
- // Operations on basic blocks
- pub fn LLVMBasicBlockAsValue(BB: BasicBlockRef) -> ValueRef;
- pub fn LLVMGetBasicBlockParent(BB: BasicBlockRef) -> ValueRef;
- pub fn LLVMAppendBasicBlockInContext(C: ContextRef,
- Fn: ValueRef,
- Name: *const c_char)
- -> BasicBlockRef;
- pub fn LLVMDeleteBasicBlock(BB: BasicBlockRef);
-
- // Operations on instructions
- pub fn LLVMGetInstructionParent(Inst: ValueRef) -> BasicBlockRef;
- pub fn LLVMGetFirstBasicBlock(Fn: ValueRef) -> BasicBlockRef;
- pub fn LLVMGetFirstInstruction(BB: BasicBlockRef) -> ValueRef;
- pub fn LLVMInstructionEraseFromParent(Inst: ValueRef);
-
- // Operations on call sites
- pub fn LLVMSetInstructionCallConv(Instr: ValueRef, CC: c_uint);
- pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, index: c_uint, attr: Attribute);
- pub fn LLVMRustAddAlignmentCallSiteAttr(Instr: ValueRef, index: c_uint, bytes: u32);
- pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: ValueRef, index: c_uint, bytes: u64);
- pub fn LLVMRustAddDereferenceableOrNullCallSiteAttr(Instr: ValueRef,
- index: c_uint,
- bytes: u64);
-
- // Operations on load/store instructions (only)
- pub fn LLVMSetVolatile(MemoryAccessInst: ValueRef, volatile: Bool);
-
- // Operations on phi nodes
- pub fn LLVMAddIncoming(PhiNode: ValueRef,
- IncomingValues: *const ValueRef,
- IncomingBlocks: *const BasicBlockRef,
- Count: c_uint);
-
- // Instruction builders
- pub fn LLVMCreateBuilderInContext(C: ContextRef) -> BuilderRef;
- pub fn LLVMPositionBuilder(Builder: BuilderRef, Block: BasicBlockRef, Instr: ValueRef);
- pub fn LLVMPositionBuilderBefore(Builder: BuilderRef, Instr: ValueRef);
- pub fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef);
- pub fn LLVMGetInsertBlock(Builder: BuilderRef) -> BasicBlockRef;
- pub fn LLVMDisposeBuilder(Builder: BuilderRef);
-
- // Metadata
- pub fn LLVMSetCurrentDebugLocation(Builder: BuilderRef, L: ValueRef);
- pub fn LLVMGetCurrentDebugLocation(Builder: BuilderRef) -> ValueRef;
- pub fn LLVMSetInstDebugLocation(Builder: BuilderRef, Inst: ValueRef);
-
- // Terminators
- pub fn LLVMBuildRetVoid(B: BuilderRef) -> ValueRef;
- pub fn LLVMBuildRet(B: BuilderRef, V: ValueRef) -> ValueRef;
- pub fn LLVMBuildAggregateRet(B: BuilderRef, RetVals: *const ValueRef, N: c_uint) -> ValueRef;
- pub fn LLVMBuildBr(B: BuilderRef, Dest: BasicBlockRef) -> ValueRef;
- pub fn LLVMBuildCondBr(B: BuilderRef,
- If: ValueRef,
- Then: BasicBlockRef,
- Else: BasicBlockRef)
- -> ValueRef;
- pub fn LLVMBuildSwitch(B: BuilderRef,
- V: ValueRef,
- Else: BasicBlockRef,
- NumCases: c_uint)
- -> ValueRef;
- pub fn LLVMBuildIndirectBr(B: BuilderRef, Addr: ValueRef, NumDests: c_uint) -> ValueRef;
- pub fn LLVMRustBuildInvoke(B: BuilderRef,
- Fn: ValueRef,
- Args: *const ValueRef,
- NumArgs: c_uint,
- Then: BasicBlockRef,
- Catch: BasicBlockRef,
- Bundle: OperandBundleDefRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildLandingPad(B: BuilderRef,
- Ty: TypeRef,
- PersFn: ValueRef,
- NumClauses: c_uint,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildResume(B: BuilderRef, Exn: ValueRef) -> ValueRef;
- pub fn LLVMBuildUnreachable(B: BuilderRef) -> ValueRef;
-
- pub fn LLVMRustBuildCleanupPad(B: BuilderRef,
- ParentPad: ValueRef,
- ArgCnt: c_uint,
- Args: *const ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMRustBuildCleanupRet(B: BuilderRef,
- CleanupPad: ValueRef,
- UnwindBB: BasicBlockRef)
- -> ValueRef;
- pub fn LLVMRustBuildCatchPad(B: BuilderRef,
- ParentPad: ValueRef,
- ArgCnt: c_uint,
- Args: *const ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMRustBuildCatchRet(B: BuilderRef, Pad: ValueRef, BB: BasicBlockRef) -> ValueRef;
- pub fn LLVMRustBuildCatchSwitch(Builder: BuilderRef,
- ParentPad: ValueRef,
- BB: BasicBlockRef,
- NumHandlers: c_uint,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMRustAddHandler(CatchSwitch: ValueRef, Handler: BasicBlockRef);
- pub fn LLVMSetPersonalityFn(Func: ValueRef, Pers: ValueRef);
-
- // Add a case to the switch instruction
- pub fn LLVMAddCase(Switch: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef);
-
- // Add a clause to the landing pad instruction
- pub fn LLVMAddClause(LandingPad: ValueRef, ClauseVal: ValueRef);
-
- // Set the cleanup on a landing pad instruction
- pub fn LLVMSetCleanup(LandingPad: ValueRef, Val: Bool);
-
- // Arithmetic
- pub fn LLVMBuildAdd(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildNSWAdd(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildNUWAdd(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildFAdd(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildSub(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildNSWSub(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildNUWSub(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildFSub(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildMul(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildNSWMul(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildNUWMul(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildFMul(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildUDiv(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildExactUDiv(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildSDiv(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildExactSDiv(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildFDiv(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildURem(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildSRem(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildFRem(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildShl(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildLShr(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildAShr(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildAnd(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildOr(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildXor(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildBinOp(B: BuilderRef,
- Op: Opcode,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMBuildNSWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMBuildNUWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMBuildFNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMBuildNot(B: BuilderRef, V: ValueRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMRustSetHasUnsafeAlgebra(Instr: ValueRef);
-
- // Memory
- pub fn LLVMBuildAlloca(B: BuilderRef, Ty: TypeRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMBuildFree(B: BuilderRef, PointerVal: ValueRef) -> ValueRef;
- pub fn LLVMBuildLoad(B: BuilderRef, PointerVal: ValueRef, Name: *const c_char) -> ValueRef;
-
- pub fn LLVMBuildStore(B: BuilderRef, Val: ValueRef, Ptr: ValueRef) -> ValueRef;
-
- pub fn LLVMBuildGEP(B: BuilderRef,
- Pointer: ValueRef,
- Indices: *const ValueRef,
- NumIndices: c_uint,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildInBoundsGEP(B: BuilderRef,
- Pointer: ValueRef,
- Indices: *const ValueRef,
- NumIndices: c_uint,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildStructGEP(B: BuilderRef,
- Pointer: ValueRef,
- Idx: c_uint,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildGlobalString(B: BuilderRef,
- Str: *const c_char,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildGlobalStringPtr(B: BuilderRef,
- Str: *const c_char,
- Name: *const c_char)
- -> ValueRef;
-
- // Casts
- pub fn LLVMBuildTrunc(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildZExt(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildSExt(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildFPToUI(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildFPToSI(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildUIToFP(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildSIToFP(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildFPTrunc(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildFPExt(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildPtrToInt(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildIntToPtr(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildBitCast(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildZExtOrBitCast(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildSExtOrBitCast(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildTruncOrBitCast(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildCast(B: BuilderRef,
- Op: Opcode,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildPointerCast(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMRustBuildIntCast(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- IsSized: bool)
- -> ValueRef;
- pub fn LLVMBuildFPCast(B: BuilderRef,
- Val: ValueRef,
- DestTy: TypeRef,
- Name: *const c_char)
- -> ValueRef;
-
- // Comparisons
- pub fn LLVMBuildICmp(B: BuilderRef,
- Op: c_uint,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildFCmp(B: BuilderRef,
- Op: c_uint,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
-
- // Miscellaneous instructions
- pub fn LLVMBuildPhi(B: BuilderRef, Ty: TypeRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMRustBuildCall(B: BuilderRef,
- Fn: ValueRef,
- Args: *const ValueRef,
- NumArgs: c_uint,
- Bundle: OperandBundleDefRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildSelect(B: BuilderRef,
- If: ValueRef,
- Then: ValueRef,
- Else: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildVAArg(B: BuilderRef,
- list: ValueRef,
- Ty: TypeRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildExtractElement(B: BuilderRef,
- VecVal: ValueRef,
- Index: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildInsertElement(B: BuilderRef,
- VecVal: ValueRef,
- EltVal: ValueRef,
- Index: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildShuffleVector(B: BuilderRef,
- V1: ValueRef,
- V2: ValueRef,
- Mask: ValueRef,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildExtractValue(B: BuilderRef,
- AggVal: ValueRef,
- Index: c_uint,
- Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildInsertValue(B: BuilderRef,
- AggVal: ValueRef,
- EltVal: ValueRef,
- Index: c_uint,
- Name: *const c_char)
- -> ValueRef;
-
- pub fn LLVMRustBuildVectorReduceFAdd(B: BuilderRef,
- Acc: ValueRef,
- Src: ValueRef)
- -> ValueRef;
- pub fn LLVMRustBuildVectorReduceFMul(B: BuilderRef,
- Acc: ValueRef,
- Src: ValueRef)
- -> ValueRef;
- pub fn LLVMRustBuildVectorReduceAdd(B: BuilderRef,
- Src: ValueRef)
- -> ValueRef;
- pub fn LLVMRustBuildVectorReduceMul(B: BuilderRef,
- Src: ValueRef)
- -> ValueRef;
- pub fn LLVMRustBuildVectorReduceAnd(B: BuilderRef,
- Src: ValueRef)
- -> ValueRef;
- pub fn LLVMRustBuildVectorReduceOr(B: BuilderRef,
- Src: ValueRef)
- -> ValueRef;
- pub fn LLVMRustBuildVectorReduceXor(B: BuilderRef,
- Src: ValueRef)
- -> ValueRef;
- pub fn LLVMRustBuildVectorReduceMin(B: BuilderRef,
- Src: ValueRef,
- IsSigned: bool)
- -> ValueRef;
- pub fn LLVMRustBuildVectorReduceMax(B: BuilderRef,
- Src: ValueRef,
- IsSigned: bool)
- -> ValueRef;
- pub fn LLVMRustBuildVectorReduceFMin(B: BuilderRef,
- Src: ValueRef,
- IsNaN: bool)
- -> ValueRef;
- pub fn LLVMRustBuildVectorReduceFMax(B: BuilderRef,
- Src: ValueRef,
- IsNaN: bool)
- -> ValueRef;
-
- pub fn LLVMRustBuildMinNum(B: BuilderRef, LHS: ValueRef, LHS: ValueRef) -> ValueRef;
- pub fn LLVMRustBuildMaxNum(B: BuilderRef, LHS: ValueRef, LHS: ValueRef) -> ValueRef;
-
- pub fn LLVMBuildIsNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMBuildIsNotNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) -> ValueRef;
- pub fn LLVMBuildPtrDiff(B: BuilderRef,
- LHS: ValueRef,
- RHS: ValueRef,
- Name: *const c_char)
- -> ValueRef;
-
- // Atomic Operations
- pub fn LLVMRustBuildAtomicLoad(B: BuilderRef,
- PointerVal: ValueRef,
- Name: *const c_char,
- Order: AtomicOrdering)
- -> ValueRef;
-
- pub fn LLVMRustBuildAtomicStore(B: BuilderRef,
- Val: ValueRef,
- Ptr: ValueRef,
- Order: AtomicOrdering)
- -> ValueRef;
-
- pub fn LLVMRustBuildAtomicCmpXchg(B: BuilderRef,
- LHS: ValueRef,
- CMP: ValueRef,
- RHS: ValueRef,
- Order: AtomicOrdering,
- FailureOrder: AtomicOrdering,
- Weak: Bool)
- -> ValueRef;
-
- pub fn LLVMBuildAtomicRMW(B: BuilderRef,
- Op: AtomicRmwBinOp,
- LHS: ValueRef,
- RHS: ValueRef,
- Order: AtomicOrdering,
- SingleThreaded: Bool)
- -> ValueRef;
-
- pub fn LLVMRustBuildAtomicFence(B: BuilderRef,
- Order: AtomicOrdering,
- Scope: SynchronizationScope);
-
-
- // Selected entries from the downcasts.
- pub fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef;
- pub fn LLVMIsAStoreInst(Inst: ValueRef) -> ValueRef;
-
- /// Writes a module to the specified path. Returns 0 on success.
- pub fn LLVMWriteBitcodeToFile(M: ModuleRef, Path: *const c_char) -> c_int;
-
- /// Creates target data from a target layout string.
- pub fn LLVMCreateTargetData(StringRep: *const c_char) -> TargetDataRef;
-
- /// Disposes target data.
- pub fn LLVMDisposeTargetData(TD: TargetDataRef);
-
- /// Creates a pass manager.
- pub fn LLVMCreatePassManager() -> PassManagerRef;
-
- /// Creates a function-by-function pass manager
- pub fn LLVMCreateFunctionPassManagerForModule(M: ModuleRef) -> PassManagerRef;
-
- /// Disposes a pass manager.
- pub fn LLVMDisposePassManager(PM: PassManagerRef);
-
- /// Runs a pass manager on a module.
- pub fn LLVMRunPassManager(PM: PassManagerRef, M: ModuleRef) -> Bool;
-
- pub fn LLVMInitializePasses();
-
- pub fn LLVMPassManagerBuilderCreate() -> PassManagerBuilderRef;
- pub fn LLVMPassManagerBuilderDispose(PMB: PassManagerBuilderRef);
- pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: PassManagerBuilderRef, Value: Bool);
- pub fn LLVMPassManagerBuilderSetDisableUnrollLoops(PMB: PassManagerBuilderRef, Value: Bool);
- pub fn LLVMPassManagerBuilderUseInlinerWithThreshold(PMB: PassManagerBuilderRef,
- threshold: c_uint);
- pub fn LLVMPassManagerBuilderPopulateModulePassManager(PMB: PassManagerBuilderRef,
- PM: PassManagerRef);
-
- pub fn LLVMPassManagerBuilderPopulateFunctionPassManager(PMB: PassManagerBuilderRef,
- PM: PassManagerRef);
- pub fn LLVMPassManagerBuilderPopulateLTOPassManager(PMB: PassManagerBuilderRef,
- PM: PassManagerRef,
- Internalize: Bool,
- RunInliner: Bool);
- pub fn LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
- PMB: PassManagerBuilderRef,
- PM: PassManagerRef) -> bool;
-
- // Stuff that's in rustllvm/ because it's not upstream yet.
-
- /// Opens an object file.
- pub fn LLVMCreateObjectFile(MemBuf: MemoryBufferRef) -> ObjectFileRef;
- /// Closes an object file.
- pub fn LLVMDisposeObjectFile(ObjFile: ObjectFileRef);
-
- /// Enumerates the sections in an object file.
- pub fn LLVMGetSections(ObjFile: ObjectFileRef) -> SectionIteratorRef;
- /// Destroys a section iterator.
- pub fn LLVMDisposeSectionIterator(SI: SectionIteratorRef);
- /// Returns true if the section iterator is at the end of the section
- /// list:
- pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef, SI: SectionIteratorRef) -> Bool;
- /// Moves the section iterator to point to the next section.
- pub fn LLVMMoveToNextSection(SI: SectionIteratorRef);
- /// Returns the current section size.
- pub fn LLVMGetSectionSize(SI: SectionIteratorRef) -> c_ulonglong;
- /// Returns the current section contents as a string buffer.
- pub fn LLVMGetSectionContents(SI: SectionIteratorRef) -> *const c_char;
-
- /// Reads the given file and returns it as a memory buffer. Use
- /// LLVMDisposeMemoryBuffer() to get rid of it.
- pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *const c_char) -> MemoryBufferRef;
-
- pub fn LLVMStartMultithreaded() -> Bool;
-
- /// Returns a string describing the last error caused by an LLVMRust* call.
- pub fn LLVMRustGetLastError() -> *const c_char;
-
- /// Print the pass timings since static dtors aren't picking them up.
- pub fn LLVMRustPrintPassTimings();
-
- pub fn LLVMStructCreateNamed(C: ContextRef, Name: *const c_char) -> TypeRef;
-
- pub fn LLVMStructSetBody(StructTy: TypeRef,
- ElementTypes: *const TypeRef,
- ElementCount: c_uint,
- Packed: Bool);
-
- /// Prepares inline assembly.
- pub fn LLVMRustInlineAsm(Ty: TypeRef,
- AsmString: *const c_char,
- Constraints: *const c_char,
- SideEffects: Bool,
- AlignStack: Bool,
- Dialect: AsmDialect)
- -> ValueRef;
-
- pub fn LLVMRustDebugMetadataVersion() -> u32;
- pub fn LLVMRustVersionMajor() -> u32;
- pub fn LLVMRustVersionMinor() -> u32;
-
- pub fn LLVMRustAddModuleFlag(M: ModuleRef, name: *const c_char, value: u32);
-
- pub fn LLVMRustMetadataAsValue(C: ContextRef, MD: MetadataRef) -> ValueRef;
-
- pub fn LLVMRustDIBuilderCreate(M: ModuleRef) -> DIBuilderRef;
-
- pub fn LLVMRustDIBuilderDispose(Builder: DIBuilderRef);
-
- pub fn LLVMRustDIBuilderFinalize(Builder: DIBuilderRef);
-
- pub fn LLVMRustDIBuilderCreateCompileUnit(Builder: DIBuilderRef,
- Lang: c_uint,
- File: DIFile,
- Producer: *const c_char,
- isOptimized: bool,
- Flags: *const c_char,
- RuntimeVer: c_uint,
- SplitName: *const c_char)
- -> DIDescriptor;
-
- pub fn LLVMRustDIBuilderCreateFile(Builder: DIBuilderRef,
- Filename: *const c_char,
- Directory: *const c_char)
- -> DIFile;
-
- pub fn LLVMRustDIBuilderCreateSubroutineType(Builder: DIBuilderRef,
- File: DIFile,
- ParameterTypes: DIArray)
- -> DICompositeType;
-
- pub fn LLVMRustDIBuilderCreateFunction(Builder: DIBuilderRef,
- Scope: DIDescriptor,
- Name: *const c_char,
- LinkageName: *const c_char,
- File: DIFile,
- LineNo: c_uint,
- Ty: DIType,
- isLocalToUnit: bool,
- isDefinition: bool,
- ScopeLine: c_uint,
- Flags: DIFlags,
- isOptimized: bool,
- Fn: ValueRef,
- TParam: DIArray,
- Decl: DIDescriptor)
- -> DISubprogram;
-
- pub fn LLVMRustDIBuilderCreateBasicType(Builder: DIBuilderRef,
- Name: *const c_char,
- SizeInBits: u64,
- AlignInBits: u32,
- Encoding: c_uint)
- -> DIBasicType;
-
- pub fn LLVMRustDIBuilderCreatePointerType(Builder: DIBuilderRef,
- PointeeTy: DIType,
- SizeInBits: u64,
- AlignInBits: u32,
- Name: *const c_char)
- -> DIDerivedType;
-
- pub fn LLVMRustDIBuilderCreateStructType(Builder: DIBuilderRef,
- Scope: DIDescriptor,
- Name: *const c_char,
- File: DIFile,
- LineNumber: c_uint,
- SizeInBits: u64,
- AlignInBits: u32,
- Flags: DIFlags,
- DerivedFrom: DIType,
- Elements: DIArray,
- RunTimeLang: c_uint,
- VTableHolder: DIType,
- UniqueId: *const c_char)
- -> DICompositeType;
-
- pub fn LLVMRustDIBuilderCreateMemberType(Builder: DIBuilderRef,
- Scope: DIDescriptor,
- Name: *const c_char,
- File: DIFile,
- LineNo: c_uint,
- SizeInBits: u64,
- AlignInBits: u32,
- OffsetInBits: u64,
- Flags: DIFlags,
- Ty: DIType)
- -> DIDerivedType;
-
- pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: DIBuilderRef,
- Scope: DIScope,
- File: DIFile,
- Line: c_uint,
- Col: c_uint)
- -> DILexicalBlock;
-
- pub fn LLVMRustDIBuilderCreateLexicalBlockFile(Builder: DIBuilderRef,
- Scope: DIScope,
- File: DIFile)
- -> DILexicalBlock;
-
- pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: DIBuilderRef,
- Context: DIScope,
- Name: *const c_char,
- LinkageName: *const c_char,
- File: DIFile,
- LineNo: c_uint,
- Ty: DIType,
- isLocalToUnit: bool,
- Val: ValueRef,
- Decl: DIDescriptor,
- AlignInBits: u32)
- -> DIGlobalVariable;
-
- pub fn LLVMRustDIBuilderCreateVariable(Builder: DIBuilderRef,
- Tag: c_uint,
- Scope: DIDescriptor,
- Name: *const c_char,
- File: DIFile,
- LineNo: c_uint,
- Ty: DIType,
- AlwaysPreserve: bool,
- Flags: DIFlags,
- ArgNo: c_uint,
- AlignInBits: u32)
- -> DIVariable;
-
- pub fn LLVMRustDIBuilderCreateArrayType(Builder: DIBuilderRef,
- Size: u64,
- AlignInBits: u32,
- Ty: DIType,
- Subscripts: DIArray)
- -> DIType;
-
- pub fn LLVMRustDIBuilderCreateVectorType(Builder: DIBuilderRef,
- Size: u64,
- AlignInBits: u32,
- Ty: DIType,
- Subscripts: DIArray)
- -> DIType;
-
- pub fn LLVMRustDIBuilderGetOrCreateSubrange(Builder: DIBuilderRef,
- Lo: i64,
- Count: i64)
- -> DISubrange;
-
- pub fn LLVMRustDIBuilderGetOrCreateArray(Builder: DIBuilderRef,
- Ptr: *const DIDescriptor,
- Count: c_uint)
- -> DIArray;
-
- pub fn LLVMRustDIBuilderInsertDeclareAtEnd(Builder: DIBuilderRef,
- Val: ValueRef,
- VarInfo: DIVariable,
- AddrOps: *const i64,
- AddrOpsCount: c_uint,
- DL: ValueRef,
- InsertAtEnd: BasicBlockRef)
- -> ValueRef;
-
- pub fn LLVMRustDIBuilderCreateEnumerator(Builder: DIBuilderRef,
- Name: *const c_char,
- Val: u64)
- -> DIEnumerator;
-
- pub fn LLVMRustDIBuilderCreateEnumerationType(Builder: DIBuilderRef,
- Scope: DIScope,
- Name: *const c_char,
- File: DIFile,
- LineNumber: c_uint,
- SizeInBits: u64,
- AlignInBits: u32,
- Elements: DIArray,
- ClassType: DIType)
- -> DIType;
-
- pub fn LLVMRustDIBuilderCreateUnionType(Builder: DIBuilderRef,
- Scope: DIScope,
- Name: *const c_char,
- File: DIFile,
- LineNumber: c_uint,
- SizeInBits: u64,
- AlignInBits: u32,
- Flags: DIFlags,
- Elements: DIArray,
- RunTimeLang: c_uint,
- UniqueId: *const c_char)
- -> DIType;
-
- pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool);
-
- pub fn LLVMRustDIBuilderCreateTemplateTypeParameter(Builder: DIBuilderRef,
- Scope: DIScope,
- Name: *const c_char,
- Ty: DIType,
- File: DIFile,
- LineNo: c_uint,
- ColumnNo: c_uint)
- -> DITemplateTypeParameter;
-
-
- pub fn LLVMRustDIBuilderCreateNameSpace(Builder: DIBuilderRef,
- Scope: DIScope,
- Name: *const c_char,
- File: DIFile,
- LineNo: c_uint)
- -> DINameSpace;
- pub fn LLVMRustDICompositeTypeSetTypeArray(Builder: DIBuilderRef,
- CompositeType: DIType,
- TypeArray: DIArray);
-
-
- pub fn LLVMRustDIBuilderCreateDebugLocation(Context: ContextRef,
- Line: c_uint,
- Column: c_uint,
- Scope: DIScope,
- InlinedAt: MetadataRef)
- -> ValueRef;
- pub fn LLVMRustDIBuilderCreateOpDeref() -> i64;
- pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64;
-
- pub fn LLVMRustWriteTypeToString(Type: TypeRef, s: RustStringRef);
- pub fn LLVMRustWriteValueToString(value_ref: ValueRef, s: RustStringRef);
-
- pub fn LLVMIsAConstantInt(value_ref: ValueRef) -> ValueRef;
- pub fn LLVMIsAConstantFP(value_ref: ValueRef) -> ValueRef;
-
- pub fn LLVMRustPassKind(Pass: PassRef) -> PassKind;
- pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef;
- pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: PassRef);
-
- pub fn LLVMRustHasFeature(T: TargetMachineRef, s: *const c_char) -> bool;
-
- pub fn LLVMRustPrintTargetCPUs(T: TargetMachineRef);
- pub fn LLVMRustPrintTargetFeatures(T: TargetMachineRef);
-
- pub fn LLVMRustCreateTargetMachine(Triple: *const c_char,
- CPU: *const c_char,
- Features: *const c_char,
- Model: CodeModel,
- Reloc: RelocMode,
- Level: CodeGenOptLevel,
- UseSoftFP: bool,
- PositionIndependentExecutable: bool,
- FunctionSections: bool,
- DataSections: bool,
- TrapUnreachable: bool,
- Singlethread: bool)
- -> TargetMachineRef;
- pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef);
- pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, PM: PassManagerRef, M: ModuleRef);
- pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef,
- M: ModuleRef,
- DisableSimplifyLibCalls: bool);
- pub fn LLVMRustConfigurePassManagerBuilder(PMB: PassManagerBuilderRef,
- OptLevel: CodeGenOptLevel,
- MergeFunctions: bool,
- SLPVectorize: bool,
- LoopVectorize: bool,
- PrepareForThinLTO: bool,
- PGOGenPath: *const c_char,
- PGOUsePath: *const c_char);
- pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef,
- M: ModuleRef,
- DisableSimplifyLibCalls: bool);
- pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef);
- pub fn LLVMRustWriteOutputFile(T: TargetMachineRef,
- PM: PassManagerRef,
- M: ModuleRef,
- Output: *const c_char,
- FileType: FileType)
- -> LLVMRustResult;
- pub fn LLVMRustPrintModule(PM: PassManagerRef,
- M: ModuleRef,
- Output: *const c_char,
- Demangle: extern fn(*const c_char,
- size_t,
- *mut c_char,
- size_t) -> size_t);
- pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char);
- pub fn LLVMRustPrintPasses();
- pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char);
- pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, AddLifetimes: bool);
- pub fn LLVMRustRunRestrictionPass(M: ModuleRef, syms: *const *const c_char, len: size_t);
- pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef);
-
- pub fn LLVMRustOpenArchive(path: *const c_char) -> ArchiveRef;
- pub fn LLVMRustArchiveIteratorNew(AR: ArchiveRef) -> ArchiveIteratorRef;
- pub fn LLVMRustArchiveIteratorNext(AIR: ArchiveIteratorRef) -> ArchiveChildRef;
- pub fn LLVMRustArchiveChildName(ACR: ArchiveChildRef, size: *mut size_t) -> *const c_char;
- pub fn LLVMRustArchiveChildData(ACR: ArchiveChildRef, size: *mut size_t) -> *const c_char;
- pub fn LLVMRustArchiveChildFree(ACR: ArchiveChildRef);
- pub fn LLVMRustArchiveIteratorFree(AIR: ArchiveIteratorRef);
- pub fn LLVMRustDestroyArchive(AR: ArchiveRef);
-
- pub fn LLVMRustGetSectionName(SI: SectionIteratorRef, data: *mut *const c_char) -> size_t;
-
- pub fn LLVMRustWriteTwineToString(T: TwineRef, s: RustStringRef);
-
- pub fn LLVMContextSetDiagnosticHandler(C: ContextRef,
- Handler: DiagnosticHandler,
- DiagnosticContext: *mut c_void);
-
- pub fn LLVMRustUnpackOptimizationDiagnostic(DI: DiagnosticInfoRef,
- pass_name_out: RustStringRef,
- function_out: *mut ValueRef,
- loc_line_out: *mut c_uint,
- loc_column_out: *mut c_uint,
- loc_filename_out: RustStringRef,
- message_out: RustStringRef);
- pub fn LLVMRustUnpackInlineAsmDiagnostic(DI: DiagnosticInfoRef,
- cookie_out: *mut c_uint,
- message_out: *mut TwineRef,
- instruction_out: *mut ValueRef);
-
- pub fn LLVMRustWriteDiagnosticInfoToString(DI: DiagnosticInfoRef, s: RustStringRef);
- pub fn LLVMRustGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind;
-
- pub fn LLVMRustSetInlineAsmDiagnosticHandler(C: ContextRef,
- H: InlineAsmDiagHandler,
- CX: *mut c_void);
-
- pub fn LLVMRustWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef);
-
- pub fn LLVMRustWriteArchive(Dst: *const c_char,
- NumMembers: size_t,
- Members: *const RustArchiveMemberRef,
- WriteSymbtab: bool,
- Kind: ArchiveKind)
- -> LLVMRustResult;
- pub fn LLVMRustArchiveMemberNew(Filename: *const c_char,
- Name: *const c_char,
- Child: ArchiveChildRef)
- -> RustArchiveMemberRef;
- pub fn LLVMRustArchiveMemberFree(Member: RustArchiveMemberRef);
-
- pub fn LLVMRustSetDataLayoutFromTargetMachine(M: ModuleRef, TM: TargetMachineRef);
-
- pub fn LLVMRustBuildOperandBundleDef(Name: *const c_char,
- Inputs: *const ValueRef,
- NumInputs: c_uint)
- -> OperandBundleDefRef;
- pub fn LLVMRustFreeOperandBundleDef(Bundle: OperandBundleDefRef);
-
- pub fn LLVMRustPositionBuilderAtStart(B: BuilderRef, BB: BasicBlockRef);
-
- pub fn LLVMRustSetComdat(M: ModuleRef, V: ValueRef, Name: *const c_char);
- pub fn LLVMRustUnsetComdat(V: ValueRef);
- pub fn LLVMRustSetModulePIELevel(M: ModuleRef);
- pub fn LLVMRustModuleBufferCreate(M: ModuleRef) -> *mut ModuleBuffer;
- pub fn LLVMRustModuleBufferPtr(p: *const ModuleBuffer) -> *const u8;
- pub fn LLVMRustModuleBufferLen(p: *const ModuleBuffer) -> usize;
- pub fn LLVMRustModuleBufferFree(p: *mut ModuleBuffer);
- pub fn LLVMRustModuleCost(M: ModuleRef) -> u64;
-
- pub fn LLVMRustThinLTOAvailable() -> bool;
- pub fn LLVMRustPGOAvailable() -> bool;
- pub fn LLVMRustWriteThinBitcodeToFile(PMR: PassManagerRef,
- M: ModuleRef,
- BC: *const c_char) -> bool;
- pub fn LLVMRustThinLTOBufferCreate(M: ModuleRef) -> *mut ThinLTOBuffer;
- pub fn LLVMRustThinLTOBufferFree(M: *mut ThinLTOBuffer);
- pub fn LLVMRustThinLTOBufferPtr(M: *const ThinLTOBuffer) -> *const c_char;
- pub fn LLVMRustThinLTOBufferLen(M: *const ThinLTOBuffer) -> size_t;
- pub fn LLVMRustCreateThinLTOData(
- Modules: *const ThinLTOModule,
- NumModules: c_uint,
- PreservedSymbols: *const *const c_char,
- PreservedSymbolsLen: c_uint,
- ) -> *mut ThinLTOData;
- pub fn LLVMRustPrepareThinLTORename(
- Data: *const ThinLTOData,
- Module: ModuleRef,
- ) -> bool;
- pub fn LLVMRustPrepareThinLTOResolveWeak(
- Data: *const ThinLTOData,
- Module: ModuleRef,
- ) -> bool;
- pub fn LLVMRustPrepareThinLTOInternalize(
- Data: *const ThinLTOData,
- Module: ModuleRef,
- ) -> bool;
- pub fn LLVMRustPrepareThinLTOImport(
- Data: *const ThinLTOData,
- Module: ModuleRef,
- ) -> bool;
- pub fn LLVMRustFreeThinLTOData(Data: *mut ThinLTOData);
- pub fn LLVMRustParseBitcodeForThinLTO(
- Context: ContextRef,
- Data: *const u8,
- len: usize,
- Identifier: *const c_char,
- ) -> ModuleRef;
- pub fn LLVMGetModuleIdentifier(M: ModuleRef, size: *mut usize) -> *const c_char;
- pub fn LLVMRustThinLTOGetDICompileUnit(M: ModuleRef,
- CU1: *mut *mut c_void,
- CU2: *mut *mut c_void);
- pub fn LLVMRustThinLTOPatchDICompileUnit(M: ModuleRef, CU: *mut c_void);
-
- pub fn LLVMRustLinkerNew(M: ModuleRef) -> LinkerRef;
- pub fn LLVMRustLinkerAdd(linker: LinkerRef,
- bytecode: *const c_char,
- bytecode_len: usize) -> bool;
- pub fn LLVMRustLinkerFree(linker: LinkerRef);
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_upper_case_globals)]
-#![allow(non_camel_case_types)]
-#![allow(non_snake_case)]
-#![allow(dead_code)]
+#![feature(static_nobundle)]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![feature(box_syntax)]
-#![feature(concat_idents)]
-#![feature(libc)]
-#![feature(link_args)]
-#![feature(static_nobundle)]
-
// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
#[allow(unused_extern_crates)]
extern crate rustc_cratesio_shim;
-#[macro_use]
-extern crate bitflags;
-extern crate libc;
-
-pub use self::IntPredicate::*;
-pub use self::RealPredicate::*;
-pub use self::TypeKind::*;
-pub use self::AtomicRmwBinOp::*;
-pub use self::MetadataType::*;
-pub use self::CodeGenOptSize::*;
-pub use self::CallConv::*;
-pub use self::Linkage::*;
-
-use std::str::FromStr;
-use std::slice;
-use std::ffi::{CString, CStr};
-use std::cell::RefCell;
-use libc::{c_uint, c_char, size_t};
-
-pub mod archive_ro;
-pub mod diagnostic;
-mod ffi;
-
-pub use ffi::*;
-
-impl LLVMRustResult {
- pub fn into_result(self) -> Result<(), ()> {
- match self {
- LLVMRustResult::Success => Ok(()),
- LLVMRustResult::Failure => Err(()),
- }
- }
-}
-
-pub fn AddFunctionAttrStringValue(llfn: ValueRef,
- idx: AttributePlace,
- attr: &CStr,
- value: &CStr) {
- unsafe {
- LLVMRustAddFunctionAttrStringValue(llfn,
- idx.as_uint(),
- attr.as_ptr(),
- value.as_ptr())
- }
-}
-
-#[derive(Copy, Clone)]
-pub enum AttributePlace {
- ReturnValue,
- Argument(u32),
- Function,
-}
-
-impl AttributePlace {
- pub fn as_uint(self) -> c_uint {
- match self {
- AttributePlace::ReturnValue => 0,
- AttributePlace::Argument(i) => 1 + i,
- AttributePlace::Function => !0,
- }
- }
-}
-
-#[derive(Copy, Clone, PartialEq)]
-#[repr(C)]
-pub enum CodeGenOptSize {
- CodeGenOptSizeNone = 0,
- CodeGenOptSizeDefault = 1,
- CodeGenOptSizeAggressive = 2,
-}
-
-impl FromStr for ArchiveKind {
- type Err = ();
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "gnu" => Ok(ArchiveKind::K_GNU),
- "bsd" => Ok(ArchiveKind::K_BSD),
- "coff" => Ok(ArchiveKind::K_COFF),
- _ => Err(()),
- }
- }
-}
-
-#[allow(missing_copy_implementations)]
-pub enum RustString_opaque {}
-type RustStringRef = *mut RustString_opaque;
-type RustStringRepr = *mut RefCell<Vec<u8>>;
-
-/// Appending to a Rust string -- used by RawRustStringOstream.
-#[no_mangle]
-pub unsafe extern "C" fn LLVMRustStringWriteImpl(sr: RustStringRef,
- ptr: *const c_char,
- size: size_t) {
- let slice = slice::from_raw_parts(ptr as *const u8, size as usize);
-
- let sr = sr as RustStringRepr;
- (*sr).borrow_mut().extend_from_slice(slice);
-}
-
-pub fn SetInstructionCallConv(instr: ValueRef, cc: CallConv) {
- unsafe {
- LLVMSetInstructionCallConv(instr, cc as c_uint);
- }
-}
-pub fn SetFunctionCallConv(fn_: ValueRef, cc: CallConv) {
- unsafe {
- LLVMSetFunctionCallConv(fn_, cc as c_uint);
- }
-}
-
-// Externally visible symbols that might appear in multiple codegen units need to appear in
-// their own comdat section so that the duplicates can be discarded at link time. This can for
-// example happen for generics when using multiple codegen units. This function simply uses the
-// value's name as the comdat value to make sure that it is in a 1-to-1 relationship to the
-// function.
-// For more details on COMDAT sections see e.g. http://www.airs.com/blog/archives/52
-pub fn SetUniqueComdat(llmod: ModuleRef, val: ValueRef) {
- unsafe {
- LLVMRustSetComdat(llmod, val, LLVMGetValueName(val));
- }
-}
-
-pub fn UnsetComdat(val: ValueRef) {
- unsafe {
- LLVMRustUnsetComdat(val);
- }
-}
-
-pub fn SetUnnamedAddr(global: ValueRef, unnamed: bool) {
- unsafe {
- LLVMSetUnnamedAddr(global, unnamed as Bool);
- }
-}
-
-pub fn set_thread_local(global: ValueRef, is_thread_local: bool) {
- unsafe {
- LLVMSetThreadLocal(global, is_thread_local as Bool);
- }
-}
-pub fn set_thread_local_mode(global: ValueRef, mode: ThreadLocalMode) {
- unsafe {
- LLVMSetThreadLocalMode(global, mode);
- }
-}
-
-impl Attribute {
- pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
- unsafe { LLVMRustAddFunctionAttribute(llfn, idx.as_uint(), *self) }
- }
-
- pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) {
- unsafe { LLVMRustAddCallSiteAttribute(callsite, idx.as_uint(), *self) }
- }
-
- pub fn unapply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
- unsafe { LLVMRustRemoveFunctionAttributes(llfn, idx.as_uint(), *self) }
- }
-
- pub fn toggle_llfn(&self, idx: AttributePlace, llfn: ValueRef, set: bool) {
- if set {
- self.apply_llfn(idx, llfn);
- } else {
- self.unapply_llfn(idx, llfn);
- }
- }
-}
-
-// Memory-managed interface to target data.
-
-struct TargetData {
- lltd: TargetDataRef,
-}
-
-impl Drop for TargetData {
- fn drop(&mut self) {
- unsafe {
- LLVMDisposeTargetData(self.lltd);
- }
- }
-}
-
-fn mk_target_data(string_rep: &str) -> TargetData {
- let string_rep = CString::new(string_rep).unwrap();
- TargetData { lltd: unsafe { LLVMCreateTargetData(string_rep.as_ptr()) } }
-}
-
-// Memory-managed interface to object files.
-
-pub struct ObjectFile {
- pub llof: ObjectFileRef,
-}
-
-unsafe impl Send for ObjectFile {}
-
-impl ObjectFile {
- // This will take ownership of llmb
- pub fn new(llmb: MemoryBufferRef) -> Option<ObjectFile> {
- unsafe {
- let llof = LLVMCreateObjectFile(llmb);
- if llof as isize == 0 {
- // LLVMCreateObjectFile took ownership of llmb
- return None;
- }
-
- Some(ObjectFile { llof: llof })
- }
- }
-}
-
-impl Drop for ObjectFile {
- fn drop(&mut self) {
- unsafe {
- LLVMDisposeObjectFile(self.llof);
- }
- }
-}
-
-// Memory-managed interface to section iterators.
-
-pub struct SectionIter {
- pub llsi: SectionIteratorRef,
-}
-
-impl Drop for SectionIter {
- fn drop(&mut self) {
- unsafe {
- LLVMDisposeSectionIterator(self.llsi);
- }
- }
-}
-
-pub fn mk_section_iter(llof: ObjectFileRef) -> SectionIter {
- unsafe { SectionIter { llsi: LLVMGetSections(llof) } }
-}
-
-/// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
-pub fn get_param(llfn: ValueRef, index: c_uint) -> ValueRef {
- unsafe {
- assert!(index < LLVMCountParams(llfn),
- "out of bounds argument access: {} out of {} arguments", index, LLVMCountParams(llfn));
- LLVMGetParam(llfn, index)
- }
-}
-
-fn get_params(llfn: ValueRef) -> Vec<ValueRef> {
- unsafe {
- let num_params = LLVMCountParams(llfn);
-
- (0..num_params).map(|idx| LLVMGetParam(llfn, idx)).collect()
- }
-}
-
-pub fn build_string<F>(f: F) -> Option<String>
- where F: FnOnce(RustStringRef)
-{
- let mut buf = RefCell::new(Vec::new());
- f(&mut buf as RustStringRepr as RustStringRef);
- String::from_utf8(buf.into_inner()).ok()
-}
-
-pub unsafe fn twine_to_string(tr: TwineRef) -> String {
- build_string(|s| LLVMRustWriteTwineToString(tr, s)).expect("got a non-UTF8 Twine from LLVM")
-}
+// NOTE: This crate only exists to allow linking on mingw targets.
+/// Initialize targets enabled by the build script via `cfg(llvm_component = "...")`.
+/// NB: this function can't be moved to `rustc_codegen_llvm` because of the `cfg`s.
pub fn initialize_available_targets() {
macro_rules! init_target(
($cfg:meta, $($method:ident),*) => { {
LLVMInitializeMSP430Target,
LLVMInitializeMSP430TargetMC,
LLVMInitializeMSP430AsmPrinter);
+ init_target!(llvm_component = "riscv",
+ LLVMInitializeRISCVTargetInfo,
+ LLVMInitializeRISCVTarget,
+ LLVMInitializeRISCVTargetMC,
+ LLVMInitializeRISCVAsmPrinter,
+ LLVMInitializeRISCVAsmParser);
init_target!(llvm_component = "sparc",
LLVMInitializeSparcTargetInfo,
LLVMInitializeSparcTarget,
LLVMInitializeWebAssemblyTargetMC,
LLVMInitializeWebAssemblyAsmPrinter);
}
-
-pub fn last_error() -> Option<String> {
- unsafe {
- let cstr = LLVMRustGetLastError();
- if cstr.is_null() {
- None
- } else {
- let err = CStr::from_ptr(cstr).to_bytes();
- let err = String::from_utf8_lossy(err).to_string();
- libc::free(cstr as *mut _);
- Some(err)
- }
- }
-}
-
-pub struct OperandBundleDef {
- inner: OperandBundleDefRef,
-}
-
-impl OperandBundleDef {
- pub fn new(name: &str, vals: &[ValueRef]) -> OperandBundleDef {
- let name = CString::new(name).unwrap();
- let def = unsafe {
- LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint)
- };
- OperandBundleDef { inner: def }
- }
-
- pub fn raw(&self) -> OperandBundleDefRef {
- self.inner
- }
-}
-
-impl Drop for OperandBundleDef {
- fn drop(&mut self) {
- unsafe {
- LLVMRustFreeOperandBundleDef(self.inner);
- }
- }
-}
syntax = { path = "../libsyntax" }
syntax_ext = { path = "../libsyntax_ext" }
syntax_pos = { path = "../libsyntax_pos" }
+rustc_metadata_utils = { path = "../librustc_metadata_utils" }
use rustc::session::config::{Sanitizer, self};
use rustc_target::spec::{PanicStrategy, TargetTriple};
use rustc::session::search_paths::PathKind;
-use rustc::middle;
-use rustc::middle::cstore::{validate_crate_name, ExternCrate, ExternCrateSource};
+use rustc::middle::cstore::{ExternCrate, ExternCrateSource};
use rustc::util::common::record_time;
use rustc::util::nodemap::FxHashSet;
use rustc::hir::map::Definitions;
+use rustc_metadata_utils::validate_crate_name;
+
use std::ops::Deref;
use std::path::PathBuf;
use std::{cmp, fs};
// If we're only compiling an rlib, then there's no need to select a
// panic runtime, so we just skip this section entirely.
let any_non_rlib = self.sess.crate_types.borrow().iter().any(|ct| {
- *ct != config::CrateTypeRlib
+ *ct != config::CrateType::Rlib
});
if !any_non_rlib {
info!("panic runtime injection skipped, only generating rlib");
if !self.sess.crate_types.borrow().iter().all(|ct| {
match *ct {
// Link the runtime
- config::CrateTypeStaticlib |
- config::CrateTypeExecutable => true,
+ config::CrateType::Staticlib |
+ config::CrateType::Executable => true,
// This crate will be compiled with the required
// instrumentation pass
- config::CrateTypeRlib |
- config::CrateTypeDylib |
- config::CrateTypeCdylib =>
+ config::CrateType::Rlib |
+ config::CrateType::Dylib |
+ config::CrateType::Cdylib =>
false,
_ => {
self.sess.err(&format!("Only executables, staticlibs, \
if !self.sess.crate_types.borrow().iter().all(|ct| {
match *ct {
// Link the runtime
- config::CrateTypeExecutable => true,
+ config::CrateType::Executable => true,
// This crate will be compiled with the required
// instrumentation pass
- config::CrateTypeRlib => false,
+ config::CrateType::Rlib => false,
_ => {
self.sess.err(&format!("Only executables and rlibs can be \
compiled with `-Z sanitizer`"));
let mut need_exe_alloc = false;
for ct in self.sess.crate_types.borrow().iter() {
match *ct {
- config::CrateTypeExecutable => need_exe_alloc = true,
- config::CrateTypeDylib |
- config::CrateTypeProcMacro |
- config::CrateTypeCdylib |
- config::CrateTypeStaticlib => need_lib_alloc = true,
- config::CrateTypeRlib => {}
+ config::CrateType::Executable => need_exe_alloc = true,
+ config::CrateType::Dylib |
+ config::CrateType::ProcMacro |
+ config::CrateType::Cdylib |
+ config::CrateType::Staticlib => need_lib_alloc = true,
+ config::CrateType::Rlib => {}
}
}
if !need_lib_alloc && !need_exe_alloc {
}
}
-impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
- fn postprocess(&mut self, krate: &ast::Crate) {
+impl<'a> CrateLoader<'a> {
+ pub fn postprocess(&mut self, krate: &ast::Crate) {
// inject the sanitizer runtime before the allocator runtime because all
// sanitizers force the use of the `alloc_system` allocator
self.inject_sanitizer_runtime();
}
}
- fn process_extern_crate(&mut self, item: &ast::Item, definitions: &Definitions) -> CrateNum {
+ pub fn process_extern_crate(
+ &mut self, item: &ast::Item, definitions: &Definitions,
+ ) -> CrateNum {
match item.node {
ast::ItemKind::ExternCrate(orig_name) => {
debug!("resolving extern crate stmt. ident: {} orig_name: {:?}",
}
}
- fn process_path_extern(
+ pub fn process_path_extern(
&mut self,
name: Symbol,
span: Span,
cnum
}
- fn process_use_extern(
+ pub fn process_use_extern(
&mut self,
name: Symbol,
span: Span,
pub metadata_loader: Box<dyn MetadataLoader + Sync>,
}
+pub enum LoadedMacro {
+ MacroDef(ast::Item),
+ ProcMacro(Lrc<SyntaxExtension>),
+}
+
impl CStore {
pub fn new(metadata_loader: Box<dyn MetadataLoader + Sync>) -> CStore {
CStore {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use cstore;
+use cstore::{self, LoadedMacro};
use encoder;
use link_args;
use native_libs;
use rustc::ty::query::QueryConfig;
use rustc::middle::cstore::{CrateStore, DepKind,
- MetadataLoader, LinkMeta,
- LoadedMacro, EncodedMetadata, NativeLibraryKind};
+ LinkMeta,
+ EncodedMetadata, NativeLibraryKind};
use rustc::middle::exported_symbols::ExportedSymbol;
use rustc::middle::stability::DeprecationEntry;
use rustc::hir::def;
};
}
-impl CrateStore for cstore::CStore {
- fn crate_data_as_rc_any(&self, krate: CrateNum) -> Lrc<dyn Any> {
- self.get_crate_data(krate)
- }
-
- fn metadata_loader(&self) -> &dyn MetadataLoader {
- &*self.metadata_loader
- }
-
- fn visibility_untracked(&self, def: DefId) -> ty::Visibility {
- self.get_crate_data(def.krate).get_visibility(def.index)
- }
-
- fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics {
- self.get_crate_data(def.krate).get_generics(def.index, sess)
- }
-
- fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem
- {
- self.get_crate_data(def.krate).get_associated_item(def.index)
- }
-
- fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind
- {
- let data = self.get_crate_data(cnum);
- let r = *data.dep_kind.lock();
- r
- }
-
- fn export_macros_untracked(&self, cnum: CrateNum) {
+impl cstore::CStore {
+ pub fn export_macros_untracked(&self, cnum: CrateNum) {
let data = self.get_crate_data(cnum);
let mut dep_kind = data.dep_kind.lock();
if *dep_kind == DepKind::UnexportedMacrosOnly {
}
}
- fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol
- {
- self.get_crate_data(cnum).name
- }
-
- fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator
- {
- self.get_crate_data(cnum).root.disambiguator
- }
-
- fn crate_hash_untracked(&self, cnum: CrateNum) -> hir::svh::Svh
- {
- self.get_crate_data(cnum).root.hash
+ pub fn dep_kind_untracked(&self, cnum: CrateNum) -> DepKind {
+ let data = self.get_crate_data(cnum);
+ let r = *data.dep_kind.lock();
+ r
}
- fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition
- {
+ pub fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition {
self.get_crate_data(cnum).root.edition
}
- /// Returns the `DefKey` for a given `DefId`. This indicates the
- /// parent `DefId` as well as some idea of what kind of data the
- /// `DefId` refers to.
- fn def_key(&self, def: DefId) -> DefKey {
- // Note: loading the def-key (or def-path) for a def-id is not
- // a *read* of its metadata. This is because the def-id is
- // really just an interned shorthand for a def-path, which is the
- // canonical name for an item.
- //
- // self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).def_key(def.index)
- }
-
- fn def_path(&self, def: DefId) -> DefPath {
- // See `Note` above in `def_key()` for why this read is
- // commented out:
- //
- // self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).def_path(def.index)
- }
-
- fn def_path_hash(&self, def: DefId) -> DefPathHash {
- self.get_crate_data(def.krate).def_path_hash(def.index)
- }
-
- fn def_path_table(&self, cnum: CrateNum) -> Lrc<DefPathTable> {
- self.get_crate_data(cnum).def_path_table.clone()
- }
-
- fn struct_field_names_untracked(&self, def: DefId) -> Vec<ast::Name>
- {
+ pub fn struct_field_names_untracked(&self, def: DefId) -> Vec<ast::Name> {
self.get_crate_data(def.krate).get_struct_field_names(def.index)
}
- fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<def::Export>
- {
+ pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<def::Export> {
let mut result = vec![];
self.get_crate_data(def_id.krate)
.each_child_of_item(def_id.index, |child| result.push(child), sess);
result
}
- fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
+ pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
let data = self.get_crate_data(id.krate);
if let Some(ref proc_macros) = data.proc_macros {
return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone());
})
}
+ pub fn associated_item_cloned_untracked(&self, def: DefId) -> ty::AssociatedItem {
+ self.get_crate_data(def.krate).get_associated_item(def.index)
+ }
+}
+
+impl CrateStore for cstore::CStore {
+ fn crate_data_as_rc_any(&self, krate: CrateNum) -> Lrc<dyn Any> {
+ self.get_crate_data(krate)
+ }
+
+ fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics {
+ self.get_crate_data(def.krate).get_generics(def.index, sess)
+ }
+
+ fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol
+ {
+ self.get_crate_data(cnum).name
+ }
+
+ fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator
+ {
+ self.get_crate_data(cnum).root.disambiguator
+ }
+
+ fn crate_hash_untracked(&self, cnum: CrateNum) -> hir::svh::Svh
+ {
+ self.get_crate_data(cnum).root.hash
+ }
+
+ /// Returns the `DefKey` for a given `DefId`. This indicates the
+ /// parent `DefId` as well as some idea of what kind of data the
+ /// `DefId` refers to.
+ fn def_key(&self, def: DefId) -> DefKey {
+ // Note: loading the def-key (or def-path) for a def-id is not
+ // a *read* of its metadata. This is because the def-id is
+ // really just an interned shorthand for a def-path, which is the
+ // canonical name for an item.
+ //
+ // self.dep_graph.read(DepNode::MetaData(def));
+ self.get_crate_data(def.krate).def_key(def.index)
+ }
+
+ fn def_path(&self, def: DefId) -> DefPath {
+ // See `Note` above in `def_key()` for why this read is
+ // commented out:
+ //
+ // self.dep_graph.read(DepNode::MetaData(def));
+ self.get_crate_data(def.krate).def_path(def.index)
+ }
+
+ fn def_path_hash(&self, def: DefId) -> DefPathHash {
+ self.get_crate_data(def.krate).def_path_hash(def.index)
+ }
+
+ fn def_path_table(&self, cnum: CrateNum) -> Lrc<DefPathTable> {
+ self.get_crate_data(cnum).def_path_table.clone()
+ }
+
fn crates_untracked(&self) -> Vec<CrateNum>
{
let mut result = vec![];
use rustc::ty::{self, Ty, TyCtxt, ReprOptions, SymbolName};
use rustc::ty::codec::{self as ty_codec, TyEncoder};
-use rustc::session::config::{self, CrateTypeProcMacro};
+use rustc::session::config::{self, CrateType};
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
let attrs = tcx.hir.krate_attrs();
let link_meta = self.link_meta;
- let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro);
+ let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
let has_default_lib_allocator = attr::contains_name(&attrs, "default_lib_allocator");
let has_global_allocator = *tcx.sess.has_global_allocator.get();
}
fn encode_dylib_dependency_formats(&mut self, _: ()) -> LazySeq<Option<LinkagePreference>> {
- match self.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) {
+ match self.tcx.sess.dependency_formats.borrow().get(&config::CrateType::Dylib) {
Some(arr) => {
self.lazy_seq(arr.iter().map(|slot| {
match *slot {
extern crate rustc_errors as errors;
extern crate syntax_ext;
extern crate proc_macro;
+extern crate rustc_metadata_utils;
#[macro_use]
extern crate rustc;
--- /dev/null
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_metadata_utils"
+version = "0.0.0"
+
+[lib]
+name = "rustc_metadata_utils"
+path = "lib.rs"
+crate-type = ["dylib"]
+
+[dependencies]
+rustc = { path = "../librustc" }
+syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
--- /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.
+
+#[macro_use]
+extern crate rustc;
+extern crate syntax_pos;
+
+use rustc::session::Session;
+use syntax_pos::Span;
+
+pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
+ let mut err_count = 0;
+ {
+ let mut say = |s: &str| {
+ match (sp, sess) {
+ (_, None) => bug!("{}", s),
+ (Some(sp), Some(sess)) => sess.span_err(sp, s),
+ (None, Some(sess)) => sess.err(s),
+ }
+ err_count += 1;
+ };
+ if s.is_empty() {
+ say("crate name must not be empty");
+ }
+ for c in s.chars() {
+ if c.is_alphanumeric() { continue }
+ if c == '_' { continue }
+ say(&format!("invalid character `{}` in crate name: `{}`", c, s));
+ }
+ }
+
+ if err_count > 0 {
+ sess.unwrap().abort_if_errors();
+ }
+}
use borrow_check::WriteKind;
use rustc::middle::region::ScopeTree;
+use rustc::mir::VarBindingForm;
use rustc::mir::{BindingForm, BorrowKind, ClearCrossCrate, Field, Local};
use rustc::mir::{LocalDecl, LocalKind, Location, Operand, Place};
use rustc::mir::{ProjectionElem, Rvalue, Statement, StatementKind};
-use rustc::mir::VarBindingForm;
use rustc::ty;
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::sync::Lrc;
+use rustc_errors::DiagnosticBuilder;
use syntax_pos::Span;
use super::borrow_set::BorrowData;
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
pub(super) fn report_use_of_moved_or_uninitialized(
&mut self,
- _context: Context,
+ context: Context,
desired_action: InitializationRequiringAction,
(place, span): (&Place<'tcx>, Span),
mpi: MovePathIndex,
curr_move_out: &FlowAtLocation<MovingOutStatements<'_, 'gcx, 'tcx>>,
) {
+ let use_spans = self
+ .move_spans(place, context.loc)
+ .or_else(|| self.borrow_spans(span, context.loc));
+ let span = use_spans.args_or_use();
+
let mois = self.move_data.path_map[mpi]
.iter()
.filter(|moi| curr_move_out.contains(moi))
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
};
- let mut err = self.tcx
- .cannot_act_on_uninitialized_variable(
- span,
- desired_action.as_noun(),
- &self
- .describe_place_with_options(place, IncludingDowncast(true))
- .unwrap_or("_".to_owned()),
- Origin::Mir,
- );
+ let mut err = self.tcx.cannot_act_on_uninitialized_variable(
+ span,
+ desired_action.as_noun(),
+ &self
+ .describe_place_with_options(place, IncludingDowncast(true))
+ .unwrap_or("_".to_owned()),
+ Origin::Mir,
+ );
err.span_label(span, format!("use of possibly uninitialized {}", item_msg));
+
+ use_spans.var_span_label(
+ &mut err,
+ format!("{} occurs due to use in closure", desired_action.as_noun()),
+ );
+
err.buffer(&mut self.errors_buffer);
} else {
let msg = ""; //FIXME: add "partially " or "collaterally "
let mut is_loop_move = false;
for moi in &mois {
- let move_msg = ""; //FIXME: add " (into closure)"
- let move_span = self
- .mir
- .source_info(self.move_data.moves[**moi].source)
- .span;
+ let move_out = self.move_data.moves[**moi];
+ let moved_place = &self.move_data.move_paths[move_out.path].place;
+
+ let move_spans = self.move_spans(moved_place, move_out.source);
+ let move_span = move_spans.args_or_use();
+
+ let move_msg = if move_spans.for_closure() {
+ " into closure"
+ } else {
+ ""
+ };
+
if span == move_span {
err.span_label(
span,
is_loop_move = true;
} else {
err.span_label(move_span, format!("value moved{} here", move_msg));
+ move_spans.var_span_label(&mut err, "variable moved due to use in closure");
};
}
+
+ use_spans.var_span_label(
+ &mut err,
+ format!("{} occurs due to use in closure", desired_action.as_noun()),
+ );
+
if !is_loop_move {
err.span_label(
span,
pub(super) fn report_move_out_while_borrowed(
&mut self,
context: Context,
- (place, span): (&Place<'tcx>, Span),
+ (place, _span): (&Place<'tcx>, Span),
borrow: &BorrowData<'tcx>,
) {
let tcx = self.tcx;
Some(name) => format!("`{}`", name),
None => "value".to_owned(),
};
+
+ let borrow_spans = self.retrieve_borrow_spans(borrow);
+ let borrow_span = borrow_spans.args_or_use();
+
+ let move_spans = self.move_spans(place, context.loc);
+ let span = move_spans.args_or_use();
+
let mut err = tcx.cannot_move_when_borrowed(
span,
&self.describe_place(place).unwrap_or("_".to_owned()),
Origin::Mir,
);
- err.span_label(
- self.retrieve_borrow_span(borrow),
- format!("borrow of {} occurs here", borrow_msg),
- );
+ err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
err.span_label(span, format!("move out of {} occurs here", value_msg));
+
+ borrow_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
+
+ move_spans.var_span_label(&mut err, "move occurs due to use in closure");
+
self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
err.buffer(&mut self.errors_buffer);
}
pub(super) fn report_use_while_mutably_borrowed(
&mut self,
context: Context,
- (place, span): (&Place<'tcx>, Span),
+ (place, _span): (&Place<'tcx>, Span),
borrow: &BorrowData<'tcx>,
) {
let tcx = self.tcx;
+
+ let borrow_spans = self.retrieve_borrow_spans(borrow);
+ let borrow_span = borrow_spans.args_or_use();
+
+ // Conflicting borrows are reported separately, so only check for move
+ // captures.
+ let use_spans = self.move_spans(place, context.loc);
+ let span = use_spans.var_or_use();
+
let mut err = tcx.cannot_use_when_mutably_borrowed(
span,
&self.describe_place(place).unwrap_or("_".to_owned()),
- self.retrieve_borrow_span(borrow),
+ borrow_span,
&self
.describe_place(&borrow.borrowed_place)
.unwrap_or("_".to_owned()),
Origin::Mir,
);
- self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
- err.buffer(&mut self.errors_buffer);
- }
-
- /// Finds the span of arguments of a closure (within `maybe_closure_span`) and its usage of
- /// the local assigned at `location`.
- /// This is done by searching in statements succeeding `location`
- /// and originating from `maybe_closure_span`.
- pub(super) fn find_closure_span(
- &self,
- maybe_closure_span: Span,
- location: Location,
- ) -> Option<(Span, Span)> {
- use rustc::hir::ExprKind::Closure;
- use rustc::mir::AggregateKind;
-
- let local = match self.mir[location.block]
- .statements
- .get(location.statement_index)
- {
- Some(&Statement {
- kind: StatementKind::Assign(Place::Local(local), _),
- ..
- }) => local,
- _ => return None,
- };
-
- for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
- if maybe_closure_span != stmt.source_info.span {
- break;
- }
+ borrow_spans.var_span_label(&mut err, {
+ let place = &borrow.borrowed_place;
+ let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
- if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
- if let AggregateKind::Closure(def_id, _) = **kind {
- debug!("find_closure_span: found closure {:?}", places);
+ format!("borrow occurs due to use of `{}` in closure", desc_place)
+ });
- return if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
- let args_span = if let Closure(_, _, _, span, _) =
- self.tcx.hir.expect_expr(node_id).node
- {
- span
- } else {
- return None;
- };
-
- self.tcx
- .with_freevars(node_id, |freevars| {
- for (v, place) in freevars.iter().zip(places) {
- match *place {
- Operand::Copy(Place::Local(l))
- | Operand::Move(Place::Local(l)) if local == l =>
- {
- debug!(
- "find_closure_span: found captured local {:?}",
- l
- );
- return Some(v.span);
- }
- _ => {}
- }
- }
- None
- })
- .map(|var_span| (args_span, var_span))
- } else {
- None
- };
- }
- }
- }
-
- None
+ self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
+ err.buffer(&mut self.errors_buffer);
}
pub(super) fn report_conflicting_borrow(
gen_borrow_kind: BorrowKind,
issued_borrow: &BorrowData<'tcx>,
) {
- let issued_span = self.retrieve_borrow_span(issued_borrow);
+ let issued_spans = self.retrieve_borrow_spans(issued_borrow);
+ let issued_span = issued_spans.args_or_use();
- let new_closure_span = self.find_closure_span(span, context.loc);
- let span = new_closure_span.map(|(args, _)| args).unwrap_or(span);
- let old_closure_span = self.find_closure_span(issued_span, issued_borrow.reserve_location);
- let issued_span = old_closure_span
- .map(|(args, _)| args)
- .unwrap_or(issued_span);
+ let borrow_spans = self.borrow_spans(span, context.loc);
+ let span = borrow_spans.args_or_use();
let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
let tcx = self.tcx;
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(),
};
- if let Some((_, var_span)) = old_closure_span {
- let place = &issued_borrow.borrowed_place;
- let desc_place = self.describe_place(place).unwrap_or("_".to_owned());
-
- err.span_label(
- var_span,
+ if issued_spans == borrow_spans {
+ borrow_spans.var_span_label(
+ &mut err,
format!(
- "previous borrow occurs due to use of `{}` in closure",
+ "borrows occur due to use of `{}` in closure",
desc_place
),
);
- }
+ } else {
+ let borrow_place = &issued_borrow.borrowed_place;
+ let borrow_place_desc = self.describe_place(borrow_place).unwrap_or("_".to_owned());
+ issued_spans.var_span_label(
+ &mut err,
+ format!(
+ "first borrow occurs due to use of `{}` in closure",
+ borrow_place_desc
+ ),
+ );
- if let Some((_, var_span)) = new_closure_span {
- err.span_label(
- var_span,
- format!("borrow occurs due to use of `{}` in closure", desc_place),
+ borrow_spans.var_span_label(
+ &mut err,
+ format!("second borrow occurs due to use of `{}` in closure", desc_place),
);
}
.last()
.unwrap();
- let borrow_span = self.mir.source_info(borrow.reserve_location).span;
+ let borrow_spans = self.retrieve_borrow_spans(borrow);
+ let borrow_span = borrow_spans.var_or_use();
+
let proper_span = match *root_place {
Place::Local(local) => self.mir.local_decls[local].source_info.span,
_ => drop_span,
self.access_place_error_reported
.insert((root_place.clone(), borrow_span));
- match &self.describe_place(&borrow.borrowed_place) {
- Some(name) => {
- self.report_local_value_does_not_live_long_enough(
- context,
- name,
- &scope_tree,
- &borrow,
- drop_span,
- borrow_span,
- proper_span,
- kind.map(|k| (k, place_span.0)),
- );
- }
- None => {
- self.report_temporary_value_does_not_live_long_enough(
- context,
- &scope_tree,
- &borrow,
- drop_span,
- borrow_span,
- proper_span,
- );
- }
- }
+ let mut err = match &self.describe_place(&borrow.borrowed_place) {
+ Some(name) => self.report_local_value_does_not_live_long_enough(
+ context,
+ name,
+ &scope_tree,
+ &borrow,
+ drop_span,
+ borrow_span,
+ proper_span,
+ kind.map(|k| (k, place_span.0)),
+ ),
+ None => self.report_temporary_value_does_not_live_long_enough(
+ context,
+ &scope_tree,
+ &borrow,
+ drop_span,
+ borrow_span,
+ proper_span,
+ ),
+ };
+
+ borrow_spans.args_span_label(&mut err, "value captured here");
+
+ err.buffer(&mut self.errors_buffer);
}
fn report_local_value_does_not_live_long_enough(
borrow_span: Span,
_proper_span: Span,
kind_place: Option<(WriteKind, &Place<'tcx>)>,
- ) {
+ ) -> DiagnosticBuilder<'cx> {
debug!(
"report_local_value_does_not_live_long_enough(\
{:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
);
self.explain_why_borrow_contains_point(context, borrow, kind_place, &mut err);
- err.buffer(&mut self.errors_buffer);
+ err
}
fn report_temporary_value_does_not_live_long_enough(
drop_span: Span,
_borrow_span: Span,
proper_span: Span,
- ) {
+ ) -> DiagnosticBuilder<'cx> {
debug!(
"report_temporary_value_does_not_live_long_enough(\
{:?}, {:?}, {:?}, {:?}, {:?}\
err.span_label(drop_span, "temporary value only lives until here");
self.explain_why_borrow_contains_point(context, borrow, None, &mut err);
- err.buffer(&mut self.errors_buffer);
+ err
}
pub(super) fn report_illegal_mutation_of_borrowed(
(place, span): (&Place<'tcx>, Span),
loan: &BorrowData<'tcx>,
) {
+ let loan_spans = self.retrieve_borrow_spans(loan);
+ let loan_span = loan_spans.args_or_use();
+
let tcx = self.tcx;
let mut err = tcx.cannot_assign_to_borrowed(
span,
- self.retrieve_borrow_span(loan),
+ loan_span,
&self.describe_place(place).unwrap_or("_".to_owned()),
Origin::Mir,
);
+ loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
+
self.explain_why_borrow_contains_point(context, loan, None, &mut err);
err.buffer(&mut self.errors_buffer);
// PATTERN;) then make the error refer to that local, rather than the
// place being assigned later.
let (place_description, assigned_span) = match local_decl {
- Some(LocalDecl { is_user_variable: Some(ClearCrossCrate::Clear), .. })
- | Some(LocalDecl { is_user_variable: Some(ClearCrossCrate::Set(
- BindingForm::Var(VarBindingForm {
- opt_match_place: None, ..
- }))), ..})
- | Some(LocalDecl { is_user_variable: None, .. })
+ Some(LocalDecl {
+ is_user_variable: Some(ClearCrossCrate::Clear),
+ ..
+ })
+ | Some(LocalDecl {
+ is_user_variable:
+ Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
+ opt_match_place: None,
+ ..
+ }))),
+ ..
+ })
+ | Some(LocalDecl {
+ is_user_variable: None,
+ ..
+ })
| None => (self.describe_place(place), assigned_span),
Some(decl) => (self.describe_place(err_place), decl.source_info.span),
};
Place::Projection(ref proj) => {
match proj.elem {
ProjectionElem::Deref => {
- let upvar_field_projection = place.is_upvar_field_projection(
- self.mir, &self.tcx);
+ let upvar_field_projection =
+ place.is_upvar_field_projection(self.mir, &self.tcx);
if let Some(field) = upvar_field_projection {
let var_index = field.index();
let name = self.mir.upvar_decls[var_index].debug_name.to_string();
&including_downcast,
)?;
} else if let Place::Local(local) = proj.base {
- if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard))
- = self.mir.local_decls[local].is_user_variable {
+ if let Some(ClearCrossCrate::Set(BindingForm::RefForGuard)) =
+ self.mir.local_decls[local].is_user_variable
+ {
self.append_place_to_string(
&proj.base,
buf,
ProjectionElem::Field(field, _ty) => {
autoderef = true;
- let upvar_field_projection = place.is_upvar_field_projection(
- self.mir, &self.tcx);
+ let upvar_field_projection =
+ place.is_upvar_field_projection(self.mir, &self.tcx);
if let Some(field) = upvar_field_projection {
let var_index = field.index();
let name = self.mir.upvar_decls[var_index].debug_name.to_string();
ty::TyAdt(def, _) => if def.is_enum() {
field.index().to_string()
} else {
- def.non_enum_variant().fields[field.index()].ident.to_string()
+ def.non_enum_variant().fields[field.index()]
+ .ident
+ .to_string()
},
ty::TyTuple(_) => field.index().to_string(),
ty::TyRef(_, ty, _) | ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
}
}
- // Retrieve span of given borrow from the current MIR representation
- crate fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
- self.mir.source_info(borrow.reserve_location).span
- }
-
// Retrieve type of a place for the current MIR representation
fn retrieve_type_for_place(&self, place: &Place<'tcx>) -> Option<ty::Ty> {
match place {
}
}
}
+
+// The span(s) associated to a use of a place.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub(super) enum UseSpans {
+ // The access is caused by capturing a variable for a closure.
+ ClosureUse {
+ // The span of the args of the closure, including the `move` keyword if
+ // it's present.
+ args_span: Span,
+ // The span of the first use of the captured variable inside the closure.
+ var_span: Span
+ },
+ // This access has a single span associated to it: common case.
+ OtherUse(Span),
+}
+
+impl UseSpans {
+ pub(super) fn args_or_use(self) -> Span {
+ match self {
+ UseSpans::ClosureUse {
+ args_span: span, ..
+ }
+ | UseSpans::OtherUse(span) => span,
+ }
+ }
+
+ pub(super) fn var_or_use(self) -> Span {
+ match self {
+ UseSpans::ClosureUse { var_span: span, .. } | UseSpans::OtherUse(span) => span,
+ }
+ }
+
+ // Add a span label to the arguments of the closure, if it exists.
+ pub(super) fn args_span_label(self, err: &mut DiagnosticBuilder, message: impl Into<String>) {
+ if let UseSpans::ClosureUse { args_span, .. } = self {
+ err.span_label(args_span, message);
+ }
+ }
+
+ // Add a span label to the use of the captured variable, if it exists.
+ pub(super) fn var_span_label(self, err: &mut DiagnosticBuilder, message: impl Into<String>) {
+ if let UseSpans::ClosureUse { var_span, .. } = self {
+ err.span_label(var_span, message);
+ }
+ }
+
+ pub(super) fn for_closure(self) -> bool {
+ match self {
+ UseSpans::ClosureUse { .. } => true,
+ UseSpans::OtherUse(_) => false,
+ }
+ }
+
+ pub(super) fn or_else<F>(self, if_other: F) -> Self
+ where
+ F: FnOnce() -> Self,
+ {
+ match self {
+ closure @ UseSpans::ClosureUse { .. } => closure,
+ UseSpans::OtherUse(_) => if_other(),
+ }
+ }
+}
+
+impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
+ /// Finds the spans associated to a move or copy of move_place at location.
+ pub(super) fn move_spans(
+ &self,
+ moved_place: &Place<'tcx>, // Could also be an upvar.
+ location: Location,
+ ) -> UseSpans {
+ use self::UseSpans::*;
+ use rustc::hir::ExprKind::Closure;
+ use rustc::mir::AggregateKind;
+
+ let stmt = match self.mir[location.block]
+ .statements
+ .get(location.statement_index)
+ {
+ Some(stmt) => stmt,
+ None => return OtherUse(self.mir.source_info(location).span),
+ };
+
+ if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
+ if let AggregateKind::Closure(def_id, _) = **kind {
+ debug!("find_closure_move_span: found closure {:?}", places);
+
+ if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
+ if let Closure(_, _, _, args_span, _) = self.tcx.hir.expect_expr(node_id).node {
+ if let Some(var_span) = self.tcx.with_freevars(node_id, |freevars| {
+ for (v, place) in freevars.iter().zip(places) {
+ match place {
+ Operand::Copy(place) | Operand::Move(place)
+ if moved_place == place =>
+ {
+ debug!(
+ "find_closure_move_span: found captured local {:?}",
+ place
+ );
+ return Some(v.span);
+ }
+ _ => {}
+ }
+ }
+ None
+ }) {
+ return ClosureUse {
+ args_span,
+ var_span,
+ };
+ }
+ }
+ }
+ }
+ }
+
+ return OtherUse(stmt.source_info.span);
+ }
+
+ /// Finds the span of arguments of a closure (within `maybe_closure_span`)
+ /// and its usage of the local assigned at `location`.
+ /// This is done by searching in statements succeeding `location`
+ /// and originating from `maybe_closure_span`.
+ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
+ use self::UseSpans::*;
+ use rustc::hir::ExprKind::Closure;
+ use rustc::mir::AggregateKind;
+
+ let local = match self.mir[location.block]
+ .statements
+ .get(location.statement_index)
+ {
+ Some(&Statement {
+ kind: StatementKind::Assign(Place::Local(local), _),
+ ..
+ }) => local,
+ _ => return OtherUse(use_span),
+ };
+
+ if self.mir.local_kind(local) != LocalKind::Temp {
+ // operands are always temporaries.
+ return OtherUse(use_span);
+ }
+
+ for stmt in &self.mir[location.block].statements[location.statement_index + 1..] {
+ if let StatementKind::Assign(_, Rvalue::Aggregate(ref kind, ref places)) = stmt.kind {
+ if let AggregateKind::Closure(def_id, _) = **kind {
+ debug!("find_closure_borrow_span: found closure {:?}", places);
+
+ return if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
+ let args_span = if let Closure(_, _, _, span, _) =
+ self.tcx.hir.expect_expr(node_id).node
+ {
+ span
+ } else {
+ return OtherUse(use_span);
+ };
+
+ self.tcx
+ .with_freevars(node_id, |freevars| {
+ for (v, place) in freevars.iter().zip(places) {
+ match *place {
+ Operand::Copy(Place::Local(l))
+ | Operand::Move(Place::Local(l))
+ if local == l =>
+ {
+ debug!(
+ "find_closure_borrow_span: found captured local \
+ {:?}",
+ l
+ );
+ return Some(v.span);
+ }
+ _ => {}
+ }
+ }
+ None
+ }).map(|var_span| ClosureUse {
+ args_span,
+ var_span,
+ }).unwrap_or(OtherUse(use_span))
+ } else {
+ OtherUse(use_span)
+ };
+ }
+ }
+
+ if use_span != stmt.source_info.span {
+ break;
+ }
+ }
+
+ OtherUse(use_span)
+ }
+
+ /// Helper to retrieve span(s) of given borrow from the current MIR
+ /// representation
+ pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData) -> UseSpans {
+ let span = self.mir.source_info(borrow.reserve_location).span;
+ self.borrow_spans(span, borrow.reserve_location)
+ }
+}
use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind};
use rustc::mir::{Terminator, TerminatorKind};
use rustc::ty::query::Providers;
-use rustc::ty::{self, ParamEnv, TyCtxt};
+use rustc::ty::{self, ParamEnv, TyCtxt, Ty};
use rustc_errors::{Diagnostic, DiagnosticBuilder, Level};
use rustc_data_structures::graph::dominators::Dominators;
}
if mbcx.errors_buffer.len() > 0 {
+ mbcx.errors_buffer.sort_by_key(|diag| diag.span.primary_span());
+
if tcx.migrate_borrowck() {
match tcx.borrowck(def_id).signalled_any_error {
SignalledError::NoErrorsSeen => {
// that is useful later.
let drop_place_ty = gcx.lift(&drop_place_ty).unwrap();
- self.visit_terminator_drop(loc, term, flow_state, drop_place, drop_place_ty, span);
+ debug!("visit_terminator_drop \
+ loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
+ loc, term, drop_place, drop_place_ty, span);
+
+ self.visit_terminator_drop(
+ loc, term, flow_state, drop_place, drop_place_ty, span, SeenTy(None));
}
TerminatorKind::DropAndReplace {
location: ref drop_place,
}
}
+/// A simple linked-list threaded up the stack of recursive calls in `visit_terminator_drop`.
+#[derive(Copy, Clone, Debug)]
+struct SeenTy<'a, 'gcx: 'a>(Option<(Ty<'gcx>, &'a SeenTy<'a, 'gcx>)>);
+
+impl<'a, 'gcx> SeenTy<'a, 'gcx> {
+ /// Return a new list with `ty` prepended to the front of `self`.
+ fn cons(&'a self, ty: Ty<'gcx>) -> Self {
+ SeenTy(Some((ty, self)))
+ }
+
+ /// True if and only if `ty` occurs on the linked list `self`.
+ fn have_seen(self, ty: Ty) -> bool {
+ let mut this = self.0;
+ loop {
+ match this {
+ None => return false,
+ Some((seen_ty, recur)) => {
+ if seen_ty == ty {
+ return true;
+ } else {
+ this = recur.0;
+ continue;
+ }
+ }
+ }
+ }
+ }
+}
+
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
/// Invokes `access_place` as appropriate for dropping the value
/// at `drop_place`. Note that the *actual* `Drop` in the MIR is
drop_place: &Place<'tcx>,
erased_drop_place_ty: ty::Ty<'gcx>,
span: Span,
+ prev_seen: SeenTy<'_, 'gcx>,
) {
+ if prev_seen.have_seen(erased_drop_place_ty) {
+ // if we have directly seen the input ty `T`, then we must
+ // have had some *direct* ownership loop between `T` and
+ // some directly-owned (as in, actually traversed by
+ // recursive calls below) part that is also of type `T`.
+ //
+ // Note: in *all* such cases, the data in question cannot
+ // be constructed (nor destructed) in finite time/space.
+ //
+ // Proper examples, some of which are statically rejected:
+ //
+ // * `struct A { field: A, ... }`:
+ // statically rejected as infinite size
+ //
+ // * `type B = (B, ...);`:
+ // statically rejected as cyclic
+ //
+ // * `struct C { field: Box<C>, ... }`
+ // * `struct D { field: Box<(D, D)>, ... }`:
+ // *accepted*, though impossible to construct
+ //
+ // Here is *NOT* an example:
+ // * `struct Z { field: Option<Box<Z>>, ... }`:
+ // Here, the type is both representable in finite space (due to the boxed indirection)
+ // and constructable in finite time (since the recursion can bottom out with `None`).
+ // This is an obvious instance of something the compiler must accept.
+ //
+ // Since some of the above impossible cases like `C` and
+ // `D` are accepted by the compiler, we must take care not
+ // to infinite-loop while processing them. But since such
+ // cases cannot actually arise, it is sound for us to just
+ // skip them during drop. If the developer uses unsafe
+ // code to construct them, they should not be surprised by
+ // weird drop behavior in their resulting code.
+ debug!("visit_terminator_drop previously seen \
+ erased_drop_place_ty: {:?} on prev_seen: {:?}; returning early.",
+ erased_drop_place_ty, prev_seen);
+ return;
+ }
+
let gcx = self.tcx.global_tcx();
let drop_field = |mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
(index, field): (usize, ty::Ty<'gcx>)| {
let field_ty = gcx.normalize_erasing_regions(mir.param_env, field);
let place = drop_place.clone().field(Field::new(index), field_ty);
- mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span);
+ debug!("visit_terminator_drop drop_field place: {:?} field_ty: {:?}", place, field_ty);
+ let seen = prev_seen.cons(erased_drop_place_ty);
+ mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span, seen);
};
match erased_drop_place_ty.sty {
.enumerate()
.for_each(|field| drop_field(self, field));
}
+
+ // #45696: special-case Box<T> by treating its dtor as
+ // only deep *across owned content*. Namely, we know
+ // dropping a box does not touch data behind any
+ // references it holds; if we were to instead fall into
+ // the base case below, we would have a Deep Write due to
+ // the box being `needs_drop`, and that Deep Write would
+ // touch `&mut` data in the box.
+ ty::TyAdt(def, _) if def.is_box() => {
+ // When/if we add a `&own T` type, this action would
+ // be like running the destructor of the `&own T`.
+ // (And the owner of backing storage referenced by the
+ // `&own T` would be responsible for deallocating that
+ // backing storage.)
+
+ // we model dropping any content owned by the box by
+ // recurring on box contents. This catches cases like
+ // `Box<Box<ScribbleWhenDropped<&mut T>>>`, while
+ // still restricting Write to *owned* content.
+ let ty = erased_drop_place_ty.boxed_ty();
+ let deref_place = drop_place.clone().deref();
+ debug!("visit_terminator_drop drop-box-content deref_place: {:?} ty: {:?}",
+ deref_place, ty);
+ let seen = prev_seen.cons(erased_drop_place_ty);
+ self.visit_terminator_drop(
+ loc, term, flow_state, &deref_place, ty, span, seen);
+ }
+
_ => {
// We have now refined the type of the value being
// dropped (potentially) to just the type of a
// subfield; so check whether that field's type still
- // "needs drop". If so, we assume that the destructor
- // may access any data it likes (i.e., a Deep Write).
+ // "needs drop".
if erased_drop_place_ty.needs_drop(gcx, self.param_env) {
+ // If so, we assume that the destructor may access
+ // any data it likes (i.e., a Deep Write).
self.access_place(
ContextKind::Drop.new(loc),
(drop_place, span),
LocalMutationIsAllowed::Yes,
flow_state,
);
+ } else {
+ // If there is no destructor, we still include a
+ // *shallow* write. This essentially ensures that
+ // borrows of the memory directly at `drop_place`
+ // cannot continue to be borrowed across the drop.
+ //
+ // If we were to use a Deep Write here, then any
+ // `&mut T` that is reachable from `drop_place`
+ // would get invalidated; fixing that is the
+ // essence of resolving issue #45696.
+ //
+ // * Note: In the compiler today, doing a Deep
+ // Write here would not actually break
+ // anything beyond #45696; for example it does not
+ // break this example:
+ //
+ // ```rust
+ // fn reborrow(x: &mut i32) -> &mut i32 { &mut *x }
+ // ```
+ //
+ // Why? Because we do not schedule/emit
+ // `Drop(x)` in the MIR unless `x` needs drop in
+ // the first place.
+ //
+ // FIXME: Its possible this logic actually should
+ // be attached to the `StorageDead` statement
+ // rather than the `Drop`. See discussion on PR
+ // #52782.
+ self.access_place(
+ ContextKind::Drop.new(loc),
+ (drop_place, span),
+ (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
+ LocalMutationIsAllowed::Yes,
+ flow_state,
+ );
}
}
}
if borrow_of_local_data(&borrow.borrowed_place) {
let err = self.tcx
.cannot_borrow_across_generator_yield(
- self.retrieve_borrow_span(borrow),
+ self.retrieve_borrow_spans(borrow).var_or_use(),
yield_span,
Origin::Mir,
);
// another match arm
binds_to.sort();
binds_to.dedup();
- for local in binds_to {
+ let mut multipart_suggestion = Vec::with_capacity(binds_to.len());
+ for (j, local) in binds_to.into_iter().enumerate() {
let bind_to = &self.mir.local_decls[local];
let binding_span = bind_to.source_info.span;
Mutability::Not => "ref",
Mutability::Mut => "ref mut",
};
+ if j == 0 {
+ err.span_label(binding_span, format!("data moved here"));
+ } else {
+ err.span_label(binding_span, format!("... and here"));
+ }
match bind_to.name {
Some(name) => {
- err.span_suggestion(
- binding_span,
- "to prevent move, use ref or ref mut",
- format!("{} {:?}", ref_kind, name),
- );
+ multipart_suggestion.push((binding_span,
+ format!("{} {}", ref_kind, name)));
}
None => {
err.span_label(
}
}
}
+ err.multipart_suggestion("to prevent move, use ref or ref mut",
+ multipart_suggestion);
}
// Nothing to suggest.
GroupedMoveError::OtherIllegalMove { .. } => (),
let act;
let acted_on;
-
let span = match error_access {
AccessKind::Move => {
err = self.tcx
act = "borrow as mutable";
acted_on = "borrowed as mutable";
- let closure_span = self.find_closure_span(span, location);
- if let Some((args, var)) = closure_span {
- err = self.tcx.cannot_borrow_path_as_mutable_because(
- args,
- &item_msg,
- &reason,
- Origin::Mir,
- );
- err.span_label(
- var,
- format!(
- "mutable borrow occurs due to use of `{}` in closure",
- self.describe_place(access_place).unwrap(),
- ),
- );
- args
- } else {
- err = self.tcx.cannot_borrow_path_as_mutable_because(
- span,
- &item_msg,
- &reason,
- Origin::Mir,
- );
- span
- }
+ let borrow_spans = self.borrow_spans(span, location);
+ let borrow_span = borrow_spans.args_or_use();
+ err = self.tcx.cannot_borrow_path_as_mutable_because(
+ borrow_span,
+ &item_msg,
+ &reason,
+ Origin::Mir,
+ );
+ borrow_spans.var_span_label(
+ &mut err,
+ format!(
+ "mutable borrow occurs due to use of `{}` in closure",
+ // always Some() if the message is printed.
+ self.describe_place(access_place).unwrap_or(String::new()),
+ )
+ );
+ borrow_span
}
};
let local_decl = &self.mir.local_decls[*local];
let suggestion = match local_decl.is_user_variable.as_ref().unwrap() {
ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf) => {
- Some(suggest_ampmut_self(local_decl))
+ Some(suggest_ampmut_self(self.tcx, local_decl))
}
ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm {
}
}
-fn suggest_ampmut_self<'cx, 'gcx, 'tcx>(local_decl: &mir::LocalDecl<'tcx>) -> (Span, String) {
- (local_decl.source_info.span, "&mut self".to_string())
+fn suggest_ampmut_self<'cx, 'gcx, 'tcx>(
+ tcx: TyCtxt<'cx, 'gcx, 'tcx>,
+ local_decl: &mir::LocalDecl<'tcx>,
+) -> (Span, String) {
+ let sp = local_decl.source_info.span;
+ (sp, match tcx.sess.codemap().span_to_snippet(sp) {
+ Ok(snippet) => {
+ let lt_pos = snippet.find('\'');
+ if let Some(lt_pos) = lt_pos {
+ format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4])
+ } else {
+ "&mut self".to_string()
+ }
+ }
+ _ => "&mut self".to_string()
+ })
}
// When we want to suggest a user change a local variable to be a `&mut`, there
let locations = mir.find_assignments(local);
if locations.len() > 0 {
let assignment_rhs_span = mir.source_info(locations[0]).span;
- let snippet = tcx.sess.codemap().span_to_snippet(assignment_rhs_span);
- if let Ok(src) = snippet {
- if src.starts_with('&') {
+ if let Ok(src) = tcx.sess.codemap().span_to_snippet(assignment_rhs_span) {
+ if let (true, Some(ws_pos)) = (
+ src.starts_with("&'"),
+ src.find(|c: char| -> bool { c.is_whitespace() }),
+ ) {
+ let lt_name = &src[1..ws_pos];
+ let ty = &src[ws_pos..];
+ return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
+ } else if src.starts_with('&') {
let borrowed_expr = src[1..].to_string();
return (assignment_rhs_span, format!("&mut {}", borrowed_expr));
}
None => local_decl.source_info.span,
};
+ if let Ok(src) = tcx.sess.codemap().span_to_snippet(highlight_span) {
+ if let (true, Some(ws_pos)) = (
+ src.starts_with("&'"),
+ src.find(|c: char| -> bool { c.is_whitespace() }),
+ ) {
+ let lt_name = &src[1..ws_pos];
+ let ty = &src[ws_pos..];
+ return (highlight_span, format!("&{} mut{}", lt_name, ty));
+ }
+ }
+
let ty_mut = local_decl.ty.builtin_deref(true).unwrap();
assert_eq!(ty_mut.mutbl, hir::MutImmutable);
- if local_decl.ty.is_region_ptr() {
- (highlight_span, format!("&mut {}", ty_mut.ty))
- } else {
- (highlight_span, format!("*mut {}", ty_mut.ty))
- }
+ (highlight_span,
+ if local_decl.ty.is_region_ptr() {
+ format!("&mut {}", ty_mut.ty)
+ } else {
+ format!("*mut {}", ty_mut.ty)
+ })
}
fn is_closure_or_generator(ty: ty::Ty) -> bool {
--- /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.
+
+//! Identify those variables whose entire value will eventually be
+//! returned from the fn via the RETURN_PLACE. As an optimization, we
+//! can skip computing liveness results for those variables. The idea
+//! is that the return type of the fn only ever contains free
+//! regions. Therefore, the types of those variables are going to
+//! ultimately be contrained to outlive those free regions -- since
+//! free regions are always live for the entire body, this implies
+//! that the liveness results are not important for those regions.
+//! This is most important in the "fns" that we create to represent static
+//! values, since those are often really quite large, and all regions in them
+//! will ultimately be constrained to be `'static`. Two examples:
+//!
+//! ```
+//! fn foo() -> &'static [u32] { &[] }
+//! static FOO: &[u32] = &[];
+//! ```
+//!
+//! In both these cases, the return value will only have static lifetime.
+//!
+//! NB: The simple logic here relies on the fact that outlives
+//! relations in our analysis don't have locations. Otherwise, we
+//! would have to restrict ourselves to values that are
+//! *unconditionally* returned (which would still cover the "big
+//! static value" case).
+//!
+//! The way that this code works is to use union-find -- we iterate
+//! over the MIR and union together two variables X and Y if all
+//! regions in the value of Y are going to be stored into X -- that
+//! is, if `typeof(X): 'a` requires that `typeof(Y): 'a`. This means
+//! that e.g. we can union together `x` and `y` if we have something
+//! like `x = (y, 22)`, but not something like `x = y.f` (since there
+//! may be regions in the type of `y` that do not appear in the field
+//! `f`).
+
+use rustc::mir::visit::Visitor;
+use rustc::mir::*;
+
+use rustc_data_structures::indexed_vec::Idx;
+use rustc_data_structures::unify as ut;
+
+crate struct EscapingLocals {
+ unification_table: ut::UnificationTable<ut::InPlace<AssignedLocal>>,
+}
+
+impl EscapingLocals {
+ crate fn compute(mir: &Mir<'tcx>) -> Self {
+ let mut visitor = GatherAssignedLocalsVisitor::new();
+ visitor.visit_mir(mir);
+
+ EscapingLocals {
+ unification_table: visitor.unification_table,
+ }
+ }
+
+ /// True if `local` is known to escape into static
+ /// memory.
+ crate fn escapes_into_return(&mut self, local: Local) -> bool {
+ let return_place = AssignedLocal::from(RETURN_PLACE);
+ let other_place = AssignedLocal::from(local);
+ self.unification_table.unioned(return_place, other_place)
+ }
+}
+
+/// The MIR visitor gathering the union-find of the locals used in
+/// assignments.
+struct GatherAssignedLocalsVisitor {
+ unification_table: ut::UnificationTable<ut::InPlace<AssignedLocal>>,
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+struct AssignedLocal(u32);
+
+impl ut::UnifyKey for AssignedLocal {
+ type Value = ();
+
+ fn index(&self) -> u32 {
+ self.0
+ }
+
+ fn from_index(i: u32) -> AssignedLocal {
+ AssignedLocal(i)
+ }
+
+ fn tag() -> &'static str {
+ "AssignedLocal"
+ }
+}
+
+impl From<Local> for AssignedLocal {
+ fn from(item: Local) -> Self {
+ // newtype_indexes use usize but are u32s.
+ assert!(item.index() < ::std::u32::MAX as usize);
+ AssignedLocal(item.index() as u32)
+ }
+}
+
+impl GatherAssignedLocalsVisitor {
+ fn new() -> Self {
+ Self {
+ unification_table: ut::UnificationTable::new(),
+ }
+ }
+
+ fn union_locals_if_needed(&mut self, lvalue: Option<Local>, rvalue: Option<Local>) {
+ if let Some(lvalue) = lvalue {
+ if let Some(rvalue) = rvalue {
+ if lvalue != rvalue {
+ debug!("EscapingLocals: union {:?} and {:?}", lvalue, rvalue);
+ self.unification_table
+ .union(AssignedLocal::from(lvalue), AssignedLocal::from(rvalue));
+ }
+ }
+ }
+ }
+}
+
+// Returns the potential `Local` associated to this `Place` or `PlaceProjection`
+fn find_local_in_place(place: &Place) -> Option<Local> {
+ match place {
+ Place::Local(local) => Some(*local),
+
+ // If you do e.g. `x = a.f` then only *part* of the type of
+ // `a` escapes into `x` (the part contained in `f`); if `a`'s
+ // type has regions that don't appear in `f`, those might not
+ // escape.
+ Place::Projection(..) => None,
+
+ Place::Static { .. } | Place::Promoted { .. } => None,
+ }
+}
+
+// Returns the potential `Local` in this `Operand`.
+fn find_local_in_operand(op: &Operand) -> Option<Local> {
+ // Conservatively check a subset of `Operand`s we know our
+ // benchmarks track, for example `html5ever`.
+ match op {
+ Operand::Copy(place) | Operand::Move(place) => find_local_in_place(place),
+ Operand::Constant(_) => None,
+ }
+}
+
+impl Visitor<'tcx> for GatherAssignedLocalsVisitor {
+ fn visit_mir(&mut self, mir: &Mir<'tcx>) {
+ // We need as many union-find keys as there are locals
+ for _ in 0..mir.local_decls.len() {
+ self.unification_table.new_key(());
+ }
+
+ self.super_mir(mir);
+ }
+
+ fn visit_assign(
+ &mut self,
+ block: BasicBlock,
+ place: &Place<'tcx>,
+ rvalue: &Rvalue<'tcx>,
+ location: Location,
+ ) {
+ let local = find_local_in_place(place);
+
+ // Find those cases where there is a `Place` consumed by
+ // `rvalue` and we know that all regions in its type will be
+ // incorporated into `place`, the `Place` we are assigning to.
+ match rvalue {
+ // `x = y` is the simplest possible case.
+ Rvalue::Use(op) => self.union_locals_if_needed(local, find_local_in_operand(op)),
+
+ // `X = &'r P` -- the type of `X` will be `&'r T_P`, where
+ // `T_P` is the type of `P`.
+ Rvalue::Ref(_, _, place) => {
+ // Special case: if you have `X = &*Y` (or `X = &**Y`
+ // etc), then the outlives relationships will ensure
+ // that all regions in `Y` are constrained by regions
+ // in `X` -- this is because the lifetimes of the
+ // references we deref through are required to outlive
+ // the borrow lifetime `'r` (which appears in `X`).
+ //
+ // (We don't actually need to check the type of `Y`:
+ // since `ProjectionElem::Deref` represents a built-in
+ // deref and not an overloaded deref, if the thing we
+ // deref through is not a reference, then it must be a
+ // `Box` or `*const`, in which case it contains no
+ // references.)
+ let mut place_ref = place;
+ while let Place::Projection(proj) = place_ref {
+ if let ProjectionElem::Deref = proj.elem {
+ place_ref = &proj.base;
+ } else {
+ break;
+ }
+ }
+
+ self.union_locals_if_needed(local, find_local_in_place(place_ref))
+ }
+
+ Rvalue::Cast(kind, op, _) => match kind {
+ CastKind::Unsize => {
+ // Casting a `&[T; N]` to `&[T]` or `&Foo` to `&Trait` --
+ // in both cases, no regions are "lost".
+ self.union_locals_if_needed(local, find_local_in_operand(op))
+ }
+ _ => (),
+ },
+
+ // Constructing an aggregate like `(x,)` or `Foo { x }`
+ // includes the full type of `x`.
+ Rvalue::Aggregate(_, ops) => {
+ for rvalue in ops.iter().map(find_local_in_operand) {
+ self.union_locals_if_needed(local, rvalue);
+ }
+ }
+
+ // For other things, be conservative and do not union.
+ _ => (),
+ };
+
+ self.super_assign(block, place, rvalue, location);
+ }
+}
use borrow_check::borrow_set::BorrowData;
use borrow_check::nll::region_infer::Cause;
use borrow_check::{Context, MirBorrowckCtxt, WriteKind};
-use rustc::mir::Place;
+use rustc::mir::{Location, Place, TerminatorKind};
use rustc_errors::DiagnosticBuilder;
mod find_use;
);
match find_use::find(mir, regioncx, tcx, region_sub, context.loc) {
- Some(Cause::LiveVar(_local, location)) => {
- err.span_label(
- mir.source_info(location).span,
- "borrow later used here".to_string(),
- );
+ Some(Cause::LiveVar(local, location)) => {
+ let span = mir.source_info(location).span;
+ let spans = self.move_spans(&Place::Local(local), location)
+ .or_else(|| self.borrow_spans(span, location));
+ let message = if self.is_borrow_location_in_loop(context.loc) {
+ if spans.for_closure() {
+ "borrow captured here by closure in later iteration of loop"
+ } else {
+ "borrow used here in later iteration of loop"
+ }
+ } else {
+ if spans.for_closure() {
+ "borrow later captured here by closure"
+ } else {
+ "borrow later used here"
+ }
+ };
+ err.span_label(spans.var_or_use(), message);
}
Some(Cause::DropVar(local, location)) => match &mir.local_decls[local].name {
}
}
}
+
+ /// Check if a borrow location is within a loop.
+ fn is_borrow_location_in_loop(
+ &self,
+ borrow_location: Location,
+ ) -> bool {
+ let mut visited_locations = Vec::new();
+ let mut pending_locations = vec![ borrow_location ];
+ debug!("is_in_loop: borrow_location={:?}", borrow_location);
+
+ while let Some(location) = pending_locations.pop() {
+ debug!("is_in_loop: location={:?} pending_locations={:?} visited_locations={:?}",
+ location, pending_locations, visited_locations);
+ if location == borrow_location && visited_locations.contains(&borrow_location) {
+ // We've managed to return to where we started (and this isn't the start of the
+ // search).
+ debug!("is_in_loop: found!");
+ return true;
+ }
+
+ // Skip locations we've been.
+ if visited_locations.contains(&location) { continue; }
+
+ let block = &self.mir.basic_blocks()[location.block];
+ if location.statement_index == block.statements.len() {
+ // Add start location of the next blocks to pending locations.
+ match block.terminator().kind {
+ TerminatorKind::Goto { target } => {
+ pending_locations.push(target.start_location());
+ },
+ TerminatorKind::SwitchInt { ref targets, .. } => {
+ for target in targets {
+ pending_locations.push(target.start_location());
+ }
+ },
+ TerminatorKind::Drop { target, unwind, .. } |
+ TerminatorKind::DropAndReplace { target, unwind, .. } |
+ TerminatorKind::Assert { target, cleanup: unwind, .. } |
+ TerminatorKind::Yield { resume: target, drop: unwind, .. } |
+ TerminatorKind::FalseUnwind { real_target: target, unwind, .. } => {
+ pending_locations.push(target.start_location());
+ if let Some(unwind) = unwind {
+ pending_locations.push(unwind.start_location());
+ }
+ },
+ TerminatorKind::Call { ref destination, cleanup, .. } => {
+ if let Some((_, destination)) = destination {
+ pending_locations.push(destination.start_location());
+ }
+ if let Some(cleanup) = cleanup {
+ pending_locations.push(cleanup.start_location());
+ }
+ },
+ TerminatorKind::FalseEdges { real_target, ref imaginary_targets, .. } => {
+ pending_locations.push(real_target.start_location());
+ for target in imaginary_targets {
+ pending_locations.push(target.start_location());
+ }
+ },
+ _ => {},
+ }
+ } else {
+ // Add the next statement to pending locations.
+ pending_locations.push(location.successor_within_block());
+ }
+
+ // Keep track of where we have visited.
+ visited_locations.push(location);
+ }
+
+ false
+ }
}
//! liveness code so that it only operates over variables with regions in their
//! types, instead of all variables.
+use borrow_check::nll::escaping_locals::EscapingLocals;
+use rustc::mir::{Local, Mir};
use rustc::ty::TypeFoldable;
use rustc_data_structures::indexed_vec::IndexVec;
-use rustc::mir::{Mir, Local};
use util::liveness::LiveVariableMap;
use rustc_data_structures::indexed_vec::Idx;
crate struct NllLivenessMap {
/// For each local variable, contains either None (if the type has no regions)
/// or Some(i) with a suitable index.
- pub from_local: IndexVec<Local, Option<LocalWithRegion>>,
- /// For each LocalWithRegion, maps back to the original Local index.
- pub to_local: IndexVec<LocalWithRegion, Local>,
+ from_local: IndexVec<Local, Option<LocalWithRegion>>,
+ /// For each LocalWithRegion, maps back to the original Local index.
+ to_local: IndexVec<LocalWithRegion, Local>,
}
impl LiveVariableMap for NllLivenessMap {
-
fn from_local(&self, local: Local) -> Option<Self::LiveVar> {
self.from_local[local]
}
impl NllLivenessMap {
/// Iterates over the variables in Mir and assigns each Local whose type contains
/// regions a LocalWithRegion index. Returns a map for converting back and forth.
- pub fn compute(mir: &Mir) -> Self {
+ crate fn compute(mir: &Mir<'tcx>) -> Self {
+ let mut escaping_locals = EscapingLocals::compute(mir);
+
let mut to_local = IndexVec::default();
- let from_local: IndexVec<Local,Option<_>> = mir
+ let mut escapes_into_return = 0;
+ let mut no_regions = 0;
+ let from_local: IndexVec<Local, Option<_>> = mir
.local_decls
.iter_enumerated()
.map(|(local, local_decl)| {
- if local_decl.ty.has_free_regions() {
- Some(to_local.push(local))
+ if escaping_locals.escapes_into_return(local) {
+ // If the local escapes into the return value,
+ // then the return value will force all of the
+ // regions in its type to outlive free regions
+ // (e.g., `'static`) and hence liveness is not
+ // needed. This is particularly important for big
+ // statics.
+ escapes_into_return += 1;
+ None
+ } else if local_decl.ty.has_free_regions() {
+ let l = to_local.push(local);
+ debug!("liveness_map: {:?} = {:?}", local, l);
+ Some(l)
+ } else {
+ no_regions += 1;
+ None
}
- else {
- None
- }
}).collect();
- Self { from_local, to_local }
+ debug!("liveness_map: {} variables need liveness", to_local.len());
+ debug!("liveness_map: {} escapes into return", escapes_into_return);
+ debug!("liveness_map: {} no regions", no_regions);
+
+ Self {
+ from_local,
+ to_local,
+ }
}
}
use util as mir_util;
use util::pretty::{self, ALIGN};
+mod constraints;
mod constraint_generation;
+mod escaping_locals;
pub mod explain_borrow;
mod facts;
mod invalidation;
mod universal_regions;
crate mod liveness_map;
-mod constraints;
-
use self::facts::AllFacts;
use self::region_infer::RegionInferenceContext;
use self::universal_regions::UniversalRegions;
location_table,
borrow_set,
&liveness,
+ &liveness_map,
&mut all_facts,
flow_inits,
move_data,
dump_mir_results(
infcx,
&liveness,
+ &liveness_map,
MirSource::item(def_id),
&mir,
®ioncx,
fn dump_mir_results<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
liveness: &LivenessResults<LocalWithRegion>,
+ liveness_map: &NllLivenessMap,
source: MirSource,
mir: &Mir<'tcx>,
regioncx: &RegionInferenceContext,
return;
}
- let map = &NllLivenessMap::compute(mir);
-
let regular_liveness_per_location: FxHashMap<_, _> = mir
.basic_blocks()
.indices()
let mut results = vec![];
liveness
.regular
- .simulate_block(&mir, bb, map, |location, local_set| {
+ .simulate_block(&mir, bb, liveness_map, |location, local_set| {
results.push((location, local_set.clone()));
});
results
let mut results = vec![];
liveness
.drop
- .simulate_block(&mir, bb, map, |location, local_set| {
+ .simulate_block(&mir, bb, liveness_map, |location, local_set| {
results.push((location, local_set.clone()));
});
results
use rustc::infer::InferCtxt;
use rustc::mir::Mir;
use rustc::ty::subst::{Substs, UnpackedKind};
-use rustc::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt};
use rustc::util::ppaux::with_highlight_region;
use rustc_errors::DiagnosticBuilder;
-use syntax::ast::Name;
+use syntax::ast::{Name, DUMMY_NODE_ID};
use syntax::symbol::keywords;
use syntax_pos::symbol::InternedString;
diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> {
let error_region = self.to_error_region(fr)?;
+
debug!("give_region_a_name: error_region = {:?}", error_region);
match error_region {
- ty::ReEarlyBound(ebr) => Some(ebr.name),
+ ty::ReEarlyBound(ebr) => {
+ self.highlight_named_span(tcx, error_region, &ebr.name, diag);
+ Some(ebr.name)
+ },
ty::ReStatic => Some(keywords::StaticLifetime.name().as_interned_str()),
ty::ReFree(free_region) => match free_region.bound_region {
- ty::BoundRegion::BrNamed(_, name) => Some(name),
+ ty::BoundRegion::BrNamed(_, name) => {
+ self.highlight_named_span(tcx, error_region, &name, diag);
+ Some(name)
+ },
ty::BoundRegion::BrEnv => {
let closure_span = tcx.hir.span_if_local(mir_def_id).unwrap();
}
}
+ /// Highlight a named span to provide context for error messages that
+ /// mention that span, for example:
+ ///
+ /// ```
+ /// |
+ /// | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ /// | -- -- lifetime `'b` defined here
+ /// | |
+ /// | lifetime `'a` defined here
+ /// |
+ /// | with_signature(cell, t, |cell, t| require(cell, t));
+ /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must
+ /// | outlive `'a`
+ /// ```
+ fn highlight_named_span(
+ &self,
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ error_region: &RegionKind,
+ name: &InternedString,
+ diag: &mut DiagnosticBuilder<'_>,
+ ) {
+ let cm = tcx.sess.codemap();
+
+ let scope = error_region.free_region_binding_scope(tcx);
+ let node = tcx.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
+
+ let mut sp = cm.def_span(tcx.hir.span(node));
+ if let Some(param) = tcx.hir.get_generics(scope).and_then(|generics| {
+ generics.get_named(name)
+ }) {
+ sp = param.span;
+ }
+
+ diag.span_label(
+ sp,
+ format!("lifetime `{}` defined here", name),
+ );
+ }
+
/// Find an argument that contains `fr` and label it with a fully
/// elaborated type, returning something like `'1`. Result looks
/// like:
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
liveness: &LivenessResults<LocalWithRegion>,
+ liveness_map: &NllLivenessMap,
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
) {
cx,
mir,
liveness,
+ liveness_map,
flow_inits,
move_data,
drop_data: FxHashMap(),
- map: &NllLivenessMap::compute(mir),
};
for bb in mir.basic_blocks().indices() {
cx: &'gen mut TypeChecker<'typeck, 'gcx, 'tcx>,
mir: &'gen Mir<'tcx>,
liveness: &'gen LivenessResults<LocalWithRegion>,
+ liveness_map: &'gen NllLivenessMap,
flow_inits: &'gen mut FlowAtLocation<MaybeInitializedPlaces<'flow, 'gcx, 'tcx>>,
move_data: &'gen MoveData<'tcx>,
drop_data: FxHashMap<Ty<'tcx>, DropData<'tcx>>,
- map: &'gen NllLivenessMap,
}
struct DropData<'tcx> {
self.liveness
.regular
- .simulate_block(self.mir, bb, self.map, |location, live_locals| {
+ .simulate_block(self.mir, bb, self.liveness_map, |location, live_locals| {
for live_local in live_locals.iter() {
- let local = self.map.from_live_var(live_local);
+ let local = self.liveness_map.from_live_var(live_local);
let live_local_ty = self.mir.local_decls[local].ty;
Self::push_type_live_constraint(&mut self.cx, live_local_ty, location);
}
let mut all_live_locals: Vec<(Location, Vec<LocalWithRegion>)> = vec![];
self.liveness
.drop
- .simulate_block(self.mir, bb, self.map, |location, live_locals| {
+ .simulate_block(self.mir, bb, self.liveness_map, |location, live_locals| {
all_live_locals.push((location, live_locals.iter().collect()));
});
debug!(
});
}
- let local = self.map.from_live_var(live_local);
+ let local = self.liveness_map.from_live_var(live_local);
let mpi = self.move_data.rev_lookup.find_local(local);
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
debug!(
self.move_data.move_paths[initialized_child]
);
- let local = self.map.from_live_var(live_local);
+ let local = self.liveness_map.from_live_var(live_local);
let live_local_ty = self.mir.local_decls[local].ty;
self.add_drop_live_constraint(live_local, live_local_ty, location);
}
use borrow_check::location::LocationTable;
use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
use borrow_check::nll::facts::AllFacts;
-use borrow_check::nll::region_infer::values::{RegionValueElements, LivenessValues};
+use borrow_check::nll::liveness_map::NllLivenessMap;
+use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
-use borrow_check::nll::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
+use borrow_check::nll::type_check::free_region_relations::{
+ CreateResult, UniversalRegionRelations,
+};
use borrow_check::nll::universal_regions::UniversalRegions;
use borrow_check::nll::LocalWithRegion;
use borrow_check::nll::ToRegionVid;
location_table: &LocationTable,
borrow_set: &BorrowSet<'tcx>,
liveness: &LivenessResults<LocalWithRegion>,
+ liveness_map: &NllLivenessMap,
all_facts: &mut Option<AllFacts>,
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
Some(&mut borrowck_context),
Some(errors_buffer),
|cx| {
- liveness::generate(cx, mir, liveness, flow_inits, move_data);
+ liveness::generate(cx, mir, liveness, liveness_map, flow_inits, move_data);
cx.equate_inputs_and_outputs(
mir,
mir_def_id,
}
(Place::Promoted(p1), Place::Promoted(p2)) => {
if p1.0 == p2.0 {
+ if let ty::TyArray(_, size) = p1.1.sty {
+ if size.unwrap_usize(tcx) == 0 {
+ // Ignore conflicts with promoted [T; 0].
+ debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
+ return Overlap::Disjoint;
+ }
+ }
// the same promoted - base case, equal
debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED");
Overlap::EqualOrDisjoint
use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard};
use build::scope::{CachedBlock, DropKind};
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc::ty::{self, Ty};
use rustc::mir::*;
use rustc::hir;
// test the branches of enum
Switch {
adt_def: &'tcx ty::AdtDef,
- variants: BitVector<usize>,
+ variants: BitArray<usize>,
},
// test the branches of enum
let locals = if has_guard.0 && tcx.all_pat_vars_are_implicit_refs_within_guards() {
let mut vals_for_guard = Vec::with_capacity(num_patterns);
for _ in 0..num_patterns {
- let val_for_guard_idx = self.local_decls.push(local.clone());
+ let val_for_guard_idx = self.local_decls.push(LocalDecl {
+ // This variable isn't mutated but has a name, so has to be
+ // immutable to avoid the unused mut lint.
+ mutability: Mutability::Not,
+ ..local.clone()
+ });
vals_for_guard.push(val_for_guard_idx);
}
let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> {
- mutability,
+ // See previous comment.
+ mutability: Mutability::Not,
ty: tcx.mk_imm_ref(tcx.types.re_empty, var_ty),
name: Some(name),
source_info,
use build::matches::{Candidate, MatchPair, Test, TestKind};
use hair::*;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc::ty::{self, Ty};
use rustc::ty::util::IntTypeExt;
use rustc::mir::*;
span: match_pair.pattern.span,
kind: TestKind::Switch {
adt_def: adt_def.clone(),
- variants: BitVector::new(adt_def.variants.len()),
+ variants: BitArray::new(adt_def.variants.len()),
},
}
}
pub fn add_variants_to_switch<'pat>(&mut self,
test_place: &Place<'tcx>,
candidate: &Candidate<'pat, 'tcx>,
- variants: &mut BitVector<usize>)
+ variants: &mut BitArray<usize>)
-> bool
{
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
use dataflow::BitDenotation;
/// This calculates if any part of a MIR local could have previously been borrowed.
-/// This means that once a local has been borrowed, its bit will always be set
-/// from that point and onwards, even if the borrow ends. You could also think of this
-/// as computing the lifetimes of infinite borrows.
+/// This means that once a local has been borrowed, its bit will be set
+/// from that point and onwards, until we see a StorageDead statement for the local,
+/// at which points there is no memory associated with the local, so it cannot be borrowed.
/// This is used to compute which locals are live during a yield expression for
/// immovable generators.
#[derive(Copy, Clone)]
fn statement_effect(&self,
sets: &mut BlockSets<Local>,
loc: Location) {
+ let stmt = &self.mir[loc.block].statements[loc.statement_index];
+
BorrowedLocalsVisitor {
sets,
- }.visit_statement(loc.block, &self.mir[loc.block].statements[loc.statement_index], loc);
+ }.visit_statement(loc.block, stmt, loc);
+
+ // StorageDead invalidates all borrows and raw pointers to a local
+ match stmt.kind {
+ StatementKind::StorageDead(l) => sets.kill(&l),
+ _ => (),
+ }
}
fn terminator_effect(&self,
let trunc = |n| {
let param_ty = self.param_env.and(self.tcx.lift_to_global(&ty).unwrap());
- let bit_width = self.tcx.layout_of(param_ty).unwrap().size.bits();
- trace!("trunc {} with size {} and shift {}", n, bit_width, 128 - bit_width);
- let shift = 128 - bit_width;
+ let width = self.tcx.layout_of(param_ty).unwrap().size;
+ trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
+ let shift = 128 - width.bits();
let result = (n << shift) >> shift;
trace!("trunc result: {}", result);
ConstValue::Scalar(Scalar::Bits {
bits: result,
- defined: bit_width as u8,
+ size: width.bytes() as u8,
})
};
let s = s.as_str();
let id = self.tcx.allocate_bytes(s.as_bytes());
let value = Scalar::Ptr(id.into()).to_value_with_len(s.len() as u64, self.tcx);
- ConstValue::from_byval_value(value)
+ ConstValue::from_byval_value(value).unwrap()
},
LitKind::ByteStr(ref data) => {
let id = self.tcx.allocate_bytes(data);
},
LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits {
bits: n as u128,
- defined: 8,
+ size: 1,
}),
LitKind::Int(n, _) if neg => {
let n = n as i128;
};
parse_float(n, fty)
}
- LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits {
- bits: b as u128,
- defined: 8,
- }),
- LitKind::Char(c) => ConstValue::Scalar(Scalar::Bits {
- bits: c as u128,
- defined: 32,
- }),
+ LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)),
+ LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)),
};
ty::Const::from_const_value(self.tcx, lit, ty)
}
use interpret::{const_val_field, const_variant_index, self};
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
-use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, Value};
+use rustc::mir::interpret::{Scalar, GlobalId, ConstValue};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::subst::{Substs, Kind};
use rustc::hir::{self, PatKind, RangeEnd};
l.partial_cmp(&r)
},
ty::TyInt(_) => {
- let a = interpret::sign_extend(tcx, a, ty.value).expect("layout error for TyInt");
- let b = interpret::sign_extend(tcx, b, ty.value).expect("layout error for TyInt");
+ let layout = tcx.layout_of(ty).ok()?;
+ let a = interpret::sign_extend(a, layout);
+ let b = interpret::sign_extend(b, layout);
Some((a as i128).cmp(&(b as i128)))
},
_ => Some(a.cmp(&b)),
if let ty::TyRef(_, rty, _) = ty.value.sty {
if let ty::TyStr = rty.sty {
- match (a.to_byval_value(), b.to_byval_value()) {
+ match (a.val, b.val) {
(
- Some(Value::ScalarPair(
+ ConstValue::ScalarPair(
Scalar::Ptr(ptr_a),
len_a,
- )),
- Some(Value::ScalarPair(
+ ),
+ ConstValue::ScalarPair(
Scalar::Ptr(ptr_b),
len_b,
- ))
+ ),
) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
+ let len_a = len_a.unwrap_or_err().ok();
+ let len_b = len_b.unwrap_or_err().ok();
+ if len_a.is_none() || len_b.is_none() {
+ tcx.sess.struct_err("str slice len is undef").delay_as_bug();
+ }
+ let len_a = len_a?;
+ let len_b = len_b?;
if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) {
if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) {
if len_a == len_b {
let s = s.as_str();
let id = tcx.allocate_bytes(s.as_bytes());
let value = Scalar::Ptr(id.into()).to_value_with_len(s.len() as u64, tcx);
- ConstValue::from_byval_value(value)
+ ConstValue::from_byval_value(value).unwrap()
},
LitKind::ByteStr(ref data) => {
let id = tcx.allocate_bytes(data);
},
LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits {
bits: n as u128,
- defined: 8,
+ size: 1,
}),
LitKind::Int(n, _) => {
enum Int {
Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n,
_ => bug!(),
};
- let defined = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size.bits() as u8;
+ let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size.bytes() as u8;
ConstValue::Scalar(Scalar::Bits {
bits: n,
- defined,
+ size,
})
},
LitKind::Float(n, fty) => {
};
parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
}
- LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits {
- bits: b as u128,
- defined: 8,
- }),
- LitKind::Char(c) => ConstValue::Scalar(Scalar::Bits {
- bits: c as u128,
- defined: 32,
- }),
+ LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)),
+ LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)),
};
Ok(ty::Const::from_const_value(tcx, lit, ty))
}
let num = num.as_str();
use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::Float;
- let (bits, defined) = match fty {
+ let (bits, size) = match fty {
ast::FloatTy::F32 => {
num.parse::<f32>().map_err(|_| ())?;
let mut f = num.parse::<Single>().unwrap_or_else(|e| {
if neg {
f = -f;
}
- (f.to_bits(), 32)
+ (f.to_bits(), 4)
}
ast::FloatTy::F64 => {
num.parse::<f64>().map_err(|_| ())?;
if neg {
f = -f;
}
- (f.to_bits(), 64)
+ (f.to_bits(), 8)
}
};
- Ok(ConstValue::Scalar(Scalar::Bits { bits, defined }))
+ Ok(ConstValue::Scalar(Scalar::Bits { bits, size }))
}
use rustc::ty::{self, Ty};
-use rustc::ty::layout::{self, LayoutOf};
+use rustc::ty::layout::{self, LayoutOf, TyLayout};
use syntax::ast::{FloatTy, IntTy, UintTy};
use rustc_apfloat::ieee::{Single, Double};
dest_ty: Ty<'tcx>,
dest: Place,
) -> EvalResult<'tcx> {
+ let src_layout = self.layout_of(src.ty)?;
+ let dst_layout = self.layout_of(dest_ty)?;
use rustc::mir::CastKind::*;
match kind {
Unsize => {
- let src_layout = self.layout_of(src.ty)?;
- let dst_layout = self.layout_of(dest_ty)?;
self.unsize_into(src.value, src_layout, dest, dst_layout)?;
}
let discr_val = def
.discriminant_for_variant(*self.tcx, index)
.val;
- let defined = self
- .layout_of(dest_ty)
- .unwrap()
- .size
- .bits() as u8;
return self.write_scalar(
dest,
Scalar::Bits {
bits: discr_val,
- defined,
+ size: dst_layout.size.bytes() as u8,
},
dest_ty);
}
}
let src_val = self.value_to_scalar(src)?;
- let dest_val = self.cast_scalar(src_val, src.ty, dest_ty)?;
+ let dest_val = self.cast_scalar(src_val, src_layout, dst_layout)?;
let valty = ValTy {
- value: Value::Scalar(dest_val),
+ value: Value::Scalar(dest_val.into()),
ty: dest_ty,
};
self.write_value(valty, dest)?;
).ok_or_else(|| EvalErrorKind::TooGeneric.into());
let fn_ptr = self.memory.create_fn_alloc(instance?);
let valty = ValTy {
- value: Value::Scalar(fn_ptr.into()),
+ value: Value::Scalar(Scalar::Ptr(fn_ptr.into()).into()),
ty: dest_ty,
};
self.write_value(valty, dest)?;
);
let fn_ptr = self.memory.create_fn_alloc(instance);
let valty = ValTy {
- value: Value::Scalar(fn_ptr.into()),
+ value: Value::Scalar(Scalar::Ptr(fn_ptr.into()).into()),
ty: dest_ty,
};
self.write_value(valty, dest)?;
pub(super) fn cast_scalar(
&self,
val: Scalar,
- src_ty: Ty<'tcx>,
- dest_ty: Ty<'tcx>,
+ src_layout: TyLayout<'tcx>,
+ dest_layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, Scalar> {
use rustc::ty::TypeVariants::*;
- trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
+ trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
match val {
- Scalar::Bits { defined: 0, .. } => Ok(val),
- Scalar::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
- Scalar::Bits { bits, .. } => {
- // TODO(oli-obk): check defined bits here
- match src_ty.sty {
- TyFloat(fty) => self.cast_from_float(bits, fty, dest_ty),
- _ => self.cast_from_int(bits, src_ty, dest_ty),
+ Scalar::Ptr(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
+ Scalar::Bits { bits, size } => {
+ assert_eq!(size as u64, src_layout.size.bytes());
+ match src_layout.ty.sty {
+ TyFloat(fty) => self.cast_from_float(bits, fty, dest_layout.ty),
+ _ => self.cast_from_int(bits, src_layout, dest_layout),
}
}
}
fn cast_from_int(
&self,
v: u128,
- src_ty: Ty<'tcx>,
- dest_ty: Ty<'tcx>,
+ src_layout: TyLayout<'tcx>,
+ dest_layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, Scalar> {
- let signed = self.layout_of(src_ty)?.abi.is_signed();
+ let signed = src_layout.abi.is_signed();
let v = if signed {
- self.sign_extend(v, src_ty)?
+ self.sign_extend(v, src_layout)
} else {
v
};
- trace!("cast_from_int: {}, {}, {}", v, src_ty, dest_ty);
+ trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
use rustc::ty::TypeVariants::*;
- match dest_ty.sty {
+ match dest_layout.ty.sty {
TyInt(_) | TyUint(_) => {
- let v = self.truncate(v, dest_ty)?;
+ let v = self.truncate(v, dest_layout);
Ok(Scalar::Bits {
bits: v,
- defined: self.layout_of(dest_ty).unwrap().size.bits() as u8,
+ size: dest_layout.size.bytes() as u8,
})
}
TyFloat(FloatTy::F32) if signed => Ok(Scalar::Bits {
bits: Single::from_i128(v as i128).value.to_bits(),
- defined: 32,
+ size: 4,
}),
TyFloat(FloatTy::F64) if signed => Ok(Scalar::Bits {
bits: Double::from_i128(v as i128).value.to_bits(),
- defined: 64,
+ size: 8,
}),
TyFloat(FloatTy::F32) => Ok(Scalar::Bits {
bits: Single::from_u128(v).value.to_bits(),
- defined: 32,
+ size: 4,
}),
TyFloat(FloatTy::F64) => Ok(Scalar::Bits {
bits: Double::from_u128(v).value.to_bits(),
- defined: 64,
+ size: 8,
}),
- TyChar if v as u8 as u128 == v => Ok(Scalar::Bits { bits: v, defined: 32 }),
- TyChar => err!(InvalidChar(v)),
+ TyChar => {
+ assert_eq!(v as u8 as u128, v);
+ Ok(Scalar::Bits { bits: v, size: 4 })
+ },
// No alignment check needed for raw pointers. But we have to truncate to target ptr size.
TyRawPtr(_) => {
Ok(Scalar::Bits {
bits: self.memory.truncate_to_ptr(v).0 as u128,
- defined: self.memory.pointer_size().bits() as u8,
+ size: self.memory.pointer_size().bytes() as u8,
})
},
// Casts to bool are not permitted by rustc, no need to handle them here.
- _ => err!(Unimplemented(format!("int to {:?} cast", dest_ty))),
+ _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
}
}
match fty {
FloatTy::F32 => Ok(Scalar::Bits {
bits: Single::from_bits(bits).to_u128(width).value,
- defined: width as u8,
+ size: (width / 8) as u8,
}),
FloatTy::F64 => Ok(Scalar::Bits {
bits: Double::from_bits(bits).to_u128(width).value,
- defined: width as u8,
+ size: (width / 8) as u8,
}),
}
},
match fty {
FloatTy::F32 => Ok(Scalar::Bits {
bits: Single::from_bits(bits).to_i128(width).value as u128,
- defined: width as u8,
+ size: (width / 8) as u8,
}),
FloatTy::F64 => Ok(Scalar::Bits {
bits: Double::from_bits(bits).to_i128(width).value as u128,
- defined: width as u8,
+ size: (width / 8) as u8,
}),
}
},
TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
Ok(Scalar::Bits {
bits: Single::to_bits(Double::from_bits(bits).convert(&mut false).value),
- defined: 32,
+ size: 4,
})
},
// f32 -> f64
TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
Ok(Scalar::Bits {
bits: Double::to_bits(Single::from_bits(bits).convert(&mut false).value),
- defined: 64,
+ size: 8,
})
},
// identity cast
TyFloat(FloatTy:: F64) => Ok(Scalar::Bits {
bits,
- defined: 64,
+ size: 8,
}),
TyFloat(FloatTy:: F32) => Ok(Scalar::Bits {
bits,
- defined: 32,
+ size: 4,
}),
_ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
}
use std::error::Error;
use rustc::hir;
-use rustc::mir::interpret::{ConstEvalErr};
+use rustc::mir::interpret::{ConstEvalErr, ScalarMaybeUndef};
use rustc::mir;
use rustc::ty::{self, TyCtxt, Ty, Instance};
use rustc::ty::layout::{self, LayoutOf, Primitive, TyLayout};
use rustc::ty::subst::Subst;
+use rustc_data_structures::indexed_vec::IndexVec;
use syntax::ast::Mutability;
use syntax::codemap::Span;
let param_env = tcx.param_env(instance.def_id());
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
// insert a stack frame so any queries have the correct substs
- ecx.push_stack_frame(
+ ecx.stack.push(super::eval_context::Frame {
+ block: mir::START_BLOCK,
+ locals: IndexVec::new(),
instance,
span,
mir,
- Place::undef(),
- StackPopCleanup::None,
- )?;
+ return_place: Place::undef(),
+ return_to_block: StackPopCleanup::None,
+ stmt: 0,
+ });
Ok(ecx)
}
pub fn value_to_const_value<'tcx>(
ecx: &EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>,
val: Value,
- ty: Ty<'tcx>,
-) -> &'tcx ty::Const<'tcx> {
- let layout = ecx.layout_of(ty).unwrap();
+ layout: TyLayout<'tcx>,
+) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
match (val, &layout.abi) {
- (Value::Scalar(Scalar::Bits { defined: 0, ..}), _) if layout.is_zst() => {},
+ (Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { size: 0, ..})), _) if layout.is_zst() => {},
(Value::ByRef(..), _) |
(Value::Scalar(_), &layout::Abi::Scalar(_)) |
(Value::ScalarPair(..), &layout::Abi::ScalarPair(..)) => {},
_ => bug!("bad value/layout combo: {:#?}, {:#?}", val, layout),
}
- let val = (|| {
- match val {
- Value::Scalar(val) => Ok(ConstValue::Scalar(val)),
- Value::ScalarPair(a, b) => Ok(ConstValue::ScalarPair(a, b)),
- Value::ByRef(ptr, align) => {
- let ptr = ptr.to_ptr().unwrap();
- let alloc = ecx.memory.get(ptr.alloc_id)?;
- assert!(alloc.align.abi() >= align.abi());
- assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= layout.size.bytes());
- let mut alloc = alloc.clone();
- alloc.align = align;
- let alloc = ecx.tcx.intern_const_alloc(alloc);
- Ok(ConstValue::ByRef(alloc, ptr.offset))
- }
- }
- })();
- match val {
- Ok(val) => ty::Const::from_const_value(ecx.tcx.tcx, val, ty),
- Err(err) => {
- let (frames, span) = ecx.generate_stacktrace(None);
- let err = ConstEvalErr {
- span,
- error: err,
- stacktrace: frames,
- };
- err.report_as_error(
- ecx.tcx,
- "failed to convert Value to ConstValue, this is a bug",
- );
- span_bug!(span, "miri error occured when converting Value to ConstValue")
+ let val = match val {
+ Value::Scalar(val) => ConstValue::Scalar(val.unwrap_or_err()?),
+ Value::ScalarPair(a, b) => ConstValue::ScalarPair(a.unwrap_or_err()?, b),
+ Value::ByRef(ptr, align) => {
+ let ptr = ptr.to_ptr().unwrap();
+ let alloc = ecx.memory.get(ptr.alloc_id)?;
+ assert!(alloc.align.abi() >= align.abi());
+ assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= layout.size.bytes());
+ let mut alloc = alloc.clone();
+ alloc.align = align;
+ let alloc = ecx.tcx.intern_const_alloc(alloc);
+ ConstValue::ByRef(alloc, ptr.offset)
}
- }
+ };
+ Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, layout.ty))
}
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
let elem_align = ecx.layout_of(elem_ty)?.align.abi();
let align_val = Scalar::Bits {
bits: elem_align as u128,
- defined: dest_layout.size.bits() as u8,
+ size: dest_layout.size.bytes() as u8,
};
ecx.write_scalar(dest, align_val, dest_layout.ty)?;
}
let size = ecx.layout_of(ty)?.size.bytes() as u128;
let size_val = Scalar::Bits {
bits: size,
- defined: dest_layout.size.bits() as u8,
+ size: dest_layout.size.bytes() as u8,
};
ecx.write_scalar(dest, size_val, dest_layout.ty)?;
}
let type_id = ecx.tcx.type_id_hash(ty) as u128;
let id_val = Scalar::Bits {
bits: type_id,
- defined: dest_layout.size.bits() as u8,
+ size: dest_layout.size.bytes() as u8,
};
ecx.write_scalar(dest, id_val, dest_layout.ty)?;
}
let place = ecx.allocate_place_for_value(value, layout, variant)?;
let (place, layout) = ecx.place_field(place, field, layout)?;
let (ptr, align) = place.to_ptr_align();
- let mut new_value = Value::ByRef(ptr, align);
+ let mut new_value = Value::ByRef(ptr.unwrap_or_err()?, align);
new_value = ecx.try_read_by_ref(new_value, layout.ty)?;
use rustc_data_structures::indexed_vec::Idx;
match (value, new_value) {
),
_ => {},
}
- Ok(value_to_const_value(&ecx, new_value, layout.ty))
+ value_to_const_value(&ecx, new_value, layout)
})();
result.map_err(|err| {
let (trace, span) = ecx.generate_stacktrace(None);
},
Value::ByRef(ptr, align) => (ptr, align),
};
- let place = Place::from_scalar_ptr(ptr, align);
+ let place = Place::from_scalar_ptr(ptr.into(), align);
ecx.read_discriminant_as_variant_index(place, layout)
}
if tcx.is_static(def_id).is_none() && cid.promoted.is_none() {
val = ecx.try_read_by_ref(val, layout.ty)?;
}
- Ok(value_to_const_value(&ecx, val, layout.ty))
+ value_to_const_value(&ecx, val, layout)
}).map_err(|err| {
let (trace, span) = ecx.generate_stacktrace(None);
let err = ConstEvalErr {
};
if tcx.is_static(def_id).is_some() {
err.report_as_error(ecx.tcx, "could not evaluate static initializer");
+ if tcx.sess.err_count() == 0 {
+ span_bug!(span, "static eval failure didn't emit an error: {:#?}", err);
+ }
}
err.into()
})
bits: u128,
kind: Primitive,
) -> EvalResult<'tcx, Scalar> {
- let defined = match kind {
- Primitive::Int(integer, _) => integer.size().bits() as u8,
+ let size = match kind {
+ Primitive::Int(integer, _) => integer.size(),
_ => bug!("invalid `{}` argument: {:?}", name, bits),
};
- let extra = 128 - defined as u128;
+ let extra = 128 - size.bits() as u128;
let bits_out = match name {
"ctpop" => bits.count_ones() as u128,
"ctlz" => bits.leading_zeros() as u128 - extra,
"bswap" => (bits << extra).swap_bytes(),
_ => bug!("not a numeric intrinsic: {}", name),
};
- Ok(Scalar::Bits { bits: bits_out, defined })
+ Ok(Scalar::Bits { bits: bits_out, size: size.bytes() as u8 })
}
use rustc::mir::interpret::{
GlobalId, Value, Scalar, FrameInfo, AllocType,
EvalResult, EvalErrorKind, Pointer, ConstValue,
+ ScalarMaybeUndef,
};
use syntax::codemap::{self, Span};
/// `[return_ptr, arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
/// `None` represents a local that is currently dead, while a live local
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
- ///
- /// Before being initialized, arguments are `Value::Scalar(Scalar::undef())` and other locals are `None`.
- pub locals: IndexVec<mir::Local, Option<Value>>,
+ pub locals: IndexVec<mir::Local, LocalValue>,
////////////////////////////////////////////////////////////////////////////////
// Current position within the function
pub stmt: usize,
}
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub enum LocalValue {
+ Dead,
+ Live(Value),
+}
+
+impl LocalValue {
+ pub fn access(self) -> EvalResult<'static, Value> {
+ match self {
+ LocalValue::Dead => err!(DeadLocal),
+ LocalValue::Live(val) => Ok(val),
+ }
+ }
+}
+
impl<'mir, 'tcx: 'mir> Eq for Frame<'mir, 'tcx> {}
impl<'mir, 'tcx: 'mir> PartialEq for Frame<'mir, 'tcx> {
let id = self.memory.allocate_value(alloc.clone(), MemoryKind::Stack)?;
Ok(Value::ByRef(Pointer::new(id, offset).into(), alloc.align))
},
- ConstValue::ScalarPair(a, b) => Ok(Value::ScalarPair(a, b)),
- ConstValue::Scalar(val) => Ok(Value::Scalar(val)),
+ ConstValue::ScalarPair(a, b) => Ok(Value::ScalarPair(a.into(), b.into())),
+ ConstValue::Scalar(val) => Ok(Value::Scalar(val.into())),
}
}
/// Note that the value does not matter if the type is sized. For unsized types,
/// the value has to be a fat pointer, and we only care about the "extra" data in it.
pub fn size_and_align_of_dst(
- &mut self,
+ &self,
ty: Ty<'tcx>,
value: Value,
) -> EvalResult<'tcx, (Size, Align)> {
// Recurse to get the size of the dynamically sized field (must be
// the last field).
- let field_ty = layout.field(&self, layout.fields.count() - 1)?.ty;
+ let field_ty = layout.field(self, layout.fields.count() - 1)?.ty;
let (unsized_size, unsized_align) =
self.size_and_align_of_dst(field_ty, value)?;
}
ty::TySlice(_) | ty::TyStr => {
- let (elem_size, align) = layout.field(&self, 0)?.size_and_align();
+ let (elem_size, align) = layout.field(self, 0)?.size_and_align();
let (_, len) = self.into_slice(value)?;
Ok((elem_size * len, align))
}
) -> EvalResult<'tcx> {
::log_settings::settings().indentation += 1;
- let locals = if mir.local_decls.len() > 1 {
- let mut locals = IndexVec::from_elem(Some(Value::Scalar(Scalar::undef())), &mir.local_decls);
+ // first push a stack frame so we have access to the local substs
+ self.stack.push(Frame {
+ mir,
+ block: mir::START_BLOCK,
+ return_to_block,
+ return_place,
+ // empty local array, we fill it in below, after we are inside the stack frame and
+ // all methods actually know about the frame
+ locals: IndexVec::new(),
+ span,
+ instance,
+ stmt: 0,
+ });
+
+ // don't allocate at all for trivial constants
+ if mir.local_decls.len() > 1 {
+ let mut locals = IndexVec::from_elem(LocalValue::Dead, &mir.local_decls);
+ for (local, decl) in locals.iter_mut().zip(mir.local_decls.iter()) {
+ *local = LocalValue::Live(self.init_value(decl.ty)?);
+ }
match self.tcx.describe_def(instance.def_id()) {
// statics and constants don't have `Storage*` statements, no need to look for them
Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {},
use rustc::mir::StatementKind::{StorageDead, StorageLive};
match stmt.kind {
StorageLive(local) |
- StorageDead(local) => locals[local] = None,
+ StorageDead(local) => locals[local] = LocalValue::Dead,
_ => {}
}
}
}
},
}
- locals
- } else {
- // don't allocate at all for trivial constants
- IndexVec::new()
- };
-
- self.stack.push(Frame {
- mir,
- block: mir::START_BLOCK,
- return_to_block,
- return_place,
- locals,
- span,
- instance,
- stmt: 0,
- });
+ self.frame_mut().locals = locals;
+ }
self.memory.cur_frame = self.cur_frame();
if let Place::Ptr { ptr, .. } = frame.return_place {
// FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
self.memory.mark_static_initialized(
- ptr.to_ptr()?.alloc_id,
+ ptr.unwrap_or_err()?.to_ptr()?.alloc_id,
mutable,
)?
} else {
Ok(())
}
- pub fn deallocate_local(&mut self, local: Option<Value>) -> EvalResult<'tcx> {
- if let Some(Value::ByRef(ptr, _align)) = local {
+ pub fn deallocate_local(&mut self, local: LocalValue) -> EvalResult<'tcx> {
+ // FIXME: should we tell the user that there was a local which was never written to?
+ if let LocalValue::Live(Value::ByRef(ptr, _align)) = local {
trace!("deallocating local");
let ptr = ptr.to_ptr()?;
self.memory.dump_alloc(ptr.alloc_id);
) -> EvalResult<'tcx> {
let dest = self.eval_place(place)?;
let dest_ty = self.place_ty(place);
+ let dest_layout = self.layout_of(dest_ty)?;
use rustc::mir::Rvalue::*;
match *rvalue {
UnaryOp(un_op, ref operand) => {
let val = self.eval_operand_to_scalar(operand)?;
- let val = self.unary_op(un_op, val, dest_ty)?;
+ let val = self.unary_op(un_op, val, dest_layout)?;
self.write_scalar(
dest,
val,
let (dest, dest_align) = self.force_allocation(dest)?.to_ptr_align();
if length > 0 {
+ let dest = dest.unwrap_or_err()?;
//write the first value
self.write_value_to_ptr(value, dest, dest_align, elem_ty)?;
let src = self.eval_place(place)?;
let ty = self.place_ty(place);
let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx);
- let defined = self.memory.pointer_size().bits() as u8;
+ let size = self.memory.pointer_size().bytes() as u8;
self.write_scalar(
dest,
Scalar::Bits {
bits: len as u128,
- defined,
+ size,
},
dest_ty,
)?;
let (ptr, _align, extra) = self.force_allocation(src)?.to_ptr_align_extra();
let val = match extra {
- PlaceExtra::None => ptr.to_value(),
+ PlaceExtra::None => Value::Scalar(ptr),
PlaceExtra::Length(len) => ptr.to_value_with_len(len, self.tcx.tcx),
PlaceExtra::Vtable(vtable) => ptr.to_value_with_vtable(vtable),
PlaceExtra::DowncastVariant(..) => {
let layout = self.layout_of(ty)?;
assert!(!layout.is_unsized(),
"SizeOf nullary MIR operator called for unsized type");
- let defined = self.memory.pointer_size().bits() as u8;
+ let size = self.memory.pointer_size().bytes() as u8;
self.write_scalar(
dest,
Scalar::Bits {
bits: layout.size.bytes() as u128,
- defined,
+ size,
},
dest_ty,
)?;
let layout = self.layout_of(ty)?;
let place = self.eval_place(place)?;
let discr_val = self.read_discriminant_value(place, layout)?;
- let defined = self.layout_of(dest_ty).unwrap().size.bits() as u8;
+ let size = self.layout_of(dest_ty).unwrap().size.bytes() as u8;
self.write_scalar(dest, Scalar::Bits {
bits: discr_val,
- defined,
+ size,
}, dest_ty)?;
}
}
assert!(variants_start == variants_end);
dataful_variant as u128
},
- Scalar::Bits { bits: raw_discr, defined } => {
- if defined < discr.size.bits() as u8 {
- return err!(ReadUndefBytes);
- }
+ Scalar::Bits { bits: raw_discr, size } => {
+ assert_eq!(size as u64, discr.size.bytes());
let discr = raw_discr.wrapping_sub(niche_start)
.wrapping_add(variants_start);
if variants_start <= discr && discr <= variants_end {
// raw discriminants for enums are isize or bigger during
// their computation, but the in-memory tag is the smallest possible
// representation
- let size = tag.value.size(self.tcx.tcx).bits();
- let shift = 128 - size;
+ let size = tag.value.size(self.tcx.tcx);
+ let shift = 128 - size.bits();
let discr_val = (discr_val << shift) >> shift;
let (discr_dest, tag) = self.place_field(dest, mir::Field::new(0), layout)?;
self.write_scalar(discr_dest, Scalar::Bits {
bits: discr_val,
- defined: size as u8,
+ size: size.bytes() as u8,
}, tag.ty)?;
}
layout::Variants::NicheFilling {
.wrapping_add(niche_start);
self.write_scalar(niche_dest, Scalar::Bits {
bits: niche_value,
- defined: niche.size.bits() as u8,
+ size: niche.size.bytes() as u8,
}, niche.ty)?;
}
}
},
};
Ok(Place::Ptr {
- ptr,
+ ptr: ptr.into(),
align,
extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant),
})
pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
let new_place = match place {
Place::Local { frame, local } => {
- match self.stack[frame].locals[local] {
- None => return err!(DeadLocal),
- Some(Value::ByRef(ptr, align)) => {
+ match self.stack[frame].locals[local].access()? {
+ Value::ByRef(ptr, align) => {
Place::Ptr {
- ptr,
+ ptr: ptr.into(),
align,
extra: PlaceExtra::None,
}
}
- Some(val) => {
+ val => {
let ty = self.stack[frame].mir.local_decls[local].ty;
let ty = self.monomorphize(ty, self.stack[frame].instance.substs);
let layout = self.layout_of(ty)?;
let ptr = self.alloc_ptr(layout)?;
self.stack[frame].locals[local] =
- Some(Value::ByRef(ptr.into(), layout.align)); // it stays live
+ LocalValue::Live(Value::ByRef(ptr.into(), layout.align)); // it stays live
+
let place = Place::from_ptr(ptr, layout.align);
self.write_value(ValTy { value: val, ty }, place)?;
place
match self.follow_by_ref_value(value, ty)? {
Value::ByRef { .. } => bug!("follow_by_ref_value can't result in `ByRef`"),
- Value::Scalar(scalar) => Ok(scalar),
+ Value::Scalar(scalar) => scalar.unwrap_or_err(),
Value::ScalarPair(..) => bug!("value_to_scalar can't work with fat pointers"),
}
pub fn write_scalar(
&mut self,
dest: Place,
- val: Scalar,
+ val: impl Into<ScalarMaybeUndef>,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx> {
let valty = ValTy {
- value: Value::Scalar(val),
+ value: Value::Scalar(val.into()),
ty: dest_ty,
};
self.write_value(valty, dest)
match dest {
Place::Ptr { ptr, align, extra } => {
assert_eq!(extra, PlaceExtra::None);
- self.write_value_to_ptr(src_val, ptr, align, dest_ty)
+ self.write_value_to_ptr(src_val, ptr.unwrap_or_err()?, align, dest_ty)
}
Place::Local { frame, local } => {
- let dest = self.stack[frame].get_local(local)?;
+ let old_val = self.stack[frame].locals[local].access()?;
self.write_value_possibly_by_val(
src_val,
|this, val| this.stack[frame].set_local(local, val),
- dest,
+ old_val,
dest_ty,
)
}
old_dest_val: Value,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx> {
+ // FIXME: this should be a layout check, not underlying value
if let Value::ByRef(dest_ptr, align) = old_dest_val {
// If the value is already `ByRef` (that is, backed by an `Allocation`),
// then we must write the new value into this allocation, because there may be
layout::Primitive::Int(_, signed) => signed,
_ => false,
},
- _ => match scalar {
- Scalar::Bits { defined: 0, .. } => false,
- _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout),
- }
+ _ => false,
};
- self.memory.write_scalar(dest, dest_align, scalar, layout.size, signed)
+ self.memory.write_scalar(dest, dest_align, scalar, layout.size, layout.align, signed)
}
Value::ScalarPair(a_val, b_val) => {
trace!("write_value_to_ptr valpair: {:#?}", layout);
_ => bug!("write_value_to_ptr: invalid ScalarPair layout: {:#?}", layout)
};
let (a_size, b_size) = (a.size(&self), b.size(&self));
+ let (a_align, b_align) = (a.align(&self), b.align(&self));
let a_ptr = dest;
- let b_offset = a_size.abi_align(b.align(&self));
+ let b_offset = a_size.abi_align(b_align);
let b_ptr = dest.ptr_offset(b_offset, &self)?.into();
// TODO: What about signedess?
- self.memory.write_scalar(a_ptr, dest_align, a_val, a_size, false)?;
- self.memory.write_scalar(b_ptr, dest_align, b_val, b_size, false)
+ self.memory.write_scalar(a_ptr, dest_align, a_val, a_size, a_align, false)?;
+ self.memory.write_scalar(b_ptr, dest_align, b_val, b_size, b_align, false)
}
}
}
}
}
- pub(crate) fn read_ptr(
- &self,
- ptr: Pointer,
- ptr_align: Align,
- pointee_ty: Ty<'tcx>,
- ) -> EvalResult<'tcx, Value> {
- let ptr_size = self.memory.pointer_size();
- let p: Scalar = self.memory.read_ptr_sized(ptr, ptr_align)?.into();
- if self.type_is_sized(pointee_ty) {
- Ok(p.to_value())
- } else {
- trace!("reading fat pointer extra of type {}", pointee_ty);
- let extra = ptr.offset(ptr_size, self)?;
- match self.tcx.struct_tail(pointee_ty).sty {
- ty::TyDynamic(..) => Ok(p.to_value_with_vtable(
- self.memory.read_ptr_sized(extra, ptr_align)?.to_ptr()?,
- )),
- ty::TySlice(..) | ty::TyStr => {
- let len = self
- .memory
- .read_ptr_sized(extra, ptr_align)?
- .to_bits(ptr_size)?;
- Ok(p.to_value_with_len(len as u64, self.tcx.tcx))
- },
- _ => bug!("unsized scalar ptr read from {:?}", pointee_ty),
- }
- }
- }
-
fn validate_scalar(
&self,
- value: Scalar,
+ value: ScalarMaybeUndef,
size: Size,
scalar: &layout::Scalar,
path: &str,
trace!("validate scalar: {:#?}, {:#?}, {:#?}, {}", value, size, scalar, ty);
let (lo, hi) = scalar.valid_range.clone().into_inner();
- let (bits, defined) = match value {
- Scalar::Bits { bits, defined } => (bits, defined),
+ let value = match value {
+ ScalarMaybeUndef::Scalar(scalar) => scalar,
+ ScalarMaybeUndef::Undef => return validation_failure!("undefined bytes", path),
+ };
+
+ let bits = match value {
+ Scalar::Bits { bits, size: value_size } => {
+ assert_eq!(value_size as u64, size.bytes());
+ bits
+ },
Scalar::Ptr(_) => {
let ptr_size = self.memory.pointer_size();
let ptr_max = u128::max_value() >> (128 - ptr_size.bits());
// has no special checks for chars
match ty.sty {
ty::TyChar => {
- assert_eq!(size.bytes(), 4);
+ debug_assert_eq!(size.bytes(), 4);
if ::std::char::from_u32(bits as u32).is_none() {
return err!(InvalidChar(bits));
}
}
use std::ops::RangeInclusive;
- let in_range = |bound: RangeInclusive<u128>| {
- defined as u64 >= size.bits() && bound.contains(&bits)
- };
+ let in_range = |bound: RangeInclusive<u128>| bound.contains(&bits);
if lo > hi {
if in_range(0..=hi) || in_range(lo..=u128::max_value()) {
Ok(())
- } else if defined as u64 >= size.bits() {
+ } else {
validation_failure!(
bits,
path,
format!("something in the range {:?} or {:?}", ..=hi, lo..)
)
- } else {
- validation_failure!("undefined bytes", path)
}
} else {
if in_range(scalar.valid_range.clone()) {
Ok(())
- } else if defined as u64 >= size.bits() {
+ } else {
validation_failure!(
bits,
path,
format!("something in the range {:?}", scalar.valid_range)
)
- } else {
- validation_failure!("undefined bytes", path)
}
}
}
mir::Field::new(0),
layout,
)?;
- let tag_value = self.value_to_scalar(ValTy {
- value: tag_value,
- ty: tag_layout.ty,
- })?;
+ let tag_value = match self.follow_by_ref_value(tag_value, tag_layout.ty)? {
+ Value::Scalar(val) => val,
+ _ => bug!("tag must be scalar"),
+ };
let path = format!("{}.TAG", path);
self.validate_scalar(tag_value, size, tag, &path, tag_layout.ty)?;
let variant_index = self.read_discriminant_as_variant_index(
self.validate_scalar(value, size, scalar, &path, layout.ty)?;
if scalar.value == Primitive::Pointer {
// ignore integer pointers, we can't reason about the final hardware
- if let Scalar::Ptr(ptr) = value {
+ if let Scalar::Ptr(ptr) = value.unwrap_or_err()? {
let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
if let Some(AllocType::Static(did)) = alloc_kind {
// statics from other crates are already checked
self.memory.check_align(ptr, ptr_align)?;
if layout.size.bytes() == 0 {
- return Ok(Some(Value::Scalar(Scalar::undef())));
+ return Ok(Some(Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { bits: 0, size: 0 }))));
}
let ptr = ptr.to_ptr()?;
}
let (src_f_value, src_field) = match src {
Value::ByRef(ptr, align) => {
- let src_place = Place::from_scalar_ptr(ptr, align);
+ let src_place = Place::from_scalar_ptr(ptr.into(), align);
let (src_f_place, src_field) =
self.place_field(src_place, mir::Field::new(i), src_layout)?;
(self.read_place(src_f_place)?, src_field)
}
write!(msg, ":").unwrap();
- match self.stack[frame].get_local(local) {
+ match self.stack[frame].locals[local].access() {
Err(err) => {
if let EvalErrorKind::DeadLocal = err.kind {
write!(msg, " is dead").unwrap();
}
Ok(Value::Scalar(val)) => {
write!(msg, " {:?}", val).unwrap();
- if let Scalar::Ptr(ptr) = val {
+ if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val {
allocs.push(ptr.alloc_id);
}
}
Ok(Value::ScalarPair(val1, val2)) => {
write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
- if let Scalar::Ptr(ptr) = val1 {
+ if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val1 {
allocs.push(ptr.alloc_id);
}
- if let Scalar::Ptr(ptr) = val2 {
+ if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val2 {
allocs.push(ptr.alloc_id);
}
}
}
Place::Ptr { ptr, align, .. } => {
match ptr {
- Scalar::Ptr(ptr) => {
+ ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => {
trace!("by align({}) ref:", align.abi());
self.memory.dump_alloc(ptr.alloc_id);
}
}
}
- /// Convenience function to ensure correct usage of locals
- pub fn modify_local<F>(&mut self, frame: usize, local: mir::Local, f: F) -> EvalResult<'tcx>
- where
- F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
- {
- let val = self.stack[frame].get_local(local)?;
- let new_val = f(self, val)?;
- self.stack[frame].set_local(local, new_val)?;
- // FIXME(solson): Run this when setting to Undef? (See previous version of this code.)
- // if let Value::ByRef(ptr) = self.stack[frame].get_local(local) {
- // self.memory.deallocate(ptr)?;
- // }
- Ok(())
- }
-
pub fn generate_stacktrace(&self, explicit_span: Option<Span>) -> (Vec<FrameInfo>, Span) {
let mut last_span = None;
let mut frames = Vec::new();
(frames, self.tcx.span)
}
- pub fn sign_extend(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
- super::sign_extend(self.tcx.tcx, value, ty)
+ pub fn sign_extend(&self, value: u128, ty: TyLayout<'_>) -> u128 {
+ super::sign_extend(value, ty)
}
- pub fn truncate(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
- super::truncate(self.tcx.tcx, value, ty)
+ pub fn truncate(&self, value: u128, ty: TyLayout<'_>) -> u128 {
+ super::truncate(value, ty)
}
fn write_field_name(&self, s: &mut String, ty: Ty<'tcx>, i: usize, variant: usize) -> ::std::fmt::Result {
}
}
}
-}
-impl<'mir, 'tcx> Frame<'mir, 'tcx> {
- pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> {
- self.locals[local].ok_or_else(|| EvalErrorKind::DeadLocal.into())
+ pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, LocalValue> {
+ trace!("{:?} is now live", local);
+
+ let ty = self.frame().mir.local_decls[local].ty;
+ let init = self.init_value(ty)?;
+ // StorageLive *always* kills the value that's currently stored
+ Ok(mem::replace(&mut self.frame_mut().locals[local], LocalValue::Live(init)))
}
+ fn init_value(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+ let ty = self.monomorphize(ty, self.substs());
+ let layout = self.layout_of(ty)?;
+ Ok(match layout.abi {
+ layout::Abi::Scalar(..) => Value::Scalar(ScalarMaybeUndef::Undef),
+ layout::Abi::ScalarPair(..) => Value::ScalarPair(
+ ScalarMaybeUndef::Undef,
+ ScalarMaybeUndef::Undef,
+ ),
+ _ => Value::ByRef(self.alloc_ptr(layout)?.into(), layout.align),
+ })
+ }
+}
+
+impl<'mir, 'tcx> Frame<'mir, 'tcx> {
fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> {
match self.locals[local] {
- None => err!(DeadLocal),
- Some(ref mut local) => {
+ LocalValue::Dead => err!(DeadLocal),
+ LocalValue::Live(ref mut local) => {
*local = value;
Ok(())
}
}
}
- pub fn storage_live(&mut self, local: mir::Local) -> Option<Value> {
- trace!("{:?} is now live", local);
-
- // StorageLive *always* kills the value that's currently stored
- mem::replace(&mut self.locals[local], Some(Value::Scalar(Scalar::undef())))
- }
-
/// Returns the old value of the local
- pub fn storage_dead(&mut self, local: mir::Local) -> Option<Value> {
+ pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue {
trace!("{:?} is now dead", local);
- self.locals[local].take()
+ mem::replace(&mut self.locals[local], LocalValue::Dead)
}
}
use rustc::ty::ParamEnv;
use rustc::ty::query::TyCtxtAt;
use rustc::ty::layout::{self, Align, TargetDataLayout, Size};
-use rustc::mir::interpret::{Pointer, AllocId, Allocation, AccessKind, Value,
+use rustc::mir::interpret::{Pointer, AllocId, Allocation, AccessKind, Value, ScalarMaybeUndef,
EvalResult, Scalar, EvalErrorKind, GlobalId, AllocType};
pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint};
use rustc_data_structures::fx::{FxHashSet, FxHashMap, FxHasher};
let alloc = self.get(ptr.alloc_id)?;
(ptr.offset.bytes(), alloc.align)
}
- Scalar::Bits { bits, defined } => {
- if (defined as u64) < self.pointer_size().bits() {
- return err!(ReadUndefBytes);
- }
+ Scalar::Bits { bits, size } => {
+ assert_eq!(size as u64, self.pointer_size().bytes());
// FIXME: what on earth does this line do? docs or fix needed!
let v = ((bits as u128) % (1 << self.pointer_size().bytes())) as u64;
if v == 0 {
Ok(())
}
- pub fn read_scalar(&self, ptr: Pointer, ptr_align: Align, size: Size) -> EvalResult<'tcx, Scalar> {
+ pub fn read_scalar(&self, ptr: Pointer, ptr_align: Align, size: Size) -> EvalResult<'tcx, ScalarMaybeUndef> {
self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer
let endianness = self.endianness();
let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?;
// We must not return Ok() for unaligned pointers!
if self.check_defined(ptr, size).is_err() {
// this inflates undefined bytes to the entire scalar, even if only a few bytes are undefined
- return Ok(Scalar::undef().into());
+ return Ok(ScalarMaybeUndef::Undef);
}
// Now we do the actual reading
let bits = read_target_uint(endianness, bytes).unwrap();
} else {
let alloc = self.get(ptr.alloc_id)?;
match alloc.relocations.get(&ptr.offset) {
- Some(&alloc_id) => return Ok(Pointer::new(alloc_id, Size::from_bytes(bits as u64)).into()),
+ Some(&alloc_id) => return Ok(ScalarMaybeUndef::Scalar(Pointer::new(alloc_id, Size::from_bytes(bits as u64)).into())),
None => {},
}
}
// We don't. Just return the bits.
- Ok(Scalar::Bits {
+ Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
bits,
- defined: size.bits() as u8,
- })
+ size: size.bytes() as u8,
+ }))
}
- pub fn read_ptr_sized(&self, ptr: Pointer, ptr_align: Align) -> EvalResult<'tcx, Scalar> {
+ pub fn read_ptr_sized(&self, ptr: Pointer, ptr_align: Align) -> EvalResult<'tcx, ScalarMaybeUndef> {
self.read_scalar(ptr, ptr_align, self.pointer_size())
}
- pub fn write_scalar(&mut self, ptr: Scalar, ptr_align: Align, val: Scalar, size: Size, signed: bool) -> EvalResult<'tcx> {
+ pub fn write_scalar(
+ &mut self,
+ ptr: Scalar,
+ ptr_align: Align,
+ val: ScalarMaybeUndef,
+ type_size: Size,
+ type_align: Align,
+ signed: bool,
+ ) -> EvalResult<'tcx> {
let endianness = self.endianness();
+ self.check_align(ptr, ptr_align)?;
+
+ let val = match val {
+ ScalarMaybeUndef::Scalar(scalar) => scalar,
+ ScalarMaybeUndef::Undef => return self.mark_definedness(ptr, type_size, false),
+ };
let bytes = match val {
Scalar::Ptr(val) => {
- assert_eq!(size, self.pointer_size());
+ assert_eq!(type_size, self.pointer_size());
val.offset.bytes() as u128
}
- Scalar::Bits { bits, defined } if defined as u64 >= size.bits() && size.bits() != 0 => bits,
-
- Scalar::Bits { .. } => {
- self.check_align(ptr.into(), ptr_align)?;
- self.mark_definedness(ptr, size, false)?;
+ Scalar::Bits { size: 0, .. } => {
+ // nothing to do for ZSTs
+ assert_eq!(type_size.bytes(), 0);
return Ok(());
}
+
+ Scalar::Bits { bits, size } => {
+ assert_eq!(size as u64, type_size.bytes());
+ bits
+ },
};
let ptr = ptr.to_ptr()?;
{
- let align = self.int_align(size);
- let dst = self.get_bytes_mut(ptr, size, ptr_align.min(align))?;
+ let dst = self.get_bytes_mut(ptr, type_size, ptr_align.min(type_align))?;
if signed {
write_target_int(endianness, dst, bytes as i128).unwrap();
} else {
Ok(())
}
- pub fn write_ptr_sized_unsigned(&mut self, ptr: Pointer, ptr_align: Align, val: Scalar) -> EvalResult<'tcx> {
+ pub fn write_ptr_sized_unsigned(&mut self, ptr: Pointer, ptr_align: Align, val: ScalarMaybeUndef) -> EvalResult<'tcx> {
let ptr_size = self.pointer_size();
- self.write_scalar(ptr.into(), ptr_align, val, ptr_size, false)
+ self.write_scalar(ptr.into(), ptr_align, val, ptr_size, ptr_align, false)
}
fn int_align(&self, size: Size) -> Align {
fn into_ptr(
&self,
value: Value,
- ) -> EvalResult<'tcx, Scalar> {
+ ) -> EvalResult<'tcx, ScalarMaybeUndef> {
Ok(match value {
Value::ByRef(ptr, align) => {
self.memory().read_ptr_sized(ptr.to_ptr()?, align)?
fn into_ptr_vtable_pair(
&self,
value: Value,
- ) -> EvalResult<'tcx, (Scalar, Pointer)> {
+ ) -> EvalResult<'tcx, (ScalarMaybeUndef, Pointer)> {
match value {
Value::ByRef(ref_ptr, align) => {
let mem = self.memory();
let vtable = mem.read_ptr_sized(
ref_ptr.ptr_offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?,
align
- )?.to_ptr()?;
+ )?.unwrap_or_err()?.to_ptr()?;
Ok((ptr, vtable))
}
- Value::ScalarPair(ptr, vtable) => Ok((ptr.into(), vtable.to_ptr()?)),
+ Value::ScalarPair(ptr, vtable) => Ok((ptr, vtable.unwrap_or_err()?.to_ptr()?)),
_ => bug!("expected ptr and vtable, got {:?}", value),
}
}
fn into_slice(
&self,
value: Value,
- ) -> EvalResult<'tcx, (Scalar, u64)> {
+ ) -> EvalResult<'tcx, (ScalarMaybeUndef, u64)> {
match value {
Value::ByRef(ref_ptr, align) => {
let mem = self.memory();
let len = mem.read_ptr_sized(
ref_ptr.ptr_offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?,
align
- )?.to_bits(mem.pointer_size())? as u64;
+ )?.unwrap_or_err()?.to_bits(mem.pointer_size())? as u64;
Ok((ptr, len))
}
Value::ScalarPair(ptr, val) => {
- let len = val.to_bits(self.memory().pointer_size())?;
- Ok((ptr.into(), len as u64))
+ let len = val.unwrap_or_err()?.to_bits(self.memory().pointer_size())?;
+ Ok((ptr, len as u64))
}
Value::Scalar(_) => bug!("expected ptr and length, got {:?}", value),
}
mod terminator;
mod traits;
-pub use self::eval_context::{EvalContext, Frame, StackPopCleanup,
- TyAndPacked, ValTy};
+pub use self::eval_context::{
+ EvalContext, Frame, StackPopCleanup,
+ TyAndPacked, ValTy,
+};
pub use self::place::{Place, PlaceExtra};
pub use self::memory::{write_target_uint, write_target_int, read_target_uint};
-use rustc::mir::interpret::{EvalResult, EvalErrorKind};
-use rustc::ty::{Ty, TyCtxt, ParamEnv};
+use rustc::ty::layout::TyLayout;
-pub fn sign_extend<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
- let param_env = ParamEnv::empty();
- let layout = tcx.layout_of(param_env.and(ty)).map_err(|layout| EvalErrorKind::Layout(layout))?;
+pub fn sign_extend(value: u128, layout: TyLayout<'_>) -> u128 {
let size = layout.size.bits();
assert!(layout.abi.is_signed());
// sign extend
let shift = 128 - size;
// shift the unsigned value to the left
// and back to the right as signed (essentially fills with FF on the left)
- Ok((((value << shift) as i128) >> shift) as u128)
+ (((value << shift) as i128) >> shift) as u128
}
-pub fn truncate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
- let param_env = ParamEnv::empty();
- let layout = tcx.layout_of(param_env.and(ty)).map_err(|layout| EvalErrorKind::Layout(layout))?;
+pub fn truncate(value: u128, layout: TyLayout<'_>) -> u128 {
let size = layout.size.bits();
let shift = 128 - size;
// truncate (shift left to drop out leftover values, shift right to fill with zeroes)
- Ok((value << shift) >> shift)
+ (value << shift) >> shift
}
use rustc::mir;
use rustc::ty::{self, Ty, layout};
use syntax::ast::FloatTy;
-use rustc::ty::layout::LayoutOf;
+use rustc::ty::layout::{LayoutOf, TyLayout};
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
fn binop_with_overflow(
- &mut self,
+ &self,
op: mir::BinOp,
left: ValTy<'tcx>,
right: ValTy<'tcx>,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx> {
let (val, overflowed) = self.binop_with_overflow(op, left, right)?;
- let val = Value::ScalarPair(val, Scalar::from_bool(overflowed));
+ let val = Value::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
let valty = ValTy {
value: val,
ty: dest_ty,
let signed = left_layout.abi.is_signed();
let mut oflo = (r as u32 as u128) != r;
let mut r = r as u32;
- let size = left_layout.size.bits() as u32;
- oflo |= r >= size;
+ let size = left_layout.size;
+ oflo |= r >= size.bits() as u32;
if oflo {
- r %= size;
+ r %= size.bits() as u32;
}
let result = if signed {
- let l = self.sign_extend(l, left_ty)? as i128;
+ let l = self.sign_extend(l, left_layout) as i128;
let result = match bin_op {
Shl => l << r,
Shr => l >> r,
_ => bug!("it has already been checked that this is a shift op"),
}
};
- let truncated = self.truncate(result, left_ty)?;
+ let truncated = self.truncate(result, left_layout);
return Ok((Scalar::Bits {
bits: truncated,
- defined: size as u8,
+ size: size.bytes() as u8,
}, oflo));
}
_ => None,
};
if let Some(op) = op {
- let l = self.sign_extend(l, left_ty)? as i128;
- let r = self.sign_extend(r, right_ty)? as i128;
+ let l = self.sign_extend(l, left_layout) as i128;
+ let r = self.sign_extend(r, right_layout) as i128;
return Ok((Scalar::from_bool(op(&l, &r)), false));
}
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
_ => None,
};
if let Some(op) = op {
- let l128 = self.sign_extend(l, left_ty)? as i128;
- let r = self.sign_extend(r, right_ty)? as i128;
- let size = left_layout.size.bits();
+ let l128 = self.sign_extend(l, left_layout) as i128;
+ let r = self.sign_extend(r, right_layout) as i128;
+ let size = left_layout.size;
match bin_op {
Rem | Div => {
// int_min / -1
- if r == -1 && l == (1 << (size - 1)) {
- return Ok((Scalar::Bits { bits: l, defined: size as u8 }, true));
+ if r == -1 && l == (1 << (size.bits() - 1)) {
+ return Ok((Scalar::Bits { bits: l, size: size.bytes() as u8 }, true));
}
},
_ => {},
trace!("{}, {}, {}", l, l128, r);
let (result, mut oflo) = op(l128, r);
trace!("{}, {}", result, oflo);
- if !oflo && size != 128 {
- let max = 1 << (size - 1);
+ if !oflo && size.bits() != 128 {
+ let max = 1 << (size.bits() - 1);
oflo = result >= max || result < -max;
}
let result = result as u128;
- let truncated = self.truncate(result, left_ty)?;
+ let truncated = self.truncate(result, left_layout);
return Ok((Scalar::Bits {
bits: truncated,
- defined: size as u8,
+ size: size.bytes() as u8,
}, oflo));
}
}
if let ty::TyFloat(fty) = left_ty.sty {
macro_rules! float_math {
- ($ty:path, $bitsize:expr) => {{
+ ($ty:path, $size:expr) => {{
let l = <$ty>::from_bits(l);
let r = <$ty>::from_bits(r);
let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
bits: res.value.to_bits(),
- defined: $bitsize,
+ size: $size,
};
let val = match bin_op {
Eq => Scalar::from_bool(l == r),
}};
}
match fty {
- FloatTy::F32 => float_math!(Single, 32),
- FloatTy::F64 => float_math!(Double, 64),
+ FloatTy::F32 => float_math!(Single, 4),
+ FloatTy::F64 => float_math!(Double, 8),
}
}
- let bit_width = self.layout_of(left_ty).unwrap().size.bits() as u8;
+ let size = self.layout_of(left_ty).unwrap().size.bytes() as u8;
// only ints left
let val = match bin_op {
Gt => Scalar::from_bool(l > r),
Ge => Scalar::from_bool(l >= r),
- BitOr => Scalar::Bits { bits: l | r, defined: bit_width },
- BitAnd => Scalar::Bits { bits: l & r, defined: bit_width },
- BitXor => Scalar::Bits { bits: l ^ r, defined: bit_width },
+ BitOr => Scalar::Bits { bits: l | r, size },
+ BitAnd => Scalar::Bits { bits: l & r, size },
+ BitXor => Scalar::Bits { bits: l ^ r, size },
Add | Sub | Mul | Rem | Div => {
let op: fn(u128, u128) -> (u128, bool) = match bin_op {
_ => bug!(),
};
let (result, oflo) = op(l, r);
- let truncated = self.truncate(result, left_ty)?;
+ let truncated = self.truncate(result, left_layout);
return Ok((Scalar::Bits {
bits: truncated,
- defined: bit_width,
+ size,
}, oflo || truncated != result));
}
&self,
un_op: mir::UnOp,
val: Scalar,
- ty: Ty<'tcx>,
+ layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, Scalar> {
use rustc::mir::UnOp::*;
use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::Float;
- let size = self.layout_of(ty)?.size;
+ let size = layout.size;
let bytes = val.to_bits(size)?;
- let size = size.bits();
- let result_bytes = match (un_op, &ty.sty) {
+ let result_bytes = match (un_op, &layout.ty.sty) {
(Not, ty::TyBool) => !val.to_bool()? as u128,
(Neg, ty::TyFloat(FloatTy::F32)) => Single::to_bits(-Single::from_bits(bytes)),
(Neg, ty::TyFloat(FloatTy::F64)) => Double::to_bits(-Double::from_bits(bytes)),
- (Neg, _) if bytes == (1 << (size - 1)) => return err!(OverflowNeg),
+ (Neg, _) if bytes == (1 << (size.bits() - 1)) => return err!(OverflowNeg),
(Neg, _) => (-(bytes as i128)) as u128,
};
Ok(Scalar::Bits {
- bits: self.truncate(result_bytes, ty)?,
- defined: size as u8,
+ bits: self.truncate(result_bytes, layout),
+ size: size.bytes() as u8,
})
}
}
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
use rustc_data_structures::indexed_vec::Idx;
-use rustc::mir::interpret::{GlobalId, Value, Scalar, EvalResult, Pointer};
+use rustc::mir::interpret::{GlobalId, Value, Scalar, EvalResult, Pointer, ScalarMaybeUndef};
use super::{EvalContext, Machine, ValTy};
use interpret::memory::HasMemory;
/// A place may have an invalid (integral or undef) pointer,
/// since it might be turned back into a reference
/// before ever being dereferenced.
- ptr: Scalar,
+ ptr: ScalarMaybeUndef,
align: Align,
extra: PlaceExtra,
},
impl<'tcx> Place {
/// Produces a Place that will error if attempted to be read from
pub fn undef() -> Self {
- Self::from_scalar_ptr(Scalar::undef().into(), Align::from_bytes(1, 1).unwrap())
+ Self::from_scalar_ptr(ScalarMaybeUndef::Undef, Align::from_bytes(1, 1).unwrap())
}
- pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self {
+ pub fn from_scalar_ptr(ptr: ScalarMaybeUndef, align: Align) -> Self {
Place::Ptr {
ptr,
align,
}
pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
- Self::from_scalar_ptr(ptr.into(), align)
+ Self::from_scalar_ptr(ScalarMaybeUndef::Scalar(ptr.into()), align)
}
- pub fn to_ptr_align_extra(self) -> (Scalar, Align, PlaceExtra) {
+ pub fn to_ptr_align_extra(self) -> (ScalarMaybeUndef, Align, PlaceExtra) {
match self {
Place::Ptr { ptr, align, extra } => (ptr, align, extra),
_ => bug!("to_ptr_and_extra: expected Place::Ptr, got {:?}", self),
}
}
- pub fn to_ptr_align(self) -> (Scalar, Align) {
+ pub fn to_ptr_align(self) -> (ScalarMaybeUndef, Align) {
let (ptr, align, _extra) = self.to_ptr_align_extra();
(ptr, align)
}
pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
// At this point, we forget about the alignment information -- the place has been turned into a reference,
// and no matter where it came from, it now must be aligned.
- self.to_ptr_align().0.to_ptr()
+ self.to_ptr_align().0.unwrap_or_err()?.to_ptr()
}
pub(super) fn elem_ty_and_len(
// Might allow this in the future, right now there's no way to do this from Rust code anyway
Local(mir::RETURN_PLACE) => err!(ReadFromReturnPointer),
// Directly reading a local will always succeed
- Local(local) => self.frame().get_local(local).map(Some),
+ Local(local) => self.frame().locals[local].access().map(Some),
// No fast path for statics. Reading from statics is rare and would require another
// Machine function to handle differently in miri.
Promoted(_) |
let field = base_layout.field(self, field_index)?;
if field.size.bytes() == 0 {
return Ok((
- Value::Scalar(Scalar::undef()),
+ Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { bits: 0, size: 0 })),
field,
));
}
match place {
Place::Ptr { ptr, align, extra } => {
assert_eq!(extra, PlaceExtra::None);
- Ok(Value::ByRef(ptr, align))
+ Ok(Value::ByRef(ptr.unwrap_or_err()?, align))
}
- Place::Local { frame, local } => self.stack[frame].get_local(local),
+ Place::Local { frame, local } => self.stack[frame].locals[local].access(),
}
}
})?;
if let Value::ByRef(ptr, align) = val {
Place::Ptr {
- ptr,
+ ptr: ptr.into(),
align,
extra: PlaceExtra::None,
}
};
let alloc = Machine::init_static(self, cid)?;
Place::Ptr {
- ptr: Scalar::Ptr(alloc.into()),
+ ptr: ScalarMaybeUndef::Scalar(Scalar::Ptr(alloc.into())),
align: layout.align,
extra: PlaceExtra::None,
}
let (base_ptr, base_align, base_extra) = match base {
Place::Ptr { ptr, align, extra } => (ptr, align, extra),
Place::Local { frame, local } => {
- match (&self.stack[frame].get_local(local)?, &base_layout.abi) {
+ match (self.stack[frame].locals[local].access()?, &base_layout.abi) {
// in case the field covers the entire type, just return the value
- (&Value::Scalar(_), &layout::Abi::Scalar(_)) |
- (&Value::ScalarPair(..), &layout::Abi::ScalarPair(..))
- if offset.bytes() == 0 && field.size == base_layout.size =>
- {
- return Ok((base, field));
- }
+ (Value::Scalar(_), &layout::Abi::Scalar(_)) |
+ (Value::ScalarPair(..), &layout::Abi::ScalarPair(..))
+ if offset.bytes() == 0 && field.size == base_layout.size => {
+ return Ok((base, field))
+ },
_ => self.force_allocation(base)?.to_ptr_align_extra(),
}
}
}
Index(local) => {
- let value = self.frame().get_local(local)?;
+ let value = self.frame().locals[local].access()?;
let ty = self.tcx.types.usize;
let n = self
.value_to_scalar(ValTy { value, ty })?
// Mark locals as alive
StorageLive(local) => {
- let old_val = self.frame_mut().storage_live(local);
+ let old_val = self.storage_live(local)?;
self.deallocate_local(old_val)?;
}
use rustc::ty::{self, Ty};
use syntax::codemap::Span;
-use rustc::mir::interpret::{EvalResult, Scalar, Value};
+use rustc::mir::interpret::{EvalResult, Value};
use interpret::{Machine, ValTy, EvalContext, Place, PlaceExtra};
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
ptr,
align: _,
extra: PlaceExtra::None,
- } => ptr.to_value(),
+ } => Value::Scalar(ptr),
_ => bug!("force_allocation broken"),
};
self.drop(val, instance, ty, span, target)
let instance = match ty.sty {
ty::TyDynamic(..) => {
- let vtable = match arg {
- Value::ScalarPair(_, Scalar::Ptr(vtable)) => vtable,
- _ => bug!("expected fat ptr, got {:?}", arg),
- };
- match self.read_drop_type_from_vtable(vtable)? {
- Some(func) => func,
- // no drop fn -> bail out
- None => {
- self.goto_block(target);
- return Ok(())
- },
+ if let Value::ScalarPair(_, vtable) = arg {
+ self.read_drop_type_from_vtable(vtable.unwrap_or_err()?.to_ptr()?)?
+ } else {
+ bug!("expected fat ptr, got {:?}", arg);
}
}
_ => instance,
use syntax::codemap::Span;
use rustc_target::spec::abi::Abi;
-use rustc::mir::interpret::{EvalResult, Scalar};
+use rustc::mir::interpret::{EvalResult, Scalar, Value};
use super::{EvalContext, Place, Machine, ValTy};
use rustc_data_structures::indexed_vec::Idx;
for (index, &const_int) in values.iter().enumerate() {
// Compare using binary_op
- let const_int = Scalar::Bits { bits: const_int, defined: 128 };
+ let const_int = Scalar::Bits { bits: const_int, size: discr_layout.size.bytes() as u8 };
let res = self.binary_op(mir::BinOp::Eq,
discr_prim, discr_val.ty,
const_int, discr_val.ty
let fn_ptr = self.memory.read_ptr_sized(
vtable.offset(ptr_size * (idx as u64 + 3), &self)?,
ptr_align
- )?.to_ptr()?;
+ )?.unwrap_or_err()?.to_ptr()?;
let instance = self.memory.get_fn(fn_ptr)?;
let mut args = args.to_vec();
let ty = self.layout_of(args[0].ty)?.field(&self, 0)?.ty;
args[0].ty = ty;
- args[0].value = ptr.to_value();
+ args[0].value = Value::Scalar(ptr);
// recurse with concrete function
self.eval_fn_call(instance, destination, &args, span, sig)
}
use rustc::ty::{self, Ty};
use rustc::ty::layout::{Size, Align, LayoutOf};
-use rustc::mir::interpret::{Scalar, Value, Pointer, EvalResult};
+use rustc::mir::interpret::{Scalar, Pointer, EvalResult};
use syntax::ast::Mutability;
let drop = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
let drop = self.memory.create_fn_alloc(drop);
- self.memory.write_ptr_sized_unsigned(vtable, ptr_align, drop.into())?;
+ self.memory.write_ptr_sized_unsigned(vtable, ptr_align, Scalar::Ptr(drop).into())?;
let size_ptr = vtable.offset(ptr_size, &self)?;
self.memory.write_ptr_sized_unsigned(size_ptr, ptr_align, Scalar::Bits {
bits: size as u128,
- defined: ptr_size.bits() as u8,
- })?;
+ size: ptr_size.bytes() as u8,
+ }.into())?;
let align_ptr = vtable.offset(ptr_size * 2, &self)?;
self.memory.write_ptr_sized_unsigned(align_ptr, ptr_align, Scalar::Bits {
bits: align as u128,
- defined: ptr_size.bits() as u8,
- })?;
+ size: ptr_size.bytes() as u8,
+ }.into())?;
for (i, method) in methods.iter().enumerate() {
if let Some((def_id, substs)) = *method {
let instance = self.resolve(def_id, substs)?;
let fn_ptr = self.memory.create_fn_alloc(instance);
let method_ptr = vtable.offset(ptr_size * (3 + i as u64), &self)?;
- self.memory.write_ptr_sized_unsigned(method_ptr, ptr_align, fn_ptr.into())?;
+ self.memory.write_ptr_sized_unsigned(method_ptr, ptr_align, Scalar::Ptr(fn_ptr).into())?;
}
}
pub fn read_drop_type_from_vtable(
&self,
vtable: Pointer,
- ) -> EvalResult<'tcx, Option<ty::Instance<'tcx>>> {
+ ) -> EvalResult<'tcx, ty::Instance<'tcx>> {
// we don't care about the pointee type, we just want a pointer
let pointer_align = self.tcx.data_layout.pointer_align;
- let pointer_size = self.tcx.data_layout.pointer_size.bits() as u8;
- match self.read_ptr(vtable, pointer_align, self.tcx.mk_nil_ptr())? {
- // some values don't need to call a drop impl, so the value is null
- Value::Scalar(Scalar::Bits { bits: 0, defined} ) if defined == pointer_size => Ok(None),
- Value::Scalar(Scalar::Ptr(drop_fn)) => self.memory.get_fn(drop_fn).map(Some),
- _ => err!(ReadBytesAsPointer),
- }
+ let drop_fn = self.memory.read_ptr_sized(vtable, pointer_align)?.unwrap_or_err()?.to_ptr()?;
+ self.memory.get_fn(drop_fn)
}
pub fn read_size_and_align_from_vtable(
) -> EvalResult<'tcx, (Size, Align)> {
let pointer_size = self.memory.pointer_size();
let pointer_align = self.tcx.data_layout.pointer_align;
- let size = self.memory.read_ptr_sized(vtable.offset(pointer_size, self)?, pointer_align)?.to_bits(pointer_size)? as u64;
+ let size = self.memory.read_ptr_sized(vtable.offset(pointer_size, self)?, pointer_align)?.unwrap_or_err()?.to_bits(pointer_size)? as u64;
let align = self.memory.read_ptr_sized(
vtable.offset(pointer_size * 2, self)?,
pointer_align
- )?.to_bits(pointer_size)? as u64;
+ )?.unwrap_or_err()?.to_bits(pointer_size)? as u64;
Ok((Size::from_bytes(size), Align::from_bytes(align, align).unwrap()))
}
}
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
-use rustc::mir::interpret::{AllocId, ConstValue};
+use rustc::mir::interpret::{AllocId, ConstValue, ScalarMaybeUndef};
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
use rustc::ty::subst::Substs;
use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind};
InliningMap {
index: FxHashMap(),
targets: Vec::new(),
- inlines: BitVector::new(1024),
+ inlines: BitVector::with_capacity(1024),
}
}
// If we are not in share generics mode, we don't link to upstream
// monomorphizations but always instantiate our own internal versions
// instead.
- if !tcx.share_generics() {
+ if !tcx.sess.opts.share_generics() {
return false
}
/// the return type of `main`. This is not needed when
/// the user writes their own `start` manually.
fn push_extra_entry_roots(&mut self) {
- if self.tcx.sess.entry_fn.get().map(|e| e.2) != Some(config::EntryMain) {
+ if self.tcx.sess.entry_fn.get().map(|e| e.2) != Some(config::EntryFnType::Main) {
return
}
};
match val {
ConstValue::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
- ConstValue::ScalarPair(Scalar::Ptr(a), Scalar::Ptr(b)) => {
+ ConstValue::ScalarPair(Scalar::Ptr(a), ScalarMaybeUndef::Scalar(Scalar::Ptr(b))) => {
collect_miri(tcx, a.alloc_id, output);
collect_miri(tcx, b.alloc_id, output);
}
- ConstValue::ScalarPair(_, Scalar::Ptr(ptr)) |
+ ConstValue::ScalarPair(_, ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr))) |
ConstValue::ScalarPair(Scalar::Ptr(ptr), _) |
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
collect_miri(tcx, ptr.alloc_id, output),
// available to downstream crates. This depends on whether we are in
// share-generics mode and whether the current crate can even have
// downstream crates.
- let export_generics = tcx.share_generics() &&
+ let export_generics = tcx.sess.opts.share_generics() &&
tcx.local_crate_exports_generics();
for mono_item in mono_items {
use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind};
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
use rustc::mir::visit::{Visitor, PlaceContext};
-use rustc::mir::interpret::{ConstEvalErr, EvalErrorKind};
+use rustc::mir::interpret::{ConstEvalErr, EvalErrorKind, ScalarMaybeUndef};
use rustc::ty::{TyCtxt, self, Instance};
use rustc::mir::interpret::{Value, Scalar, GlobalId, EvalResult};
use interpret::EvalContext;
type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some((
Value::Scalar(Scalar::Bits {
bits: n as u128,
- defined: self.tcx.data_layout.pointer_size.bits() as u8,
- }),
+ size: self.tcx.data_layout.pointer_size.bytes() as u8,
+ }.into()),
self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
span,
)))
let prim = self.use_ecx(source_info, |this| {
this.ecx.value_to_scalar(ValTy { value: val.0, ty: val.1.ty })
})?;
- let val = self.use_ecx(source_info, |this| this.ecx.unary_op(op, prim, val.1.ty))?;
- Some((Value::Scalar(val), place_layout, span))
+ let val = self.use_ecx(source_info, |this| this.ecx.unary_op(op, prim, val.1))?;
+ Some((Value::Scalar(val.into()), place_layout, span))
}
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
Rvalue::BinaryOp(op, ref left, ref right) => {
})?;
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
Value::ScalarPair(
- val,
- Scalar::from_bool(overflow),
+ val.into(),
+ Scalar::from_bool(overflow).into(),
)
} else {
if overflow {
let _: Option<()> = self.use_ecx(source_info, |_| Err(err));
return None;
}
- Value::Scalar(val)
+ Value::Scalar(val.into())
};
Some((val, place_layout, span))
},
if let TerminatorKind::Assert { expected, msg, cond, .. } = kind {
if let Some(value) = self.eval_operand(cond, source_info) {
trace!("assertion on {:?} should be {:?}", value, expected);
- if Value::Scalar(Scalar::from_bool(*expected)) != value.0 {
+ if Value::Scalar(Scalar::from_bool(*expected).into()) != value.0 {
// poison all places this operand references so that further code
// doesn't use the invalid value
match cond {
.eval_operand(len, source_info)
.expect("len must be const");
let len = match len.0 {
- Value::Scalar(Scalar::Bits { bits, ..}) => bits,
+ Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits {
+ bits, ..
+ })) => bits,
_ => bug!("const len not primitive: {:?}", len),
};
let index = self
.eval_operand(index, source_info)
.expect("index must be const");
let index = match index.0 {
- Value::Scalar(Scalar::Bits { bits, .. }) => bits,
+ Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits {
+ bits, ..
+ })) => bits,
_ => bug!("const index not primitive: {:?}", index),
};
format!(
// The `liveness` variable contains the liveness of MIR locals ignoring borrows.
// This is correct for movable generators since borrows cannot live across
// suspension points. However for immovable generators we need to account for
- // borrows, so we conseratively assume that all borrowed locals live forever.
+ // borrows, so we conseratively assume that all borrowed locals are live until
+ // we find a StorageDead statement referencing the locals.
// To do this we just union our `liveness` result with `borrowed_locals`, which
// contains all the locals which has been borrowed before this suspension point.
// If a borrow is converted to a raw reference, we must also assume that it lives
use rustc::hir::CodegenFnAttrFlags;
use rustc::hir::def_id::DefId;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::*;
// Traverse the MIR manually so we can account for the effects of
// inlining on the CFG.
let mut work_list = vec![START_BLOCK];
- let mut visited = BitVector::new(callee_mir.basic_blocks().len());
+ let mut visited = BitArray::new(callee_mir.basic_blocks().len());
while let Some(bb) = work_list.pop() {
if !visited.insert(bb.index()) { continue; }
let blk = &callee_mir.basic_blocks()[bb];
//! The Qualif flags below can be used to also provide better
//! diagnostics as to why a constant rvalue wasn't promoted.
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_data_structures::fx::FxHashSet;
param_env: ty::ParamEnv<'tcx>,
local_qualif: IndexVec<Local, Option<Qualif>>,
qualif: Qualif,
- const_fn_arg_vars: BitVector<Local>,
+ const_fn_arg_vars: BitArray<Local>,
temp_promotion_state: IndexVec<Local, TempState>,
promotion_candidates: Vec<Candidate>
}
param_env,
local_qualif,
qualif: Qualif::empty(),
- const_fn_arg_vars: BitVector::new(mir.local_decls.len()),
+ const_fn_arg_vars: BitArray::new(mir.local_decls.len()),
temp_promotion_state: temps,
promotion_candidates: vec![]
}
let mir = self.mir;
- let mut seen_blocks = BitVector::new(mir.basic_blocks().len());
+ let mut seen_blocks = BitArray::new(mir.basic_blocks().len());
let mut bb = START_BLOCK;
loop {
seen_blocks.insert(bb.index());
use rustc::ty::TyCtxt;
use rustc::mir::*;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use transform::{MirPass, MirSource};
use util::patch::MirPatch;
&self,
bb: BasicBlock,
mir: &Mir,
- nop_landing_pads: &BitVector<BasicBlock>,
+ nop_landing_pads: &BitArray<BasicBlock>,
) -> bool {
for stmt in &mir[bb].statements {
match stmt.kind {
let mut jumps_folded = 0;
let mut landing_pads_removed = 0;
- let mut nop_landing_pads = BitVector::new(mir.basic_blocks().len());
+ let mut nop_landing_pads = BitArray::new(mir.basic_blocks().len());
// This is a post-order traversal, so that if A post-dominates B
// then A will be visited before B.
//! naively generate still contains the `_a = ()` write in the unreachable block "after" the
//! return.
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext};
-use rustc::session::config::FullDebugInfo;
+use rustc::session::config::DebugInfo;
use std::borrow::Cow;
use transform::{MirPass, MirSource};
}
pub fn remove_dead_blocks(mir: &mut Mir) {
- let mut seen = BitVector::new(mir.basic_blocks().len());
+ let mut seen = BitArray::new(mir.basic_blocks().len());
for (bb, _) in traversal::preorder(mir) {
seen.insert(bb.index());
}
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource,
mir: &mut Mir<'tcx>) {
- let mut marker = DeclMarker { locals: BitVector::new(mir.local_decls.len()) };
+ let mut marker = DeclMarker { locals: BitArray::new(mir.local_decls.len()) };
marker.visit_mir(mir);
// Return pointer and arguments are always live
marker.locals.insert(RETURN_PLACE);
}
// We may need to keep dead user variables live for debuginfo.
- if tcx.sess.opts.debuginfo == FullDebugInfo {
+ if tcx.sess.opts.debuginfo == DebugInfo::Full {
for local in mir.vars_iter() {
marker.locals.insert(local);
}
/// Construct the mapping while swapping out unused stuff out from the `vec`.
fn make_local_map<'tcx, V>(
vec: &mut IndexVec<Local, V>,
- mask: BitVector<Local>,
+ mask: BitArray<Local>,
) -> IndexVec<Local, Option<Local>> {
let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, &*vec);
let mut used = Local::new(0);
}
struct DeclMarker {
- pub locals: BitVector<Local>,
+ pub locals: BitArray<Local>,
}
impl<'tcx> Visitor<'tcx> for DeclMarker {
desc,
OGN = o
);
- err.span_label(old_loan_span, "first closure is constructed here");
- err.span_label(new_loan_span, "second closure is constructed here");
+ if old_loan_span == new_loan_span {
+ err.span_label(
+ old_loan_span,
+ "closures are constructed here in different iterations of loop"
+ );
+ } else {
+ err.span_label(old_loan_span, "first closure is constructed here");
+ err.span_label(new_loan_span, "second closure is constructed here");
+ }
if let Some(old_load_end_span) = old_load_end_span {
err.span_label(old_load_end_span, "borrow from first closure ends here");
}
impl<'a> AstValidator<'a> {
fn err_handler(&self) -> &errors::Handler {
- &self.session.parse_sess.span_diagnostic
+ &self.session.diagnostic()
}
fn check_lifetime(&self, ident: Ident) {
impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
fn path_is_private_type(&self, path: &hir::Path) -> bool {
let did = match path.def {
- Def::PrimTy(..) | Def::SelfTy(..) => return false,
+ Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => return false,
def => def.def_id(),
};
rustc_errors = { path = "../librustc_errors" }
syntax_pos = { path = "../libsyntax_pos" }
rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_metadata = { path = "../librustc_metadata" }
use Namespace::{self, TypeNS, ValueNS, MacroNS};
use {resolve_error, resolve_struct_error, ResolutionError};
-use rustc::middle::cstore::LoadedMacro;
use rustc::hir::def::*;
use rustc::hir::def_id::{BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
use rustc::ty;
+use rustc::middle::cstore::CrateStore;
+use rustc_metadata::cstore::LoadedMacro;
use std::cell::Cell;
use rustc_data_structures::sync::Lrc;
impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) {
fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
arenas.alloc_name_binding(NameBinding {
- kind: NameBindingKind::Def(self.0),
+ kind: NameBindingKind::Def(self.0, false),
+ vis: self.1,
+ span: self.2,
+ expansion: self.3,
+ })
+ }
+}
+
+pub(crate) struct IsMacroExport;
+
+impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark, IsMacroExport) {
+ fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
+ arenas.alloc_name_binding(NameBinding {
+ kind: NameBindingKind::Def(self.0, true),
vis: self.1,
span: self.2,
expansion: self.3,
imports: Vec<(Name, Span)>,
}
-impl<'a> Resolver<'a> {
+impl<'a, 'cl> Resolver<'a, 'cl> {
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
/// otherwise, reports an error.
pub fn define<T>(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def: T)
pub fn get_macro(&mut self, def: Def) -> Lrc<SyntaxExtension> {
let def_id = match def {
Def::Macro(def_id, ..) => def_id,
- _ => panic!("Expected Def::Macro(..)"),
+ Def::NonMacroAttr => return Lrc::new(SyntaxExtension::NonMacroAttr),
+ _ => panic!("Expected Def::Macro(..) or Def::NonMacroAttr"),
};
if let Some(ext) = self.macro_map.get(&def_id) {
return ext.clone();
}
}
-pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
- pub resolver: &'a mut Resolver<'b>,
+pub struct BuildReducedGraphVisitor<'a, 'b: 'a, 'c: 'b> {
+ pub resolver: &'a mut Resolver<'b, 'c>,
pub legacy_scope: LegacyScope<'b>,
pub expansion: Mark,
}
-impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
+impl<'a, 'b, 'cl> BuildReducedGraphVisitor<'a, 'b, 'cl> {
fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
let mark = id.placeholder_to_mark();
self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark);
+ self.resolver.unresolved_invocations_macro_export.insert(mark);
let invocation = self.resolver.invocations[&mark];
invocation.module.set(self.resolver.current_module);
invocation.legacy_scope.set(self.legacy_scope);
}
}
-impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
+impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr);
method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat);
use syntax_pos::{Span, MultiSpan, DUMMY_SP};
-struct UnusedImportCheckVisitor<'a, 'b: 'a> {
- resolver: &'a mut Resolver<'b>,
+struct UnusedImportCheckVisitor<'a, 'b: 'a, 'd: 'b> {
+ resolver: &'a mut Resolver<'b, 'd>,
/// All the (so far) unused imports, grouped path list
unused_imports: NodeMap<NodeMap<Span>>,
base_id: ast::NodeId,
}
// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
-impl<'a, 'b> Deref for UnusedImportCheckVisitor<'a, 'b> {
- type Target = Resolver<'b>;
+impl<'a, 'b, 'd> Deref for UnusedImportCheckVisitor<'a, 'b, 'd> {
+ type Target = Resolver<'b, 'd>;
- fn deref<'c>(&'c self) -> &'c Resolver<'b> {
+ fn deref<'c>(&'c self) -> &'c Resolver<'b, 'd> {
&*self.resolver
}
}
-impl<'a, 'b> DerefMut for UnusedImportCheckVisitor<'a, 'b> {
- fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> {
+impl<'a, 'b, 'd> DerefMut for UnusedImportCheckVisitor<'a, 'b, 'd> {
+ fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b, 'd> {
&mut *self.resolver
}
}
-impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
+impl<'a, 'b, 'd> UnusedImportCheckVisitor<'a, 'b, 'd> {
// We have information about whether `use` (import) directives are actually
// used now. If an import is not used at all, we signal a lint error.
fn check_import(&mut self, item_id: ast::NodeId, id: ast::NodeId, span: Span) {
}
}
-impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> {
+impl<'a, 'b, 'cl> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'cl> {
fn visit_item(&mut self, item: &'a ast::Item) {
self.item_span = item.span;
directive.vis.get() == ty::Visibility::Public ||
directive.span.is_dummy() => {
if let ImportDirectiveSubclass::MacroUse = directive.subclass {
- if resolver.session.features_untracked().use_extern_macros &&
- !directive.span.is_dummy() {
+ if resolver.use_extern_macros && !directive.span.is_dummy() {
resolver.session.buffer_lint(
lint::builtin::MACRO_USE_EXTERN_CRATE,
directive.id,
#[macro_use]
extern crate rustc;
extern crate rustc_data_structures;
+extern crate rustc_metadata;
pub use rustc::hir::def::{Namespace, PerNS};
use rustc::hir::map::{Definitions, DefCollector};
use rustc::hir::{self, PrimTy, TyBool, TyChar, TyFloat, TyInt, TyUint, TyStr};
-use rustc::middle::cstore::{CrateStore, CrateLoader};
+use rustc::middle::cstore::CrateStore;
use rustc::session::Session;
use rustc::lint;
use rustc::hir::def::*;
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
+use rustc_metadata::creader::CrateLoader;
+use rustc_metadata::cstore::CStore;
+
use syntax::codemap::CodeMap;
use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext};
use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
mod build_reduced_graph;
mod resolve_imports;
+fn is_known_tool(name: Name) -> bool {
+ ["clippy", "rustfmt"].contains(&&*name.as_str())
+}
+
/// A free importable items suggested in case of resolution failure.
struct ImportSuggestion {
path: Path,
err.span_label(typaram_span, "type variable from outer function");
}
},
- Def::Mod(..) | Def::Struct(..) | Def::Union(..) | Def::Enum(..) | Def::Variant(..) |
- Def::Trait(..) | Def::TyAlias(..) | Def::TyForeign(..) | Def::TraitAlias(..) |
- Def::AssociatedTy(..) | Def::PrimTy(..) | Def::Fn(..) | Def::Const(..) |
- Def::Static(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::Method(..) |
- Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | Def::Label(..) |
- Def::Existential(..) | Def::AssociatedExistential(..) |
- Def::Macro(..) | Def::GlobalAsm(..) | Def::Err =>
+ _ => {
bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \
Def::TyParam")
+ }
}
// Try to retrieve the span of the function signature and generate a new message with
}
/// This thing walks the whole crate in DFS manner, visiting each item, resolving names as it goes.
-impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
+impl<'a, 'tcx, 'cl> Visitor<'tcx> for Resolver<'a, 'cl> {
fn visit_item(&mut self, item: &'tcx Item) {
self.resolve_item(item);
}
#[derive(Clone, Debug)]
enum NameBindingKind<'a> {
- Def(Def),
+ Def(Def, /* is_macro_export */ bool),
Module(Module<'a>),
Import {
binding: &'a NameBinding<'a>,
fn def(&self) -> Def {
match self.kind {
- NameBindingKind::Def(def) => def,
+ NameBindingKind::Def(def, _) => def,
NameBindingKind::Module(module) => module.def().unwrap(),
NameBindingKind::Import { binding, .. } => binding.def(),
NameBindingKind::Ambiguity { .. } => Def::Err,
}
}
- fn get_macro(&self, resolver: &mut Resolver<'a>) -> Lrc<SyntaxExtension> {
+ fn get_macro<'b: 'a>(&self, resolver: &mut Resolver<'a, 'b>) -> Lrc<SyntaxExtension> {
resolver.get_macro(self.def_ignoring_ambiguity())
}
fn is_variant(&self) -> bool {
match self.kind {
- NameBindingKind::Def(Def::Variant(..)) |
- NameBindingKind::Def(Def::VariantCtor(..)) => true,
+ NameBindingKind::Def(Def::Variant(..), _) |
+ NameBindingKind::Def(Def::VariantCtor(..), _) => true,
_ => false,
}
}
fn is_macro_def(&self) -> bool {
match self.kind {
- NameBindingKind::Def(Def::Macro(..)) => true,
+ NameBindingKind::Def(Def::Macro(..), _) => true,
_ => false,
}
}
/// The main resolver class.
///
/// This is the visitor that walks the whole crate.
-pub struct Resolver<'a> {
+pub struct Resolver<'a, 'b: 'a> {
session: &'a Session,
- cstore: &'a dyn CrateStore,
+ cstore: &'a CStore,
pub definitions: Definitions,
/// true if `#![feature(use_extern_macros)]`
use_extern_macros: bool,
- crate_loader: &'a mut dyn CrateLoader,
+ crate_loader: &'a mut CrateLoader<'b>,
macro_names: FxHashSet<Ident>,
macro_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
pub all_macros: FxHashMap<Name, Def>,
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
macro_defs: FxHashMap<Mark, DefId>,
local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
- macro_exports: Vec<Export>,
+ macro_exports: Vec<Export>, // FIXME: Remove when `use_extern_macros` is stabilized
pub whitelisted_legacy_custom_derives: Vec<Name>,
pub found_unresolved_macro: bool,
/// Only supposed to be used by rustdoc, otherwise should be false.
pub ignore_extern_prelude_feature: bool,
+
+ /// Macro invocations in the whole crate that can expand into a `#[macro_export] macro_rules`.
+ unresolved_invocations_macro_export: FxHashSet<Mark>,
}
/// Nothing really interesting here, it just provides memory for the rest of the crate.
}
}
-impl<'a, 'b: 'a> ty::DefIdTree for &'a Resolver<'b> {
+impl<'a, 'b: 'a, 'cl: 'b> ty::DefIdTree for &'a Resolver<'b, 'cl> {
fn parent(self, id: DefId) -> Option<DefId> {
match id.krate {
LOCAL_CRATE => self.definitions.def_key(id.index).parent,
/// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
/// the resolver is no longer needed as all the relevant information is inline.
-impl<'a> hir::lowering::Resolver for Resolver<'a> {
+impl<'a, 'cl> hir::lowering::Resolver for Resolver<'a, 'cl> {
fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) {
self.resolve_hir_path_cb(path, is_value,
|resolver, span, error| resolve_error(resolver, span, error))
}
}
-impl<'a> Resolver<'a> {
+impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
/// Rustdoc uses this to resolve things in a recoverable way. ResolutionError<'a>
/// isn't something that can be returned because it can't be made to live that long,
/// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
}
}
-impl<'a> Resolver<'a> {
+impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
pub fn new(session: &'a Session,
- cstore: &'a dyn CrateStore,
+ cstore: &'a CStore,
krate: &Crate,
crate_name: &str,
make_glob_map: MakeGlobMap,
- crate_loader: &'a mut dyn CrateLoader,
+ crate_loader: &'a mut CrateLoader<'crateloader>,
arenas: &'a ResolverArenas<'a>)
- -> Resolver<'a> {
+ -> Resolver<'a, 'crateloader> {
let root_def_id = DefId::local(CRATE_DEF_INDEX);
let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name());
let graph_root = arenas.alloc_module(ModuleData {
arenas,
dummy_binding: arenas.alloc_name_binding(NameBinding {
- kind: NameBindingKind::Def(Def::Err),
+ kind: NameBindingKind::Def(Def::Err, false),
expansion: Mark::root(),
span: DUMMY_SP,
vis: ty::Visibility::Public,
}),
- // The `proc_macro` and `decl_macro` features imply `use_extern_macros`
- use_extern_macros:
- features.use_extern_macros || features.decl_macro,
+ use_extern_macros: features.use_extern_macros(),
crate_loader,
macro_names: FxHashSet(),
current_type_ascription: Vec::new(),
injected_crate: None,
ignore_extern_prelude_feature: false,
+ unresolved_invocations_macro_export: FxHashSet(),
}
}
path_span: Span)
-> Option<LexicalScopeBinding<'a>> {
let record_used = record_used_id.is_some();
+ assert!(ns == TypeNS || ns == ValueNS);
if ns == TypeNS {
ident.span = if ident.name == keywords::SelfType.name() {
// FIXME(jseyfried) improve `Self` hygiene
return Some(LexicalScopeBinding::Item(binding))
}
_ if poisoned.is_some() => break,
- Err(Undetermined) => return None,
- Err(Determined) => {}
+ Err(Determined) => continue,
+ Err(Undetermined) =>
+ span_bug!(ident.span, "undetermined resolution during main resolution pass"),
}
}
ident.span, Mark::root()).to_name_binding(self.arenas);
return Some(LexicalScopeBinding::Item(binding));
}
+ if ns == TypeNS && is_known_tool(ident.name) {
+ let binding = (Def::ToolMod, ty::Visibility::Public,
+ ident.span, Mark::root()).to_name_binding(self.arenas);
+ return Some(LexicalScopeBinding::Item(binding));
+ }
if let Some(prelude) = self.prelude {
if let Ok(binding) = self.resolve_ident_in_module_unadjusted(prelude, ident, ns,
false, false, path_span) {
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def);
if let Some(next_module) = binding.module() {
module = Some(next_module);
+ } else if def == Def::ToolMod && i + 1 != path.len() {
+ return PathResult::NonModule(PathResolution::new(Def::NonMacroAttr))
} else if def == Def::Err {
return PathResult::NonModule(err_path_resolution());
} else if opt_ns.is_some() && (is_last || maybe_assoc) {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use {AmbiguityError, CrateLint, Resolver, ResolutionError, resolve_error};
-use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult};
-use Namespace::{self, MacroNS};
-use build_reduced_graph::BuildReducedGraphVisitor;
+use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error};
+use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
+use Namespace::{self, TypeNS, MacroNS};
+use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
use resolve_imports::ImportResolver;
use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex,
DefIndexAddressSpace};
use rustc::hir::def::{Def, Export};
use rustc::hir::map::{self, DefCollector};
use rustc::{ty, lint};
+use rustc::middle::cstore::CrateStore;
use syntax::ast::{self, Name, Ident};
use syntax::attr::{self, HasAttrs};
use syntax::errors::DiagnosticBuilder;
use syntax::ext::hygiene::{self, Mark};
use syntax::ext::placeholders::placeholder;
use syntax::ext::tt::macro_rules;
-use syntax::feature_gate::{self, emit_feature_err, GateIssue};
+use syntax::feature_gate::{self, feature_err, emit_feature_err, is_builtin_attr_name, GateIssue};
use syntax::fold::{self, Folder};
use syntax::parse::parser::PathStyle;
use syntax::parse::token::{self, Token};
}
}
-impl<'a> base::Resolver for Resolver<'a> {
+impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
fn next_node_id(&mut self) -> ast::NodeId {
self.session.next_node_id()
}
}
fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> {
- struct EliminateCrateVar<'b, 'a: 'b>(&'b mut Resolver<'a>, Span);
+ struct EliminateCrateVar<'b, 'a: 'b, 'crateloader: 'a>(
+ &'b mut Resolver<'a, 'crateloader>, Span
+ );
- impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> {
+ impl<'a, 'b, 'crateloader> Folder for EliminateCrateVar<'a, 'b, 'crateloader> {
fn fold_path(&mut self, path: ast::Path) -> ast::Path {
match self.fold_qpath(None, path) {
(None, path) => path,
self.current_module = invocation.module.get();
self.current_module.unresolved_invocations.borrow_mut().remove(&mark);
+ self.unresolved_invocations_macro_export.remove(&mark);
self.current_module.unresolved_invocations.borrow_mut().extend(derives);
+ self.unresolved_invocations_macro_export.extend(derives);
for &derive in derives {
self.invocations.insert(derive, invocation);
}
let kind = ext.kind();
self.macro_map.insert(def_id, ext);
let binding = self.arenas.alloc_name_binding(NameBinding {
- kind: NameBindingKind::Def(Def::Macro(def_id, kind)),
+ kind: NameBindingKind::Def(Def::Macro(def_id, kind), false),
span: DUMMY_SP,
vis: ty::Visibility::Invisible,
expansion: Mark::root(),
if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
self.report_proc_macro_stub(invoc.span());
return Err(Determinacy::Determined);
+ } else if let Def::NonMacroAttr = def {
+ if let InvocationKind::Attr { .. } = invoc.kind {
+ if !self.session.features_untracked().tool_attributes {
+ feature_err(&self.session.parse_sess, "tool_attributes",
+ invoc.span(), GateIssue::Language,
+ "tool attributes are unstable").emit();
+ }
+ return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr)));
+ } else {
+ self.report_non_macro_attr(invoc.path_span());
+ return Err(Determinacy::Determined);
+ }
}
let def_id = def.def_id();
if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
self.report_proc_macro_stub(path.span);
return Err(Determinacy::Determined);
+ } else if let Def::NonMacroAttr = def {
+ self.report_non_macro_attr(path.span);
+ return Err(Determinacy::Determined);
}
self.unused_macros.remove(&def.def_id());
Ok(self.get_macro(def))
}
}
-impl<'a> Resolver<'a> {
+impl<'a, 'cl> Resolver<'a, 'cl> {
fn report_proc_macro_stub(&self, span: Span) {
self.session.span_err(span,
"can't use a procedural macro from the same crate that defines it");
}
+ fn report_non_macro_attr(&self, span: Span) {
+ self.session.span_err(span,
+ "expected a macro, found non-macro attribute");
+ }
+
fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
-> Result<Def, Determinacy> {
let (attr, traits, item) = match invoc.kind {
fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
-> Result<Def, Determinacy> {
- if kind != MacroKind::Bang && path.segments.len() > 1 {
+ let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
+ if def != Err(Determinacy::Undetermined) {
+ // Do not report duplicated errors on every undetermined resolution.
+ path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
+ self.session.span_err(segment.args.as_ref().unwrap().span(),
+ "generic arguments in macro path");
+ });
+ }
+ if kind != MacroKind::Bang && path.segments.len() > 1 && def != Ok(Def::NonMacroAttr) {
if !self.session.features_untracked().proc_macro_path_invoc {
emit_feature_err(
&self.session.parse_sess,
);
}
}
-
- let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
- if def != Err(Determinacy::Undetermined) {
- // Do not report duplicated errors on every undetermined resolution.
- path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
- self.session.span_err(segment.args.as_ref().unwrap().span(),
- "generic arguments in macro path");
- });
- }
def
}
result
}
- // Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`)
+ // Resolve the initial segment of a non-global macro path
+ // (e.g. `foo` in `foo::bar!(); or `foo!();`).
+ // This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
+ // expansion and import resolution (perhaps they can be merged in the future).
pub fn resolve_lexical_macro_path_segment(&mut self,
mut ident: Ident,
ns: Namespace,
record_used: bool,
path_span: Span)
-> Result<MacroBinding<'a>, Determinacy> {
+ // General principles:
+ // 1. Not controlled (user-defined) names should have higher priority than controlled names
+ // built into the language or standard library. This way we can add new names into the
+ // language or standard library without breaking user code.
+ // 2. "Closed set" below means new names can appear after the current resolution attempt.
+ // Places to search (in order of decreasing priority):
+ // (Type NS)
+ // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
+ // (open set, not controlled).
+ // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+ // (open, not controlled).
+ // 3. Extern prelude (closed, not controlled).
+ // 4. Tool modules (closed, controlled right now, but not in the future).
+ // 5. Standard library prelude (de-facto closed, controlled).
+ // 6. Language prelude (closed, controlled).
+ // (Macro NS)
+ // 1. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+ // (open, not controlled).
+ // 2. Macro prelude (language, standard library, user-defined legacy plugins lumped into
+ // one set) (open, the open part is from macro expansions, not controlled).
+ // 2a. User-defined prelude from macro-use
+ // (open, the open part is from macro expansions, not controlled).
+ // 2b. Standard library prelude, currently just a macro-use (closed, controlled)
+ // 2c. Language prelude, perhaps including builtin attributes
+ // (closed, controlled, except for legacy plugins).
+ // 3. Builtin attributes (closed, controlled).
+
+ assert!(ns == TypeNS || ns == MacroNS);
ident = ident.modern();
- let mut module = Some(self.current_module);
- let mut potential_illegal_shadower = Err(Determinacy::Determined);
- let determinacy =
- if record_used { Determinacy::Determined } else { Determinacy::Undetermined };
+
+ // Names from inner scope that can't shadow names from outer scopes, e.g.
+ // mod m { ... }
+ // {
+ // use prefix::*; // if this imports another `m`, then it can't shadow the outer `m`
+ // // and we have and ambiguity error
+ // m::mac!();
+ // }
+ // This includes names from globs and from macro expansions.
+ let mut potentially_ambiguous_result: Option<MacroBinding> = None;
+
+ enum WhereToResolve<'a> {
+ Module(Module<'a>),
+ MacroPrelude,
+ BuiltinAttrs,
+ ExternPrelude,
+ ToolPrelude,
+ StdLibPrelude,
+ PrimitiveTypes,
+ }
+
+ // Go through all the scopes and try to resolve the name.
+ let mut where_to_resolve = WhereToResolve::Module(self.current_module);
+ let mut use_prelude = !self.current_module.no_implicit_prelude;
loop {
- let orig_current_module = self.current_module;
- let result = if let Some(module) = module {
- self.current_module = module; // Lexical resolutions can never be a privacy error.
- // Since expanded macros may not shadow the lexical scope and
- // globs may not shadow global macros (both enforced below),
- // we resolve with restricted shadowing (indicated by the penultimate argument).
- self.resolve_ident_in_module_unadjusted(
- module, ident, ns, true, record_used, path_span,
- ).map(MacroBinding::Modern)
- } else {
- self.macro_prelude.get(&ident.name).cloned().ok_or(determinacy)
- .map(MacroBinding::Global)
+ let result = match where_to_resolve {
+ WhereToResolve::Module(module) => {
+ let orig_current_module = mem::replace(&mut self.current_module, module);
+ let binding = self.resolve_ident_in_module_unadjusted(
+ module, ident, ns, true, record_used, path_span,
+ );
+ self.current_module = orig_current_module;
+ binding.map(MacroBinding::Modern)
+ }
+ WhereToResolve::MacroPrelude => {
+ match self.macro_prelude.get(&ident.name).cloned() {
+ Some(binding) => Ok(MacroBinding::Global(binding)),
+ None => Err(Determinacy::Determined),
+ }
+ }
+ WhereToResolve::BuiltinAttrs => {
+ if is_builtin_attr_name(ident.name) {
+ let binding = (Def::NonMacroAttr, ty::Visibility::Public,
+ ident.span, Mark::root()).to_name_binding(self.arenas);
+ Ok(MacroBinding::Global(binding))
+ } else {
+ Err(Determinacy::Determined)
+ }
+ }
+ WhereToResolve::ExternPrelude => {
+ if use_prelude && self.extern_prelude.contains(&ident.name) {
+ if !self.session.features_untracked().extern_prelude &&
+ !self.ignore_extern_prelude_feature {
+ feature_err(&self.session.parse_sess, "extern_prelude",
+ ident.span, GateIssue::Language,
+ "access to extern crates through prelude is experimental")
+ .emit();
+ }
+
+ let crate_id =
+ self.crate_loader.process_path_extern(ident.name, ident.span);
+ let crate_root =
+ self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
+ self.populate_module_if_necessary(crate_root);
+
+ let binding = (crate_root, ty::Visibility::Public,
+ ident.span, Mark::root()).to_name_binding(self.arenas);
+ Ok(MacroBinding::Global(binding))
+ } else {
+ Err(Determinacy::Determined)
+ }
+ }
+ WhereToResolve::ToolPrelude => {
+ if use_prelude && is_known_tool(ident.name) {
+ let binding = (Def::ToolMod, ty::Visibility::Public,
+ ident.span, Mark::root()).to_name_binding(self.arenas);
+ Ok(MacroBinding::Global(binding))
+ } else {
+ Err(Determinacy::Determined)
+ }
+ }
+ WhereToResolve::StdLibPrelude => {
+ let mut result = Err(Determinacy::Determined);
+ if use_prelude {
+ if let Some(prelude) = self.prelude {
+ if let Ok(binding) =
+ self.resolve_ident_in_module_unadjusted(prelude, ident, ns,
+ false, false, path_span) {
+ result = Ok(MacroBinding::Global(binding));
+ }
+ }
+ }
+ result
+ }
+ WhereToResolve::PrimitiveTypes => {
+ if let Some(prim_ty) =
+ self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
+ let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
+ ident.span, Mark::root()).to_name_binding(self.arenas);
+ Ok(MacroBinding::Global(binding))
+ } else {
+ Err(Determinacy::Determined)
+ }
+ }
};
- self.current_module = orig_current_module;
- match result.map(MacroBinding::binding) {
- Ok(binding) => {
+ macro_rules! continue_search { () => {
+ where_to_resolve = match where_to_resolve {
+ WhereToResolve::Module(module) => {
+ match self.hygienic_lexical_parent(module, &mut ident.span) {
+ Some(parent_module) => WhereToResolve::Module(parent_module),
+ None => {
+ use_prelude = !module.no_implicit_prelude;
+ if ns == MacroNS {
+ WhereToResolve::MacroPrelude
+ } else {
+ WhereToResolve::ExternPrelude
+ }
+ }
+ }
+ }
+ WhereToResolve::MacroPrelude => WhereToResolve::BuiltinAttrs,
+ WhereToResolve::BuiltinAttrs => break, // nowhere else to search
+ WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
+ WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
+ WhereToResolve::StdLibPrelude => WhereToResolve::PrimitiveTypes,
+ WhereToResolve::PrimitiveTypes => break, // nowhere else to search
+ };
+
+ continue;
+ }}
+
+ match result {
+ Ok(result) => {
if !record_used {
- return result;
+ return Ok(result);
}
- if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower {
- if shadower.def() != binding.def() {
- let name = ident.name;
+
+ let binding = result.binding();
+
+ // Found a solution that is ambiguous with a previously found solution.
+ // Push an ambiguity error for later reporting and
+ // return something for better recovery.
+ if let Some(previous_result) = potentially_ambiguous_result {
+ if binding.def() != previous_result.binding().def() {
self.ambiguity_errors.push(AmbiguityError {
span: path_span,
- name,
- b1: shadower,
+ name: ident.name,
+ b1: previous_result.binding(),
b2: binding,
lexical: true,
});
- return potential_illegal_shadower;
+ return Ok(previous_result);
}
}
+
+ // Found a solution that's not an ambiguity yet, but is "suspicious" and
+ // can participate in ambiguities later on.
+ // Remember it and go search for other solutions in outer scopes.
if binding.is_glob_import() || binding.expansion != Mark::root() {
- potential_illegal_shadower = result;
- } else {
- return result;
+ potentially_ambiguous_result = Some(result);
+
+ continue_search!();
}
+
+ // Found a solution that can't be ambiguous, great success.
+ return Ok(result);
},
+ Err(Determinacy::Determined) => {
+ continue_search!();
+ }
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
- Err(Determinacy::Determined) => {}
}
+ }
- module = match module {
- Some(module) => self.hygienic_lexical_parent(module, &mut ident.span),
- None => return potential_illegal_shadower,
- }
+ // Previously found potentially ambiguous result turned out to not be ambiguous after all.
+ if let Some(previous_result) = potentially_ambiguous_result {
+ return Ok(previous_result);
}
+
+ if record_used { Err(Determinacy::Determined) } else { Err(Determinacy::Undetermined) }
}
pub fn resolve_legacy_scope(&mut self,
match (legacy_resolution, resolution) {
(Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => {
- let msg1 = format!("`{}` could refer to the macro defined here", ident);
- let msg2 = format!("`{}` could also refer to the macro imported here", ident);
- self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident))
- .span_note(legacy_binding.span, &msg1)
- .span_note(binding.span, &msg2)
- .emit();
+ if legacy_binding.def_id != binding.def_ignoring_ambiguity().def_id() {
+ let msg1 = format!("`{}` could refer to the macro defined here", ident);
+ let msg2 =
+ format!("`{}` could also refer to the macro imported here", ident);
+ self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident))
+ .span_note(legacy_binding.span, &msg1)
+ .span_note(binding.span, &msg2)
+ .emit();
+ }
},
(None, Err(_)) => {
assert!(def.is_none());
let def = Def::Macro(def_id, MacroKind::Bang);
self.all_macros.insert(ident.name, def);
if attr::contains_name(&item.attrs, "macro_export") {
- self.macro_exports.push(Export {
- ident: ident.modern(),
- def: def,
- vis: ty::Visibility::Public,
- span: item.span,
- });
+ if self.use_extern_macros {
+ let module = self.graph_root;
+ let vis = ty::Visibility::Public;
+ self.define(module, ident, MacroNS,
+ (def, vis, item.span, expansion, IsMacroExport));
+ } else {
+ self.macro_exports.push(Export {
+ ident: ident.modern(),
+ def: def,
+ vis: ty::Visibility::Public,
+ span: item.span,
+ });
+ }
} else {
self.unused_macros.insert(def_id);
}
}
}
-impl<'a> Resolver<'a> {
+impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
-> &'a RefCell<NameResolution<'a>> {
*module.resolutions.borrow_mut().entry((ident.modern(), ns))
// if it cannot be shadowed by some new item/import expanded from a macro.
// This happens either if there are no unexpanded macros, or expanded names cannot
// shadow globs (that happens in macro namespace or with restricted shadowing).
- let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty();
+ let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty() ||
+ (ns == MacroNS && ptr::eq(module, self.graph_root) &&
+ !self.unresolved_invocations_macro_export.is_empty());
if let Some(binding) = resolution.binding {
if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
return check_usable(self, binding);
resolution.binding = Some(binding);
resolution.shadowed_glob = Some(old_binding);
}
+ } else if let (&NameBindingKind::Def(_, true), &NameBindingKind::Def(_, true)) =
+ (&old_binding.kind, &binding.kind) {
+
+ this.session.buffer_lint_with_diagnostic(
+ DUPLICATE_MACRO_EXPORTS,
+ CRATE_NODE_ID,
+ binding.span,
+ &format!("a macro named `{}` has already been exported", ident),
+ BuiltinLintDiagnostics::DuplicatedMacroExports(
+ ident, old_binding.span, binding.span));
+
+ resolution.binding = Some(binding);
} else {
return Err(old_binding);
}
// If the resolution becomes a success, define it in the module's glob importers.
fn update_resolution<T, F>(&mut self, module: Module<'a>, ident: Ident, ns: Namespace, f: F)
-> T
- where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T
+ where F: FnOnce(&mut Resolver<'a, 'crateloader>, &mut NameResolution<'a>) -> T
{
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
// during which the resolution might end up getting re-defined via a glob cycle.
}
}
-pub struct ImportResolver<'a, 'b: 'a> {
- pub resolver: &'a mut Resolver<'b>,
+pub struct ImportResolver<'a, 'b: 'a, 'c: 'a + 'b> {
+ pub resolver: &'a mut Resolver<'b, 'c>,
}
-impl<'a, 'b: 'a> ::std::ops::Deref for ImportResolver<'a, 'b> {
- type Target = Resolver<'b>;
- fn deref(&self) -> &Resolver<'b> {
+impl<'a, 'b: 'a, 'c: 'a + 'b> ::std::ops::Deref for ImportResolver<'a, 'b, 'c> {
+ type Target = Resolver<'b, 'c>;
+ fn deref(&self) -> &Resolver<'b, 'c> {
self.resolver
}
}
-impl<'a, 'b: 'a> ::std::ops::DerefMut for ImportResolver<'a, 'b> {
- fn deref_mut(&mut self) -> &mut Resolver<'b> {
+impl<'a, 'b: 'a, 'c: 'a + 'b> ::std::ops::DerefMut for ImportResolver<'a, 'b, 'c> {
+ fn deref_mut(&mut self) -> &mut Resolver<'b, 'c> {
self.resolver
}
}
-impl<'a, 'b: 'a> ty::DefIdTree for &'a ImportResolver<'a, 'b> {
+impl<'a, 'b: 'a, 'c: 'a + 'b> ty::DefIdTree for &'a ImportResolver<'a, 'b, 'c> {
fn parent(self, id: DefId) -> Option<DefId> {
self.resolver.parent(id)
}
}
-impl<'a, 'b:'a> ImportResolver<'a, 'b> {
+impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
// Import resolution
//
// This is a fixed-point algorithm. We resolve imports until our efforts
expansion: directive.expansion,
});
let _ = self.try_define(directive.parent, target, TypeNS, binding);
+ let import = self.import_map.entry(directive.id).or_default();
+ import[TypeNS] = Some(PathResolution::new(binding.def()));
return None;
}
}
match binding.kind {
// Never suggest the name that has binding error
// i.e. the name that cannot be previously resolved
- NameBindingKind::Def(Def::Err) => return None,
+ NameBindingKind::Def(Def::Err, _) => return None,
_ => Some(&i.name),
}
},
use rustc::hir::map::{Node, NodeTraitItem, NodeImplItem};
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::middle::cstore::ExternCrate;
-use rustc::session::config::CrateType::CrateTypeExecutable;
+use rustc::session::config::CrateType;
use rustc::ty::{self, TyCtxt};
use rustc_typeck::hir_ty_to_ty;
HirDef::Label(..) |
HirDef::Macro(..) |
HirDef::GlobalAsm(..) |
+ HirDef::ToolMod |
+ HirDef::NonMacroAttr |
HirDef::Err => None,
}
}
let executable = sess.crate_types
.borrow()
.iter()
- .any(|ct| *ct == CrateTypeExecutable);
+ .any(|ct| *ct == CrateType::Executable);
let mut out_name = if executable {
"".to_owned()
} else {
mod nvptx64;
mod powerpc;
mod powerpc64;
+mod riscv;
mod s390x;
mod sparc;
mod sparc64;
"nvptx" => nvptx::compute_abi_info(self),
"nvptx64" => nvptx64::compute_abi_info(self),
"hexagon" => hexagon::compute_abi_info(self),
+ "riscv32" => riscv::compute_abi_info(self, 32),
+ "riscv64" => riscv::compute_abi_info(self, 64),
a => return Err(format!("unrecognized arch \"{}\" in target specification", a))
}
--- /dev/null
+// Copyright 2012-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.
+
+// Reference: RISC-V ELF psABI specification
+// https://github.com/riscv/riscv-elf-psabi-doc
+
+use abi::call::{ArgType, FnType};
+
+fn classify_ret_ty<Ty>(arg: &mut ArgType<Ty>, xlen: u64) {
+ // "Scalars wider than 2✕XLEN are passed by reference and are replaced in
+ // the argument list with the address."
+ // "Aggregates larger than 2✕XLEN bits are passed by reference and are
+ // replaced in the argument list with the address, as are C++ aggregates
+ // with nontrivial copy constructors, destructors, or vtables."
+ if arg.layout.size.bits() > 2 * xlen {
+ arg.make_indirect();
+ }
+
+ // "When passed in registers, scalars narrower than XLEN bits are widened
+ // according to the sign of their type up to 32 bits, then sign-extended to
+ // XLEN bits."
+ arg.extend_integer_width_to(xlen); // this method only affects integer scalars
+}
+
+fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>, xlen: u64) {
+ // "Scalars wider than 2✕XLEN are passed by reference and are replaced in
+ // the argument list with the address."
+ // "Aggregates larger than 2✕XLEN bits are passed by reference and are
+ // replaced in the argument list with the address, as are C++ aggregates
+ // with nontrivial copy constructors, destructors, or vtables."
+ if arg.layout.size.bits() > 2 * xlen {
+ arg.make_indirect();
+ }
+
+ // "When passed in registers, scalars narrower than XLEN bits are widened
+ // according to the sign of their type up to 32 bits, then sign-extended to
+ // XLEN bits."
+ arg.extend_integer_width_to(xlen); // this method only affects integer scalars
+}
+
+pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>, xlen: u64) {
+ if !fty.ret.is_ignore() {
+ classify_ret_ty(&mut fty.ret, xlen);
+ }
+
+ for arg in &mut fty.args {
+ if arg.is_ignore() {
+ continue;
+ }
+ classify_arg_ty(arg, xlen);
+ }
+}
//! is really just odds-and-ends relating to code gen and linking.
//! This crate mostly exists to make rustc smaller, so we might put
//! more 'stuff' here in the future. It does not have a dependency on
-//! rustc_llvm.
-//!
-//! FIXME: Split this into two crates: one that has deps on syntax, and
-//! one that doesn't; the one that doesn't might get decent parallel
-//! build speedups.
+//! LLVM.
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
--- /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.
+
+use spec::{LinkerFlavor, Target, TargetResult};
+
+pub fn target() -> TargetResult {
+ let mut base = super::hermit_base::opts();
+ base.max_atomic_width = Some(128);
+ base.abi_blacklist = super::arm_base::abi_blacklist();
+ base.linker = Some("aarch64-hermit-gcc".to_string());
+
+ Ok(Target {
+ llvm_target: "aarch64-unknown-hermit".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "64".to_string(),
+ target_c_int_width: "32".to_string(),
+ data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+ arch: "aarch64".to_string(),
+ target_os: "hermit".to_string(),
+ target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ options: base,
+ })
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use spec::{LinkArgs, LinkerFlavor, PanicStrategy, TargetOptions};
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+ let mut args = LinkArgs::new();
+ args.insert(LinkerFlavor::Gcc, vec![
+ "-Wl,-Bstatic".to_string(),
+ "-Wl,--no-dynamic-linker".to_string(),
+ "-Wl,--gc-sections".to_string(),
+ "-Wl,--as-needed".to_string(),
+ ]);
+
+ TargetOptions {
+ exe_allocation_crate: None,
+ executables: true,
+ has_elf_tls: true,
+ linker_is_gnu: true,
+ no_default_libraries: false,
+ panic_strategy: PanicStrategy::Abort,
+ position_independent_executables: false,
+ pre_link_args: args,
+ relocation_model: "static".to_string(),
+ target_family: Some("unix".to_string()),
+ tls_model: "local-exec".to_string(),
+ .. Default::default()
+ }
+}
mod dragonfly_base;
mod freebsd_base;
mod haiku_base;
+mod hermit_base;
mod linux_base;
mod linux_musl_base;
mod openbsd_base;
("armv7-unknown-cloudabi-eabihf", armv7_unknown_cloudabi_eabihf),
("i686-unknown-cloudabi", i686_unknown_cloudabi),
("x86_64-unknown-cloudabi", x86_64_unknown_cloudabi),
+
+ ("aarch64-unknown-hermit", aarch64_unknown_hermit),
+ ("x86_64-unknown-hermit", x86_64_unknown_hermit),
+
+ ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
}
/// Everything `rustc` knows about how to compile for a specific target.
--- /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 spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+use spec::abi::{Abi};
+
+pub fn target() -> TargetResult {
+ Ok(Target {
+ data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+ llvm_target: "riscv32".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "32".to_string(),
+ target_c_int_width: "32".to_string(),
+ target_os: "none".to_string(),
+ target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
+ arch: "riscv32".to_string(),
+ linker_flavor: LinkerFlavor::Ld,
+
+ options: TargetOptions {
+ linker: Some("riscv32-unknown-elf-ld".to_string()),
+ cpu: "generic-rv32".to_string(),
+ max_atomic_width: Some(32),
+ atomic_cas: false, // incomplete +a extension
+ features: "+m,+a".to_string(), // disable +c extension
+ executables: true,
+ panic_strategy: PanicStrategy::Abort,
+ relocation_model: "static".to_string(),
+ abi_blacklist: vec![
+ Abi::Cdecl,
+ Abi::Stdcall,
+ Abi::Fastcall,
+ Abi::Vectorcall,
+ Abi::Thiscall,
+ Abi::Aapcs,
+ Abi::Win64,
+ Abi::SysV64,
+ Abi::PtxKernel,
+ Abi::Msp430Interrupt,
+ Abi::X86Interrupt,
+ ],
+ .. Default::default()
+ },
+ })
+}
--- /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.
+
+use spec::{LinkerFlavor, Target, TargetResult};
+
+pub fn target() -> TargetResult {
+ let mut base = super::hermit_base::opts();
+ base.cpu = "x86-64".to_string();
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
+ base.linker = Some("x86_64-hermit-gcc".to_string());
+ base.max_atomic_width = Some(64);
+
+ Ok(Target {
+ llvm_target: "x86_64-unknown-hermit".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "64".to_string(),
+ target_c_int_width: "32".to_string(),
+ data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+ arch: "x86_64".to_string(),
+ target_os: "hermit".to_string(),
+ target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ options: base,
+ })
+}
if let Some((id, _, entry_type)) = *fcx.tcx.sess.entry_fn.borrow() {
if id == fn_id {
match entry_type {
- config::EntryMain => {
+ config::EntryFnType::Main => {
let substs = fcx.tcx.mk_substs_trait(declared_ret_ty, &[]);
let trait_ref = ty::TraitRef::new(term_id, substs);
let return_ty_span = decl.output.span();
traits::Obligation::new(
cause, param_env, trait_ref.to_predicate()));
},
- config::EntryStart => {},
+ config::EntryFnType::Start => {},
}
}
}
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::query::Providers;
use rustc::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt};
+use rustc::util::profiling::ProfileCategory;
use session::{CompileIncomplete, config};
use util::common::time;
fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
if let Some((id, sp, entry_type)) = *tcx.sess.entry_fn.borrow() {
match entry_type {
- config::EntryMain => check_main_fn_ty(tcx, id, sp),
- config::EntryStart => check_start_fn_ty(tcx, id, sp),
+ config::EntryFnType::Main => check_main_fn_ty(tcx, id, sp),
+ config::EntryFnType::Start => check_start_fn_ty(tcx, id, sp),
}
}
}
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> Result<(), CompileIncomplete>
{
+ tcx.sess.profiler(|p| p.start_activity(ProfileCategory::TypeChecking));
+
// this ensures that later parts of type checking can assume that items
// have valid types and not error
tcx.sess.track_errors(|| {
check_unused::check_crate(tcx);
check_for_entry_fn(tcx);
+ tcx.sess.profiler(|p| p.end_activity(ProfileCategory::TypeChecking));
+
tcx.sess.compile_status()
}
// except according to those terms.
use rustc::hir;
-use rustc::traits::{self, auto_trait as auto};
-use rustc::ty::{self, ToPredicate, TypeFoldable};
-use rustc::ty::subst::Subst;
-use rustc::infer::InferOk;
+use rustc::traits::auto_trait as auto;
+use rustc::ty::{self, TypeFoldable};
use std::fmt::Debug;
-use syntax_pos::DUMMY_SP;
-use core::DocAccessLevels;
+use self::def_ctor::{get_def_from_def_id, get_def_from_node_id};
use super::*;
-pub struct AutoTraitFinder<'a, 'tcx: 'a, 'rcx: 'a> {
- pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>,
+pub struct AutoTraitFinder<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
+ pub cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>,
pub f: auto::AutoTraitFinder<'a, 'tcx>,
}
-impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
- pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx>) -> Self {
+impl<'a, 'tcx, 'rcx, 'cstore> AutoTraitFinder<'a, 'tcx, 'rcx, 'cstore> {
+ pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>) -> Self {
let f = auto::AutoTraitFinder::new(&cx.tcx);
AutoTraitFinder { cx, f }
}
pub fn get_with_def_id(&self, def_id: DefId) -> Vec<Item> {
- let ty = self.cx.tcx.type_of(def_id);
-
- let def_ctor: fn(DefId) -> Def = match ty.sty {
- ty::TyAdt(adt, _) => match adt.adt_kind() {
- AdtKind::Struct => Def::Struct,
- AdtKind::Enum => Def::Enum,
- AdtKind::Union => Def::Union,
- }
- ty::TyInt(_) |
- ty::TyUint(_) |
- ty::TyFloat(_) |
- ty::TyStr |
- ty::TyBool |
- ty::TyChar => return self.get_auto_trait_impls(def_id, &move |_: DefId| {
- match ty.sty {
- ty::TyInt(x) => Def::PrimTy(hir::TyInt(x)),
- ty::TyUint(x) => Def::PrimTy(hir::TyUint(x)),
- ty::TyFloat(x) => Def::PrimTy(hir::TyFloat(x)),
- ty::TyStr => Def::PrimTy(hir::TyStr),
- ty::TyBool => Def::PrimTy(hir::TyBool),
- ty::TyChar => Def::PrimTy(hir::TyChar),
- _ => unreachable!(),
- }
- }, None),
- _ => {
- debug!("Unexpected type {:?}", def_id);
- return Vec::new()
- }
- };
-
- self.get_auto_trait_impls(def_id, &def_ctor, None)
+ get_def_from_def_id(&self.cx, def_id, &|def_ctor| {
+ self.get_auto_trait_impls(def_id, &def_ctor, None)
+ })
}
pub fn get_with_node_id(&self, id: ast::NodeId, name: String) -> Vec<Item> {
- let item = &self.cx.tcx.hir.expect_item(id).node;
- let did = self.cx.tcx.hir.local_def_id(id);
-
- let def_ctor = match *item {
- hir::ItemKind::Struct(_, _) => Def::Struct,
- hir::ItemKind::Union(_, _) => Def::Union,
- hir::ItemKind::Enum(_, _) => Def::Enum,
- _ => panic!("Unexpected type {:?} {:?}", item, id),
- };
-
- self.get_auto_trait_impls(did, &def_ctor, Some(name))
- }
-
- fn get_real_ty<F>(&self,
- def_id: DefId,
- def_ctor: &F,
- real_name: &Option<Ident>,
- generics: &ty::Generics,
- ) -> hir::Ty
- where F: Fn(DefId) -> Def {
- let path = get_path_for_type(self.cx.tcx, def_id, def_ctor);
- let mut segments = path.segments.into_vec();
- let last = segments.pop().unwrap();
-
- segments.push(hir::PathSegment::new(
- real_name.unwrap_or(last.ident),
- self.generics_to_path_params(generics.clone()),
- false,
- ));
-
- let new_path = hir::Path {
- span: path.span,
- def: path.def,
- segments: HirVec::from_vec(segments),
- };
-
- hir::Ty {
- id: ast::DUMMY_NODE_ID,
- node: hir::TyKind::Path(hir::QPath::Resolved(None, P(new_path))),
- span: DUMMY_SP,
- hir_id: hir::DUMMY_HIR_ID,
- }
- }
-
- pub fn get_blanket_impls<F>(
- &self,
- def_id: DefId,
- def_ctor: &F,
- name: Option<String>,
- generics: &ty::Generics,
- ) -> Vec<Item>
- where F: Fn(DefId) -> Def {
- let ty = self.cx.tcx.type_of(def_id);
- let mut traits = Vec::new();
- if self.cx.access_levels.borrow().is_doc_reachable(def_id) {
- let real_name = name.clone().map(|name| Ident::from_str(&name));
- let param_env = self.cx.tcx.param_env(def_id);
- for &trait_def_id in self.cx.all_traits.iter() {
- if !self.cx.access_levels.borrow().is_doc_reachable(trait_def_id) ||
- self.cx.generated_synthetics
- .borrow_mut()
- .get(&(def_id, trait_def_id))
- .is_some() {
- continue
- }
- self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| {
- self.cx.tcx.infer_ctxt().enter(|infcx| {
- let t_generics = infcx.tcx.generics_of(impl_def_id);
- let trait_ref = infcx.tcx.impl_trait_ref(impl_def_id).unwrap();
-
- match infcx.tcx.type_of(impl_def_id).sty {
- ::rustc::ty::TypeVariants::TyParam(_) => {},
- _ => return,
- }
-
- let substs = infcx.fresh_substs_for_item(DUMMY_SP, def_id);
- let ty = ty.subst(infcx.tcx, substs);
- let param_env = param_env.subst(infcx.tcx, substs);
-
- let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
- let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
-
- // Require the type the impl is implemented on to match
- // our type, and ignore the impl if there was a mismatch.
- let cause = traits::ObligationCause::dummy();
- let eq_result = infcx.at(&cause, param_env)
- .eq(trait_ref.self_ty(), ty);
- if let Ok(InferOk { value: (), obligations }) = eq_result {
- // FIXME(eddyb) ignoring `obligations` might cause false positives.
- drop(obligations);
-
- let may_apply = infcx.predicate_may_hold(&traits::Obligation::new(
- cause.clone(),
- param_env,
- trait_ref.to_predicate(),
- ));
- if !may_apply {
- return
- }
- self.cx.generated_synthetics.borrow_mut()
- .insert((def_id, trait_def_id));
- let trait_ = hir::TraitRef {
- path: get_path_for_type(infcx.tcx,
- trait_def_id,
- hir::def::Def::Trait),
- ref_id: ast::DUMMY_NODE_ID,
- };
- let provided_trait_methods =
- infcx.tcx.provided_trait_methods(trait_def_id)
- .into_iter()
- .map(|meth| meth.ident.to_string())
- .collect();
-
- let ty = self.get_real_ty(def_id, def_ctor, &real_name, generics);
- let predicates = infcx.tcx.predicates_of(impl_def_id);
-
- traits.push(Item {
- source: infcx.tcx.def_span(impl_def_id).clean(self.cx),
- name: None,
- attrs: Default::default(),
- visibility: None,
- def_id: self.next_def_id(impl_def_id.krate),
- stability: None,
- deprecation: None,
- inner: ImplItem(Impl {
- unsafety: hir::Unsafety::Normal,
- generics: (t_generics, &predicates).clean(self.cx),
- provided_trait_methods,
- trait_: Some(trait_.clean(self.cx)),
- for_: ty.clean(self.cx),
- items: infcx.tcx.associated_items(impl_def_id)
- .collect::<Vec<_>>()
- .clean(self.cx),
- polarity: None,
- synthetic: false,
- blanket_impl: Some(infcx.tcx.type_of(impl_def_id)
- .clean(self.cx)),
- }),
- });
- debug!("{:?} => {}", trait_ref, may_apply);
- }
- });
- });
- }
- }
- traits
+ get_def_from_node_id(&self.cx, id, name, &|def_ctor, name| {
+ let did = self.cx.tcx.hir.local_def_id(id);
+ self.get_auto_trait_impls(did, &def_ctor, Some(name))
+ })
}
pub fn get_auto_trait_impls<F>(
def_ctor,
tcx.require_lang_item(lang_items::SyncTraitLangItem),
).into_iter())
- .chain(self.get_blanket_impls(def_id, def_ctor, name, &generics).into_iter())
.collect();
debug!(
_ => unreachable!(),
};
let real_name = name.map(|name| Ident::from_str(&name));
- let ty = self.get_real_ty(def_id, def_ctor, &real_name, &generics);
+ let ty = self.cx.get_real_ty(def_id, def_ctor, &real_name, &generics);
return Some(Item {
source: Span::empty(),
name: None,
attrs: Default::default(),
visibility: None,
- def_id: self.next_def_id(def_id.krate),
+ def_id: self.cx.next_def_id(def_id.krate),
stability: None,
deprecation: None,
inner: ImplItem(Impl {
None
}
- fn generics_to_path_params(&self, generics: ty::Generics) -> hir::GenericArgs {
- let mut args = vec![];
-
- for param in generics.params.iter() {
- match param.kind {
- ty::GenericParamDefKind::Lifetime => {
- let name = if param.name == "" {
- hir::ParamName::Plain(keywords::StaticLifetime.ident())
- } else {
- hir::ParamName::Plain(ast::Ident::from_interned_str(param.name))
- };
-
- args.push(hir::GenericArg::Lifetime(hir::Lifetime {
- id: ast::DUMMY_NODE_ID,
- span: DUMMY_SP,
- name: hir::LifetimeName::Param(name),
- }));
- }
- ty::GenericParamDefKind::Type {..} => {
- args.push(hir::GenericArg::Type(self.ty_param_to_ty(param.clone())));
- }
- }
- }
-
- hir::GenericArgs {
- args: HirVec::from_vec(args),
- bindings: HirVec::new(),
- parenthesized: false,
- }
- }
-
- fn ty_param_to_ty(&self, param: ty::GenericParamDef) -> hir::Ty {
- debug!("ty_param_to_ty({:?}) {:?}", param, param.def_id);
- hir::Ty {
- id: ast::DUMMY_NODE_ID,
- node: hir::TyKind::Path(hir::QPath::Resolved(
- None,
- P(hir::Path {
- span: DUMMY_SP,
- def: Def::TyParam(param.def_id),
- segments: HirVec::from_vec(vec![
- hir::PathSegment::from_ident(Ident::from_interned_str(param.name))
- ]),
- }),
- )),
- span: DUMMY_SP,
- hir_id: hir::DUMMY_HIR_ID,
- }
- }
-
fn find_auto_trait_generics(
&self,
did: DefId,
// Desired order is 'larger, smaller', so flip then
if self.region_name(r1) != self.region_name(r2) {
finished
- .entry(self.region_name(r2).unwrap())
+ .entry(self.region_name(r2).expect("no region_name found"))
.or_insert_with(|| Vec::new())
.push(r1);
}
(&RegionTarget::Region(r1), &RegionTarget::Region(r2)) => {
if self.region_name(r1) != self.region_name(r2) {
finished
- .entry(self.region_name(r2).unwrap())
+ .entry(self.region_name(r2).expect("no region name found"))
.or_insert_with(|| Vec::new())
.push(r1) // Larger, smaller
}
.flat_map(|(ty, mut bounds)| {
if let Some(data) = ty_to_fn.get(&ty) {
let (poly_trait, output) =
- (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned());
+ (data.0.as_ref().expect("as_ref failed").clone(), data.1.as_ref().cloned());
let new_ty = match &poly_trait.trait_ {
&Type::ResolvedPath {
ref path,
ref is_generic,
} => {
let mut new_path = path.clone();
- let last_segment = new_path.segments.pop().unwrap();
+ let last_segment = new_path.segments.pop()
+ .expect("segments were empty");
let (old_input, old_output) = match last_segment.args {
GenericArgs::AngleBracketed { types, .. } => (types, None),
let mut for_generics = self.extract_for_generics(tcx, orig_p.clone());
assert!(bounds.len() == 1);
- let mut b = bounds.pop().unwrap();
+ let mut b = bounds.pop().expect("bounds were empty");
if b.is_sized_bound(self.cx) {
has_sized.insert(ty.clone());
_ => false,
};
- let poly_trait = b.get_poly_trait().unwrap();
+ let poly_trait = b.get_poly_trait().expect("Cannot get poly trait");
if is_fn {
ty_to_fn
// FIXME: Remove this scope when NLL lands
{
let args =
- &mut new_trait_path.segments.last_mut().unwrap().args;
+ &mut new_trait_path.segments
+ .last_mut()
+ .expect("segments were empty")
+ .args;
match args {
// Convert somethiung like '<T as Iterator::Item> = u8'
_ => false,
}
}
-
- // This is an ugly hack, but it's the simplest way to handle synthetic impls without greatly
- // refactoring either librustdoc or librustc. In particular, allowing new DefIds to be
- // registered after the AST is constructed would require storing the defid mapping in a
- // RefCell, decreasing the performance for normal compilation for very little gain.
- //
- // Instead, we construct 'fake' def ids, which start immediately after the last DefId in
- // DefIndexAddressSpace::Low. In the Debug impl for clean::Item, we explicitly check for fake
- // def ids, as we'll end up with a panic if we use the DefId Debug impl for fake DefIds
- fn next_def_id(&self, crate_num: CrateNum) -> DefId {
- let start_def_id = {
- let next_id = if crate_num == LOCAL_CRATE {
- self.cx
- .tcx
- .hir
- .definitions()
- .def_path_table()
- .next_id(DefIndexAddressSpace::Low)
- } else {
- self.cx
- .cstore
- .def_path_table(crate_num)
- .next_id(DefIndexAddressSpace::Low)
- };
-
- DefId {
- krate: crate_num,
- index: next_id,
- }
- };
-
- let mut fake_ids = self.cx.fake_def_ids.borrow_mut();
-
- let def_id = fake_ids.entry(crate_num).or_insert(start_def_id).clone();
- fake_ids.insert(
- crate_num,
- DefId {
- krate: crate_num,
- index: DefIndex::from_array_index(
- def_id.index.as_array_index() + 1,
- def_id.index.address_space(),
- ),
- },
- );
-
- MAX_DEF_ID.with(|m| {
- m.borrow_mut()
- .entry(def_id.krate.clone())
- .or_insert(start_def_id);
- });
-
- self.cx.all_fake_def_ids.borrow_mut().insert(def_id);
-
- def_id.clone()
- }
}
// Replaces all ReVars in a type with ty::Region's, using the provided map
--- /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 rustc::hir;
+use rustc::traits;
+use rustc::ty::ToPredicate;
+use rustc::ty::subst::Subst;
+use rustc::infer::InferOk;
+use syntax_pos::DUMMY_SP;
+
+use core::DocAccessLevels;
+
+use super::*;
+
+use self::def_ctor::{get_def_from_def_id, get_def_from_node_id};
+
+pub struct BlanketImplFinder<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
+ pub cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>,
+}
+
+impl<'a, 'tcx, 'rcx, 'cstore> BlanketImplFinder <'a, 'tcx, 'rcx, 'cstore> {
+ pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>) -> Self {
+ BlanketImplFinder { cx }
+ }
+
+ pub fn get_with_def_id(&self, def_id: DefId) -> Vec<Item> {
+ get_def_from_def_id(&self.cx, def_id, &|def_ctor| {
+ self.get_blanket_impls(def_id, &def_ctor, None)
+ })
+ }
+
+ pub fn get_with_node_id(&self, id: ast::NodeId, name: String) -> Vec<Item> {
+ get_def_from_node_id(&self.cx, id, name, &|def_ctor, name| {
+ let did = self.cx.tcx.hir.local_def_id(id);
+ self.get_blanket_impls(did, &def_ctor, Some(name))
+ })
+ }
+
+ pub fn get_blanket_impls<F>(
+ &self,
+ def_id: DefId,
+ def_ctor: &F,
+ name: Option<String>,
+ ) -> Vec<Item>
+ where F: Fn(DefId) -> Def {
+ let mut impls = Vec::new();
+ if self.cx
+ .tcx
+ .get_attrs(def_id)
+ .lists("doc")
+ .has_word("hidden")
+ {
+ debug!(
+ "get_blanket_impls(def_id={:?}, def_ctor=...): item has doc('hidden'), \
+ aborting",
+ def_id
+ );
+ return impls;
+ }
+ let ty = self.cx.tcx.type_of(def_id);
+ if self.cx.access_levels.borrow().is_doc_reachable(def_id) || ty.is_primitive() {
+ let generics = self.cx.tcx.generics_of(def_id);
+ let real_name = name.clone().map(|name| Ident::from_str(&name));
+ let param_env = self.cx.tcx.param_env(def_id);
+ for &trait_def_id in self.cx.all_traits.iter() {
+ if !self.cx.access_levels.borrow().is_doc_reachable(trait_def_id) ||
+ self.cx.generated_synthetics
+ .borrow_mut()
+ .get(&(def_id, trait_def_id))
+ .is_some() {
+ continue
+ }
+ self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| {
+ self.cx.tcx.infer_ctxt().enter(|infcx| {
+ let t_generics = infcx.tcx.generics_of(impl_def_id);
+ let trait_ref = infcx.tcx.impl_trait_ref(impl_def_id)
+ .expect("Cannot get impl trait");
+
+ match trait_ref.self_ty().sty {
+ ty::TypeVariants::TyParam(_) => {},
+ _ => return,
+ }
+
+ let substs = infcx.fresh_substs_for_item(DUMMY_SP, def_id);
+ let ty = ty.subst(infcx.tcx, substs);
+ let param_env = param_env.subst(infcx.tcx, substs);
+
+ let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
+ let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
+
+ // Require the type the impl is implemented on to match
+ // our type, and ignore the impl if there was a mismatch.
+ let cause = traits::ObligationCause::dummy();
+ let eq_result = infcx.at(&cause, param_env)
+ .eq(trait_ref.self_ty(), ty);
+ if let Ok(InferOk { value: (), obligations }) = eq_result {
+ // FIXME(eddyb) ignoring `obligations` might cause false positives.
+ drop(obligations);
+
+ let may_apply = infcx.predicate_may_hold(&traits::Obligation::new(
+ cause.clone(),
+ param_env,
+ trait_ref.to_predicate(),
+ ));
+ if !may_apply {
+ return
+ }
+ self.cx.generated_synthetics.borrow_mut()
+ .insert((def_id, trait_def_id));
+ let trait_ = hir::TraitRef {
+ path: get_path_for_type(infcx.tcx,
+ trait_def_id,
+ hir::def::Def::Trait),
+ ref_id: ast::DUMMY_NODE_ID,
+ };
+ let provided_trait_methods =
+ infcx.tcx.provided_trait_methods(trait_def_id)
+ .into_iter()
+ .map(|meth| meth.ident.to_string())
+ .collect();
+
+ let ty = self.cx.get_real_ty(def_id, def_ctor, &real_name, generics);
+ let predicates = infcx.tcx.predicates_of(impl_def_id);
+
+ impls.push(Item {
+ source: infcx.tcx.def_span(impl_def_id).clean(self.cx),
+ name: None,
+ attrs: Default::default(),
+ visibility: None,
+ def_id: self.cx.next_def_id(impl_def_id.krate),
+ stability: None,
+ deprecation: None,
+ inner: ImplItem(Impl {
+ unsafety: hir::Unsafety::Normal,
+ generics: (t_generics, &predicates).clean(self.cx),
+ provided_trait_methods,
+ trait_: Some(trait_.clean(self.cx)),
+ for_: ty.clean(self.cx),
+ items: infcx.tcx.associated_items(impl_def_id)
+ .collect::<Vec<_>>()
+ .clean(self.cx),
+ polarity: None,
+ synthetic: false,
+ blanket_impl: Some(infcx.tcx.type_of(impl_def_id)
+ .clean(self.cx)),
+ }),
+ });
+ }
+ });
+ });
+ }
+ }
+ impls
+ }
+}
--- /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 core::DocContext;
+
+use super::*;
+
+pub fn get_def_from_def_id<F>(cx: &DocContext,
+ def_id: DefId,
+ callback: &F,
+) -> Vec<Item>
+where F: Fn(& dyn Fn(DefId) -> Def) -> Vec<Item> {
+ let ty = cx.tcx.type_of(def_id);
+
+ match ty.sty {
+ ty::TyAdt(adt, _) => callback(&match adt.adt_kind() {
+ AdtKind::Struct => Def::Struct,
+ AdtKind::Enum => Def::Enum,
+ AdtKind::Union => Def::Union,
+ }),
+ ty::TyInt(_) |
+ ty::TyUint(_) |
+ ty::TyFloat(_) |
+ ty::TyStr |
+ ty::TyBool |
+ ty::TyChar => callback(&move |_: DefId| {
+ match ty.sty {
+ ty::TyInt(x) => Def::PrimTy(hir::TyInt(x)),
+ ty::TyUint(x) => Def::PrimTy(hir::TyUint(x)),
+ ty::TyFloat(x) => Def::PrimTy(hir::TyFloat(x)),
+ ty::TyStr => Def::PrimTy(hir::TyStr),
+ ty::TyBool => Def::PrimTy(hir::TyBool),
+ ty::TyChar => Def::PrimTy(hir::TyChar),
+ _ => unreachable!(),
+ }
+ }),
+ _ => {
+ debug!("Unexpected type {:?}", def_id);
+ Vec::new()
+ }
+ }
+}
+
+pub fn get_def_from_node_id<F>(cx: &DocContext,
+ id: ast::NodeId,
+ name: String,
+ callback: &F,
+) -> Vec<Item>
+where F: Fn(& dyn Fn(DefId) -> Def, String) -> Vec<Item> {
+ let item = &cx.tcx.hir.expect_item(id).node;
+
+ callback(&match *item {
+ hir::ItemKind::Struct(_, _) => Def::Struct,
+ hir::ItemKind::Union(_, _) => Def::Union,
+ hir::ItemKind::Enum(_, _) => Def::Enum,
+ _ => panic!("Unexpected type {:?} {:?}", item, id),
+ }, name)
+}
use rustc::hir;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
-use rustc::middle::cstore::LoadedMacro;
+use rustc_metadata::cstore::LoadedMacro;
use rustc::ty;
use rustc::util::nodemap::FxHashSet;
use core::{DocContext, DocAccessLevels};
use doctree;
-use clean::{self, GetDefId, ToSource, get_auto_traits_with_def_id};
+use clean::{
+ self,
+ GetDefId,
+ ToSource,
+ get_auto_traits_with_def_id,
+ get_blanket_impls_with_def_id,
+};
use super::Clean;
}
});
let fqn = if let clean::TypeKind::Macro = kind {
- vec![crate_name, relative.last().unwrap()]
+ vec![crate_name, relative.last().expect("relative was empty")]
} else {
once(crate_name).chain(relative).collect()
};
if auto_traits {
let auto_impls = get_auto_traits_with_def_id(cx, did);
- let mut renderinfo = cx.renderinfo.borrow_mut();
- let new_impls: Vec<clean::Item> = auto_impls.into_iter()
- .filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
+ {
+ let mut renderinfo = cx.renderinfo.borrow_mut();
+ let new_impls: Vec<clean::Item> = auto_impls.into_iter()
+ .filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
- impls.extend(new_impls);
+ impls.extend(new_impls);
+ }
+ impls.extend(get_blanket_impls_with_def_id(cx, did));
}
// If this is the first time we've inlined something from another crate, then
build_impl(cx, def_id, &mut impls);
let auto_impls = get_auto_traits_with_def_id(cx, def_id);
+ let blanket_impls = get_blanket_impls_with_def_id(cx, def_id);
let mut renderinfo = cx.renderinfo.borrow_mut();
let new_impls: Vec<clean::Item> = auto_impls.into_iter()
- .filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
+ .chain(blanket_impls.into_iter())
+ .filter(|i| renderinfo.inlined.insert(i.def_id))
+ .collect();
impls.extend(new_impls);
}
pub use self::Visibility::{Public, Inherited};
use rustc_target::spec::abi::Abi;
-use syntax;
-use syntax::ast::{self, AttrStyle, Name, NodeId, Ident};
+use syntax::ast::{self, AttrStyle, Ident};
use syntax::attr;
use syntax::codemap::{dummy_spanned, Spanned};
-use syntax::feature_gate::UnstableFeatures;
use syntax::ptr::P;
use syntax::symbol::keywords::{self, Keyword};
-use syntax::symbol::{Symbol, InternedString};
+use syntax::symbol::InternedString;
use syntax_pos::{self, DUMMY_SP, Pos, FileName};
use rustc::mir::interpret::ConstValue;
use rustc::mir::interpret::GlobalId;
use rustc::hir::{self, GenericArg, HirVec};
use rustc::hir::def::{self, Def, CtorKind};
-use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
-use rustc::hir::def_id::DefIndexAddressSpace;
-use rustc::hir::map::Node;
+use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::ty::subst::Substs;
use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind};
use rustc::middle::stability;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_typeck::hir_ty_to_ty;
use rustc::infer::region_constraints::{RegionConstraintData, Constraint};
-use rustc::lint as lint;
use std::collections::hash_map::Entry;
use std::fmt;
use std::cell::RefCell;
use std::sync::Arc;
use std::u32;
-use std::ops::Range;
use core::{self, DocContext};
use doctree;
use visit_ast;
use html::render::{cache, ExternalLocation};
use html::item_type::ItemType;
-use html::markdown::markdown_links;
pub mod inline;
pub mod cfg;
mod simplify;
mod auto_trait;
+mod blanket_impl;
+pub mod def_ctor;
use self::cfg::Cfg;
use self::auto_trait::AutoTraitFinder;
+use self::blanket_impl::BlanketImplFinder;
-thread_local!(static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = RefCell::new(FxHashMap()));
+thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> =
+ RefCell::new(FxHashMap()));
const FN_OUTPUT_NAME: &'static str = "Output";
pub masked_crates: FxHashSet<CrateNum>,
}
-impl<'a, 'tcx, 'rcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> {
+impl<'a, 'tcx, 'rcx, 'cstore> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> {
fn clean(&self, cx: &DocContext) -> Crate {
use ::visit_lib::LibEmbargoVisitor;
impl Clean<Item> for doctree::Module {
fn clean(&self, cx: &DocContext) -> Item {
let name = if self.name.is_some() {
- self.name.unwrap().clean(cx)
+ self.name.expect("No name provided").clean(cx)
} else {
"".to_string()
};
// maintain a stack of mod ids, for doc comment path resolution
// but we also need to resolve the module's own docs based on whether its docs were written
// inside or outside the module, so check for that
- let attrs = if self.attrs.iter()
- .filter(|a| a.check_name("doc"))
- .next()
- .map_or(true, |a| a.style == AttrStyle::Inner) {
- // inner doc comment, use the module's own scope for resolution
- if self.id != NodeId::new(0) {
- *cx.current_item_name.borrow_mut() = Some(cx.tcx.hir.name(self.id));
- } else {
- *cx.current_item_name.borrow_mut() = None;
- }
- cx.mod_ids.borrow_mut().push(self.id);
- self.attrs.clean(cx)
- } else {
- // outer doc comment, use its parent's scope
- match cx.mod_ids.borrow().last() {
- Some(parent) if *parent != NodeId::new(0) => {
- *cx.current_item_name.borrow_mut() = Some(cx.tcx.hir.name(*parent));
- }
- _ => {
- *cx.current_item_name.borrow_mut() = None;
- }
- }
- let attrs = self.attrs.clean(cx);
- cx.mod_ids.borrow_mut().push(self.id);
- attrs
- };
+ let attrs = self.attrs.clean(cx);
let mut items: Vec<Item> = vec![];
items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
items.extend(self.macros.iter().map(|x| x.clean(cx)));
- cx.mod_ids.borrow_mut().pop();
-
// determine if we should display the inner contents or
// the outer `mod` item for the source code.
let whence = {
pub span: Option<syntax_pos::Span>,
/// map from Rust paths to resolved defs and potential URL fragments
pub links: Vec<(String, Option<DefId>, Option<String>)>,
+ pub inner_docs: bool,
}
impl Attributes {
}
}
+ let inner_docs = attrs.iter()
+ .filter(|a| a.check_name("doc"))
+ .next()
+ .map_or(true, |a| a.style == AttrStyle::Inner);
+
Attributes {
doc_strings,
other_attrs,
cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
span: sp,
links: vec![],
+ inner_docs,
}
}
}
}
-/// Given a def, returns its name and disambiguator
-/// for a value namespace
-///
-/// Returns None for things which cannot be ambiguous since
-/// they exist in both namespaces (structs and modules)
-fn value_ns_kind(def: Def, path_str: &str) -> Option<(&'static str, String)> {
- match def {
- // structs, variants, and mods exist in both namespaces. skip them
- Def::StructCtor(..) | Def::Mod(..) | Def::Variant(..) | Def::VariantCtor(..) => None,
- Def::Fn(..)
- => Some(("function", format!("{}()", path_str))),
- Def::Method(..)
- => Some(("method", format!("{}()", path_str))),
- Def::Const(..)
- => Some(("const", format!("const@{}", path_str))),
- Def::Static(..)
- => Some(("static", format!("static@{}", path_str))),
- _ => Some(("value", format!("value@{}", path_str))),
- }
-}
-
-/// Given a def, returns its name, the article to be used, and a disambiguator
-/// for the type namespace
-fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String) {
- let (kind, article) = match def {
- // we can still have non-tuple structs
- Def::Struct(..) => ("struct", "a"),
- Def::Enum(..) => ("enum", "an"),
- Def::Trait(..) => ("trait", "a"),
- Def::Union(..) => ("union", "a"),
- _ => ("type", "a"),
- };
- (kind, article, format!("{}@{}", kind, path_str))
-}
-
-fn span_of_attrs(attrs: &Attributes) -> syntax_pos::Span {
- if attrs.doc_strings.is_empty() {
- return DUMMY_SP;
- }
- let start = attrs.doc_strings[0].span();
- let end = attrs.doc_strings.last().unwrap().span();
- start.to(end)
-}
-
-fn ambiguity_error(cx: &DocContext, attrs: &Attributes,
- path_str: &str,
- article1: &str, kind1: &str, disambig1: &str,
- article2: &str, kind2: &str, disambig2: &str) {
- let sp = span_of_attrs(attrs);
- cx.sess()
- .struct_span_warn(sp,
- &format!("`{}` is both {} {} and {} {}",
- path_str, article1, kind1,
- article2, kind2))
- .help(&format!("try `{}` if you want to select the {}, \
- or `{}` if you want to \
- select the {}",
- disambig1, kind1, disambig2,
- kind2))
- .emit();
-}
-
-/// Given an enum variant's def, return the def of its enum and the associated fragment
-fn handle_variant(cx: &DocContext, def: Def) -> Result<(Def, Option<String>), ()> {
- use rustc::ty::DefIdTree;
-
- let parent = if let Some(parent) = cx.tcx.parent(def.def_id()) {
- parent
- } else {
- return Err(())
- };
- let parent_def = Def::Enum(parent);
- let variant = cx.tcx.expect_variant_def(def);
- Ok((parent_def, Some(format!("{}.v", variant.name))))
-}
-
-const PRIMITIVES: &[(&str, Def)] = &[
- ("u8", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U8))),
- ("u16", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U16))),
- ("u32", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U32))),
- ("u64", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U64))),
- ("u128", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U128))),
- ("usize", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::Usize))),
- ("i8", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I8))),
- ("i16", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I16))),
- ("i32", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I32))),
- ("i64", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I64))),
- ("i128", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I128))),
- ("isize", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::Isize))),
- ("f32", Def::PrimTy(hir::PrimTy::TyFloat(syntax::ast::FloatTy::F32))),
- ("f64", Def::PrimTy(hir::PrimTy::TyFloat(syntax::ast::FloatTy::F64))),
- ("str", Def::PrimTy(hir::PrimTy::TyStr)),
- ("bool", Def::PrimTy(hir::PrimTy::TyBool)),
- ("char", Def::PrimTy(hir::PrimTy::TyChar)),
-];
-
-fn is_primitive(path_str: &str, is_val: bool) -> Option<Def> {
- if is_val {
- None
- } else {
- PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1)
- }
-}
-
-/// Resolve a given string as a path, along with whether or not it is
-/// in the value namespace. Also returns an optional URL fragment in the case
-/// of variants and methods
-fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<(Def, Option<String>), ()> {
- // In case we're in a module, try to resolve the relative
- // path
- if let Some(id) = cx.mod_ids.borrow().last() {
- let result = cx.resolver.borrow_mut()
- .with_scope(*id,
- |resolver| {
- resolver.resolve_str_path_error(DUMMY_SP,
- &path_str, is_val)
- });
-
- if let Ok(result) = result {
- // In case this is a trait item, skip the
- // early return and try looking for the trait
- let value = match result.def {
- Def::Method(_) | Def::AssociatedConst(_) => true,
- Def::AssociatedTy(_) => false,
- Def::Variant(_) => return handle_variant(cx, result.def),
- // not a trait item, just return what we found
- _ => return Ok((result.def, None))
- };
-
- if value != is_val {
- return Err(())
- }
- } else if let Some(prim) = is_primitive(path_str, is_val) {
- return Ok((prim, Some(path_str.to_owned())))
- } else {
- // If resolution failed, it may still be a method
- // because methods are not handled by the resolver
- // If so, bail when we're not looking for a value
- if !is_val {
- return Err(())
- }
- }
-
- // Try looking for methods and associated items
- let mut split = path_str.rsplitn(2, "::");
- let item_name = if let Some(first) = split.next() {
- first
- } else {
- return Err(())
- };
-
- let mut path = if let Some(second) = split.next() {
- second.to_owned()
- } else {
- return Err(())
- };
-
- if path == "self" || path == "Self" {
- if let Some(name) = *cx.current_item_name.borrow() {
- path = name.to_string();
- }
- }
-
- let ty = cx.resolver.borrow_mut()
- .with_scope(*id,
- |resolver| {
- resolver.resolve_str_path_error(DUMMY_SP, &path, false)
- })?;
- match ty.def {
- Def::Struct(did) | Def::Union(did) | Def::Enum(did) | Def::TyAlias(did) => {
- let item = cx.tcx.inherent_impls(did).iter()
- .flat_map(|imp| cx.tcx.associated_items(*imp))
- .find(|item| item.ident.name == item_name);
- if let Some(item) = item {
- let out = match item.kind {
- ty::AssociatedKind::Method if is_val => "method",
- ty::AssociatedKind::Const if is_val => "associatedconstant",
- _ => return Err(())
- };
- Ok((ty.def, Some(format!("{}.{}", out, item_name))))
- } else {
- let is_enum = match ty.def {
- Def::Enum(_) => true,
- _ => false,
- };
- let elem = if is_enum {
- cx.tcx.adt_def(did).all_fields().find(|item| item.ident.name == item_name)
- } else {
- cx.tcx.adt_def(did)
- .non_enum_variant()
- .fields
- .iter()
- .find(|item| item.ident.name == item_name)
- };
- if let Some(item) = elem {
- Ok((ty.def,
- Some(format!("{}.{}",
- if is_enum { "variant" } else { "structfield" },
- item.ident))))
- } else {
- Err(())
- }
- }
- }
- Def::Trait(did) => {
- let item = cx.tcx.associated_item_def_ids(did).iter()
- .map(|item| cx.tcx.associated_item(*item))
- .find(|item| item.ident.name == item_name);
- if let Some(item) = item {
- let kind = match item.kind {
- ty::AssociatedKind::Const if is_val => "associatedconstant",
- ty::AssociatedKind::Type if !is_val => "associatedtype",
- ty::AssociatedKind::Method if is_val => {
- if item.defaultness.has_value() {
- "method"
- } else {
- "tymethod"
- }
- }
- _ => return Err(())
- };
-
- Ok((ty.def, Some(format!("{}.{}", kind, item_name))))
- } else {
- Err(())
- }
- }
- _ => Err(())
- }
- } else {
- Err(())
- }
-}
-
-/// Resolve a string as a macro
-fn macro_resolve(cx: &DocContext, path_str: &str) -> Option<Def> {
- use syntax::ext::base::{MacroKind, SyntaxExtension};
- use syntax::ext::hygiene::Mark;
- let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
- let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
- let mut resolver = cx.resolver.borrow_mut();
- let mark = Mark::root();
- let res = resolver
- .resolve_macro_to_def_inner(mark, &path, MacroKind::Bang, false);
- if let Ok(def) = res {
- if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) {
- return Some(def);
- }
- }
- if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) {
- return Some(*def);
- }
- None
-}
-
-#[derive(Debug)]
-enum PathKind {
- /// can be either value or type, not a macro
- Unknown,
- /// macro
- Macro,
- /// values, functions, consts, statics, everything in the value namespace
- Value,
- /// types, traits, everything in the type namespace
- Type,
-}
-
-fn resolution_failure(
- cx: &DocContext,
- attrs: &Attributes,
- path_str: &str,
- dox: &str,
- link_range: Option<Range<usize>>,
-) {
- let sp = span_of_attrs(attrs);
- let msg = format!("`[{}]` cannot be resolved, ignoring it...", path_str);
-
- let code_dox = sp.to_src(cx);
-
- let doc_comment_padding = 3;
- let mut diag = if let Some(link_range) = link_range {
- // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
- // ^ ~~~~~~
- // | link_range
- // last_new_line_offset
-
- let mut diag;
- if dox.lines().count() == code_dox.lines().count() {
- let line_offset = dox[..link_range.start].lines().count();
- // The span starts in the `///`, so we don't have to account for the leading whitespace
- let code_dox_len = if line_offset <= 1 {
- doc_comment_padding
- } else {
- // The first `///`
- doc_comment_padding +
- // Each subsequent leading whitespace and `///`
- code_dox.lines().skip(1).take(line_offset - 1).fold(0, |sum, line| {
- sum + doc_comment_padding + line.len() - line.trim().len()
- })
- };
-
- // Extract the specific span
- let sp = sp.from_inner_byte_pos(
- link_range.start + code_dox_len,
- link_range.end + code_dox_len,
- );
-
- diag = cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
- NodeId::new(0),
- sp,
- &msg);
- diag.span_label(sp, "cannot be resolved, ignoring");
- } else {
- diag = cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
- NodeId::new(0),
- sp,
- &msg);
-
- let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
- let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
-
- // Print the line containing the `link_range` and manually mark it with '^'s
- diag.note(&format!(
- "the link appears in this line:\n\n{line}\n\
- {indicator: <before$}{indicator:^<found$}",
- line=line,
- indicator="",
- before=link_range.start - last_new_line_offset,
- found=link_range.len(),
- ));
- }
- diag
- } else {
- cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
- NodeId::new(0),
- sp,
- &msg)
- };
- diag.help("to escape `[` and `]` characters, just add '\\' before them like \
- `\\[` or `\\]`");
- diag.emit();
-}
-
impl Clean<Attributes> for [ast::Attribute] {
fn clean(&self, cx: &DocContext) -> Attributes {
- let mut attrs = Attributes::from_ast(cx.sess().diagnostic(), self);
-
- if UnstableFeatures::from_environment().is_nightly_build() {
- let dox = attrs.collapsed_doc_value().unwrap_or_else(String::new);
- for (ori_link, link_range) in markdown_links(&dox) {
- // bail early for real links
- if ori_link.contains('/') {
- continue;
- }
- let link = ori_link.replace("`", "");
- let (def, fragment) = {
- let mut kind = PathKind::Unknown;
- let path_str = if let Some(prefix) =
- ["struct@", "enum@", "type@",
- "trait@", "union@"].iter()
- .find(|p| link.starts_with(**p)) {
- kind = PathKind::Type;
- link.trim_left_matches(prefix)
- } else if let Some(prefix) =
- ["const@", "static@",
- "value@", "function@", "mod@",
- "fn@", "module@", "method@"]
- .iter().find(|p| link.starts_with(**p)) {
- kind = PathKind::Value;
- link.trim_left_matches(prefix)
- } else if link.ends_with("()") {
- kind = PathKind::Value;
- link.trim_right_matches("()")
- } else if link.starts_with("macro@") {
- kind = PathKind::Macro;
- link.trim_left_matches("macro@")
- } else if link.ends_with('!') {
- kind = PathKind::Macro;
- link.trim_right_matches('!')
- } else {
- &link[..]
- }.trim();
-
- if path_str.contains(|ch: char| !(ch.is_alphanumeric() ||
- ch == ':' || ch == '_')) {
- continue;
- }
-
- match kind {
- PathKind::Value => {
- if let Ok(def) = resolve(cx, path_str, true) {
- def
- } else {
- resolution_failure(cx, &attrs, path_str, &dox, link_range);
- // this could just be a normal link or a broken link
- // we could potentially check if something is
- // "intra-doc-link-like" and warn in that case
- continue;
- }
- }
- PathKind::Type => {
- if let Ok(def) = resolve(cx, path_str, false) {
- def
- } else {
- resolution_failure(cx, &attrs, path_str, &dox, link_range);
- // this could just be a normal link
- continue;
- }
- }
- PathKind::Unknown => {
- // try everything!
- if let Some(macro_def) = macro_resolve(cx, path_str) {
- if let Ok(type_def) = resolve(cx, path_str, false) {
- let (type_kind, article, type_disambig)
- = type_ns_kind(type_def.0, path_str);
- ambiguity_error(cx, &attrs, path_str,
- article, type_kind, &type_disambig,
- "a", "macro", &format!("macro@{}", path_str));
- continue;
- } else if let Ok(value_def) = resolve(cx, path_str, true) {
- let (value_kind, value_disambig)
- = value_ns_kind(value_def.0, path_str)
- .expect("struct and mod cases should have been \
- caught in previous branch");
- ambiguity_error(cx, &attrs, path_str,
- "a", value_kind, &value_disambig,
- "a", "macro", &format!("macro@{}", path_str));
- }
- (macro_def, None)
- } else if let Ok(type_def) = resolve(cx, path_str, false) {
- // It is imperative we search for not-a-value first
- // Otherwise we will find struct ctors for when we are looking
- // for structs, and the link won't work.
- // if there is something in both namespaces
- if let Ok(value_def) = resolve(cx, path_str, true) {
- let kind = value_ns_kind(value_def.0, path_str);
- if let Some((value_kind, value_disambig)) = kind {
- let (type_kind, article, type_disambig)
- = type_ns_kind(type_def.0, path_str);
- ambiguity_error(cx, &attrs, path_str,
- article, type_kind, &type_disambig,
- "a", value_kind, &value_disambig);
- continue;
- }
- }
- type_def
- } else if let Ok(value_def) = resolve(cx, path_str, true) {
- value_def
- } else {
- resolution_failure(cx, &attrs, path_str, &dox, link_range);
- // this could just be a normal link
- continue;
- }
- }
- PathKind::Macro => {
- if let Some(def) = macro_resolve(cx, path_str) {
- (def, None)
- } else {
- resolution_failure(cx, &attrs, path_str, &dox, link_range);
- continue
- }
- }
- }
- };
-
- if let Def::PrimTy(_) = def {
- attrs.links.push((ori_link, None, fragment));
- } else {
- let id = register_def(cx, def);
- attrs.links.push((ori_link, Some(id), fragment));
- }
- }
-
- cx.sess().abort_if_errors();
- }
-
- attrs
+ Attributes::from_ast(cx.sess().diagnostic(), self)
}
}
hir::GenericBound::Outlives(lt) => lt,
_ => panic!(),
});
- let name = bounds.next().unwrap().name.ident();
+ let name = bounds.next().expect("no more bounds").name.ident();
let mut s = format!("{}: {}", self.name.ident(), name);
for bound in bounds {
s.push_str(&format!(" + {}", bound.name.ident()));
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::OutlivesPredicate(ref a, ref b) = *self;
WherePredicate::RegionPredicate {
- lifetime: a.clean(cx).unwrap(),
- bounds: vec![GenericBound::Outlives(b.clean(cx).unwrap())]
+ lifetime: a.clean(cx).expect("failed to clean lifetime"),
+ bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))]
}
}
}
WherePredicate::BoundPredicate {
ty: ty.clean(cx),
- bounds: vec![GenericBound::Outlives(lt.clean(cx).unwrap())]
+ bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))]
}
}
}
hir::GenericBound::Outlives(lt) => lt,
_ => panic!(),
});
- let name = bounds.next().unwrap().name.ident();
+ let name = bounds.next().expect("no more bounds").name.ident();
let mut s = format!("{}: {}", self.name.ident(), name);
for bound in bounds {
s.push_str(&format!(" + {}", bound.name.ident()));
(self.generics.clean(cx), (&self.decl, self.body).clean(cx))
});
- *cx.current_item_name.borrow_mut() = Some(self.name);
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
impl Clean<Item> for doctree::Trait {
fn clean(&self, cx: &DocContext) -> Item {
- *cx.current_item_name.borrow_mut() = Some(self.name);
let attrs = self.attrs.clean(cx);
let is_spotlight = attrs.has_doc_flag("spotlight");
Item {
AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
}
};
- *cx.current_item_name.borrow_mut() = Some(self.ident.name);
Item {
name: Some(self.ident.name.clean(cx)),
attrs: self.attrs.clean(cx),
generics: Generics::default(),
}, true),
};
- *cx.current_item_name.borrow_mut() = Some(self.ident.name);
Item {
name: Some(self.ident.name.clean(cx)),
source: self.span.clean(cx),
};
if let Some(&hir::ItemKind::Ty(ref ty, ref generics)) = alias {
- let provided_params = &path.segments.last().unwrap();
+ let provided_params = &path.segments.last().expect("segments were empty");
let mut ty_substs = FxHashMap();
let mut lt_substs = FxHashMap();
provided_params.with_generic_args(|generic_args| {
segments: segments.into(),
};
Type::QPath {
- name: p.segments.last().unwrap().ident.name.clean(cx),
+ name: p.segments.last().expect("segments were empty").ident.name.clean(cx),
self_type: box qself.clean(cx),
trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
}
ty::TyStr => Primitive(PrimitiveType::Str),
ty::TySlice(ty) => Slice(box ty.clean(cx)),
ty::TyArray(ty, n) => {
- let mut n = cx.tcx.lift(&n).unwrap();
+ let mut n = cx.tcx.lift(&n).expect("array lift failed");
if let ConstValue::Unevaluated(def_id, substs) = n.val {
let param_env = cx.tcx.param_env(def_id);
let cid = GlobalId {
},
ty::TyFnDef(..) |
ty::TyFnPtr(_) => {
- let ty = cx.tcx.lift(self).unwrap();
+ let ty = cx.tcx.lift(self).expect("TyFnPtr lift failed");
let sig = ty.fn_sig(cx.tcx);
BareFunction(box BareFunctionDecl {
unsafety: sig.unsafety(),
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
// by looking up the projections associated with the def_id.
let predicates_of = cx.tcx.predicates_of(def_id);
- let substs = cx.tcx.lift(&substs).unwrap();
+ let substs = cx.tcx.lift(&substs).expect("TyAnon lift failed");
let bounds = predicates_of.instantiate(cx.tcx, substs);
let mut regions = vec![];
let mut has_sized = false;
impl Clean<Item> for hir::StructField {
fn clean(&self, cx: &DocContext) -> Item {
- *cx.current_item_name.borrow_mut() = Some(self.ident.name);
Item {
name: Some(self.ident.name).clean(cx),
attrs: self.attrs.clean(cx),
fn clean(&self, cx: &DocContext) -> Vec<Item> {
let name = self.name.clean(cx);
let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());
+ ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone()));
- *cx.current_item_name.borrow_mut() = Some(self.name);
ret.push(Item {
name: Some(name),
attrs: self.attrs.clean(cx),
fn clean(&self, cx: &DocContext) -> Vec<Item> {
let name = self.name.clean(cx);
let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());
+ ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone()));
- *cx.current_item_name.borrow_mut() = Some(self.name);
ret.push(Item {
name: Some(name),
attrs: self.attrs.clean(cx),
fn clean(&self, cx: &DocContext) -> Vec<Item> {
let name = self.name.clean(cx);
let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());
+ ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone()));
- *cx.current_item_name.borrow_mut() = Some(self.name);
ret.push(Item {
name: Some(name),
attrs: self.attrs.clean(cx),
impl Clean<Item> for doctree::Variant {
fn clean(&self, cx: &DocContext) -> Item {
- *cx.current_item_name.borrow_mut() = Some(self.name);
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
impl Path {
pub fn last_name(&self) -> &str {
- self.segments.last().unwrap().name.as_str()
+ self.segments.last().expect("segments were empty").name.as_str()
}
}
impl Clean<Item> for doctree::Typedef {
fn clean(&self, cx: &DocContext) -> Item {
- *cx.current_item_name.borrow_mut() = Some(self.name);
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
impl Clean<Item> for doctree::Static {
fn clean(&self, cx: &DocContext) -> Item {
debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
- *cx.current_item_name.borrow_mut() = Some(self.name);
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
impl Clean<Item> for doctree::Constant {
fn clean(&self, cx: &DocContext) -> Item {
- *cx.current_item_name.borrow_mut() = Some(self.name);
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
finder.get_with_def_id(id)
}
-fn get_name_if_possible(cx: &DocContext, node: NodeId) -> Option<Name> {
- match cx.tcx.hir.get(node) {
- Node::NodeItem(_) |
- Node::NodeForeignItem(_) |
- Node::NodeImplItem(_) |
- Node::NodeTraitItem(_) |
- Node::NodeVariant(_) |
- Node::NodeField(_) |
- Node::NodeLifetime(_) |
- Node::NodeGenericParam(_) |
- Node::NodeBinding(&hir::Pat { node: hir::PatKind::Binding(_,_,_,_), .. }) |
- Node::NodeStructCtor(_) => {}
- _ => return None,
- }
- Some(cx.tcx.hir.name(node))
+pub fn get_blanket_impls_with_node_id(cx: &DocContext, id: ast::NodeId, name: String) -> Vec<Item> {
+ let finder = BlanketImplFinder::new(cx);
+ finder.get_with_node_id(id, name)
+}
+
+pub fn get_blanket_impls_with_def_id(cx: &DocContext, id: DefId) -> Vec<Item> {
+ let finder = BlanketImplFinder::new(cx);
+
+ finder.get_with_def_id(id)
}
impl Clean<Vec<Item>> for doctree::Impl {
.collect()
}).unwrap_or(FxHashSet());
- *cx.current_item_name.borrow_mut() = get_name_if_possible(cx, self.for_.id);
ret.push(Item {
name: None,
attrs: self.attrs.clean(cx),
impl Clean<Item> for doctree::ExternCrate {
fn clean(&self, cx: &DocContext) -> Item {
- *cx.current_item_name.borrow_mut() = Some(self.name);
Item {
name: None,
attrs: self.attrs.clean(cx),
Import::Simple(name.clean(cx), resolve_use_source(cx, path))
};
- *cx.current_item_name.borrow_mut() = Some(self.name);
vec![Item {
name: None,
attrs: self.attrs.clean(cx),
}
};
- *cx.current_item_name.borrow_mut() = Some(self.name);
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
// Utilities
-trait ToSource {
+pub trait ToSource {
fn to_src(&self, cx: &DocContext) -> String;
}
},
_ => {
let mut s = String::new();
- ::rustc::mir::fmt_const_val(&mut s, n).unwrap();
+ ::rustc::mir::fmt_const_val(&mut s, n).expect("fmt_const_val failed");
// array lengths are obviously usize
if s.ends_with("usize") {
let n = s.len() - "usize".len();
ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
}
-fn register_def(cx: &DocContext, def: Def) -> DefId {
+pub fn register_def(cx: &DocContext, def: Def) -> DefId {
debug!("register_def({:?})", def);
let (did, kind) = match def {
Def::TyForeign(i) => (i, TypeKind::Foreign),
Def::Const(i) => (i, TypeKind::Const),
Def::Static(i, _) => (i, TypeKind::Static),
- Def::Variant(i) => (cx.tcx.parent_def_id(i).unwrap(), TypeKind::Enum),
+ Def::Variant(i) => (cx.tcx.parent_def_id(i).expect("cannot get parent def id"),
+ TypeKind::Enum),
Def::Macro(i, _) => (i, TypeKind::Macro),
Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
Def::SelfTy(_, Some(impl_def_id)) => {
impl Clean<Item> for doctree::Macro {
fn clean(&self, cx: &DocContext) -> Item {
let name = self.name.clean(cx);
- *cx.current_item_name.borrow_mut() = None;
Item {
name: Some(name.clone()),
attrs: self.attrs.clean(cx),
}
}
-fn get_path_for_type<F>(tcx: TyCtxt, def_id: DefId, def_ctor: F) -> hir::Path
+pub fn get_path_for_type<F>(tcx: TyCtxt, def_id: DefId, def_ctor: F) -> hir::Path
where F: Fn(DefId) -> Def {
struct AbsolutePathBuffer {
names: Vec<String>,
if !trait_is_same_or_supertrait(cx, did, trait_did) {
return false
}
- let last = path.segments.last_mut().unwrap();
+ let last = path.segments.last_mut().expect("segments were empty");
match last.args {
PP::AngleBracketed { ref mut bindings, .. } => {
bindings.push(clean::TypeBinding {
use rustc_lint;
use rustc_driver::{self, driver, target_features, abort_on_err};
use rustc::session::{self, config};
-use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
+use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CrateNum, LOCAL_CRATE};
use rustc::hir::def::Def;
+use rustc::hir::{self, HirVec};
use rustc::middle::cstore::CrateStore;
use rustc::middle::privacy::AccessLevels;
use rustc::ty::{self, TyCtxt, AllArenas};
use rustc_metadata::cstore::CStore;
use rustc_target::spec::TargetTriple;
-use syntax::ast::{Name, NodeId};
+use syntax::ast::{self, Ident};
use syntax::codemap;
use syntax::edition::Edition;
use syntax::feature_gate::UnstableFeatures;
use syntax::json::JsonEmitter;
+use syntax::ptr::P;
+use syntax::symbol::keywords;
+use syntax_pos::DUMMY_SP;
use errors;
use errors::emitter::{Emitter, EmitterWriter};
use visit_ast::RustdocVisitor;
use clean;
-use clean::Clean;
+use clean::{get_path_for_type, Clean, MAX_DEF_ID, AttributesExt};
use html::render::RenderInfo;
+use passes;
-pub use rustc::session::config::{Input, CodegenOptions};
+pub use rustc::session::config::{Input, Options, CodegenOptions};
pub use rustc::session::search_paths::SearchPaths;
pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;
-pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
+pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
- pub resolver: &'a RefCell<resolve::Resolver<'rcx>>,
+ pub resolver: &'a RefCell<resolve::Resolver<'rcx, 'cstore>>,
/// The stack of module NodeIds up till this point
- pub mod_ids: RefCell<Vec<NodeId>>,
pub crate_name: Option<String>,
- pub cstore: Rc<dyn CrateStore>,
+ pub cstore: Rc<CStore>,
pub populated_all_crate_impls: Cell<bool>,
// Note that external items for which `doc(hidden)` applies to are shown as
// non-reachable while local items aren't. This is because we're reusing
pub all_fake_def_ids: RefCell<FxHashSet<DefId>>,
/// Maps (type_id, trait_id) -> auto trait impl
pub generated_synthetics: RefCell<FxHashSet<(DefId, DefId)>>,
- pub current_item_name: RefCell<Option<Name>>,
pub all_traits: Vec<DefId>,
}
-impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> {
+impl<'a, 'tcx, 'rcx, 'cstore> DocContext<'a, 'tcx, 'rcx, 'cstore> {
pub fn sess(&self) -> &session::Session {
&self.tcx.sess
}
*self.lt_substs.borrow_mut() = old_lts;
r
}
+
+ // This is an ugly hack, but it's the simplest way to handle synthetic impls without greatly
+ // refactoring either librustdoc or librustc. In particular, allowing new DefIds to be
+ // registered after the AST is constructed would require storing the defid mapping in a
+ // RefCell, decreasing the performance for normal compilation for very little gain.
+ //
+ // Instead, we construct 'fake' def ids, which start immediately after the last DefId in
+ // DefIndexAddressSpace::Low. In the Debug impl for clean::Item, we explicitly check for fake
+ // def ids, as we'll end up with a panic if we use the DefId Debug impl for fake DefIds
+ pub fn next_def_id(&self, crate_num: CrateNum) -> DefId {
+ let start_def_id = {
+ let next_id = if crate_num == LOCAL_CRATE {
+ self.tcx
+ .hir
+ .definitions()
+ .def_path_table()
+ .next_id(DefIndexAddressSpace::Low)
+ } else {
+ self.cstore
+ .def_path_table(crate_num)
+ .next_id(DefIndexAddressSpace::Low)
+ };
+
+ DefId {
+ krate: crate_num,
+ index: next_id,
+ }
+ };
+
+ let mut fake_ids = self.fake_def_ids.borrow_mut();
+
+ let def_id = fake_ids.entry(crate_num).or_insert(start_def_id).clone();
+ fake_ids.insert(
+ crate_num,
+ DefId {
+ krate: crate_num,
+ index: DefIndex::from_array_index(
+ def_id.index.as_array_index() + 1,
+ def_id.index.address_space(),
+ ),
+ },
+ );
+
+ MAX_DEF_ID.with(|m| {
+ m.borrow_mut()
+ .entry(def_id.krate.clone())
+ .or_insert(start_def_id);
+ });
+
+ self.all_fake_def_ids.borrow_mut().insert(def_id);
+
+ def_id.clone()
+ }
+
+ pub fn get_real_ty<F>(&self,
+ def_id: DefId,
+ def_ctor: &F,
+ real_name: &Option<Ident>,
+ generics: &ty::Generics,
+ ) -> hir::Ty
+ where F: Fn(DefId) -> Def {
+ let path = get_path_for_type(self.tcx, def_id, def_ctor);
+ let mut segments = path.segments.into_vec();
+ let last = segments.pop().expect("segments were empty");
+
+ segments.push(hir::PathSegment::new(
+ real_name.unwrap_or(last.ident),
+ self.generics_to_path_params(generics.clone()),
+ false,
+ ));
+
+ let new_path = hir::Path {
+ span: path.span,
+ def: path.def,
+ segments: HirVec::from_vec(segments),
+ };
+
+ hir::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: hir::TyKind::Path(hir::QPath::Resolved(None, P(new_path))),
+ span: DUMMY_SP,
+ hir_id: hir::DUMMY_HIR_ID,
+ }
+ }
+
+ pub fn generics_to_path_params(&self, generics: ty::Generics) -> hir::GenericArgs {
+ let mut args = vec![];
+
+ for param in generics.params.iter() {
+ match param.kind {
+ ty::GenericParamDefKind::Lifetime => {
+ let name = if param.name == "" {
+ hir::ParamName::Plain(keywords::StaticLifetime.ident())
+ } else {
+ hir::ParamName::Plain(ast::Ident::from_interned_str(param.name))
+ };
+
+ args.push(hir::GenericArg::Lifetime(hir::Lifetime {
+ id: ast::DUMMY_NODE_ID,
+ span: DUMMY_SP,
+ name: hir::LifetimeName::Param(name),
+ }));
+ }
+ ty::GenericParamDefKind::Type {..} => {
+ args.push(hir::GenericArg::Type(self.ty_param_to_ty(param.clone())));
+ }
+ }
+ }
+
+ hir::GenericArgs {
+ args: HirVec::from_vec(args),
+ bindings: HirVec::new(),
+ parenthesized: false,
+ }
+ }
+
+ pub fn ty_param_to_ty(&self, param: ty::GenericParamDef) -> hir::Ty {
+ debug!("ty_param_to_ty({:?}) {:?}", param, param.def_id);
+ hir::Ty {
+ id: ast::DUMMY_NODE_ID,
+ node: hir::TyKind::Path(hir::QPath::Resolved(
+ None,
+ P(hir::Path {
+ span: DUMMY_SP,
+ def: Def::TyParam(param.def_id),
+ segments: HirVec::from_vec(vec![
+ hir::PathSegment::from_ident(Ident::from_interned_str(param.name))
+ ]),
+ }),
+ )),
+ span: DUMMY_SP,
+ hir_id: hir::DUMMY_HIR_ID,
+ }
+ }
}
pub trait DocAccessLevels {
{
// rustdoc doesn't override (or allow to override) anything from this that is relevant here, so
// stick to the defaults
- let sessopts = config::basic_options();
+ let sessopts = Options::default();
let emitter: Box<dyn Emitter + sync::Send> = match error_format {
ErrorOutputType::HumanReadable(color_config) => Box::new(
EmitterWriter::stderr(
error_format: ErrorOutputType,
cmd_lints: Vec<(String, lint::Level)>,
lint_cap: Option<lint::Level>,
- describe_lints: bool) -> (clean::Crate, RenderInfo)
+ describe_lints: bool,
+ mut manual_passes: Vec<String>,
+ mut default_passes: passes::DefaultPassOption)
+ -> (clean::Crate, RenderInfo, Vec<String>)
{
// Parse, resolve, and typecheck the given crate.
let sessopts = config::Options {
maybe_sysroot,
search_paths,
- crate_types: vec![config::CrateTypeRlib],
+ crate_types: vec![config::CrateType::Rlib],
lint_opts: if !allow_warnings {
lints
} else {
error_format,
edition,
describe_lints,
- ..config::basic_options()
+ ..Options::default()
};
driver::spawn_thread_pool(sessopts, move |sessopts| {
let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
ty_substs: Default::default(),
lt_substs: Default::default(),
impl_trait_bounds: Default::default(),
- mod_ids: Default::default(),
send_trait: send_trait,
fake_def_ids: RefCell::new(FxHashMap()),
all_fake_def_ids: RefCell::new(FxHashSet()),
generated_synthetics: RefCell::new(FxHashSet()),
- current_item_name: RefCell::new(None),
all_traits: tcx.all_traits(LOCAL_CRATE).to_vec(),
};
debug!("crate: {:?}", tcx.hir.krate());
- let krate = {
+ let mut krate = {
let mut v = RustdocVisitor::new(&ctxt);
v.visit(tcx.hir.krate());
v.clean(&ctxt)
};
- (krate, ctxt.renderinfo.into_inner())
+ fn report_deprecated_attr(name: &str, diag: &errors::Handler) {
+ let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \
+ considered deprecated", name));
+ msg.warn("please see https://github.com/rust-lang/rust/issues/44136");
+
+ if name == "no_default_passes" {
+ msg.help("you may want to use `#![doc(document_private_items)]`");
+ }
+
+ msg.emit();
+ }
+
+ // Process all of the crate attributes, extracting plugin metadata along
+ // with the passes which we are supposed to run.
+ for attr in krate.module.as_ref().unwrap().attrs.lists("doc") {
+ let diag = ctxt.sess().diagnostic();
+
+ let name = attr.name().map(|s| s.as_str());
+ let name = name.as_ref().map(|s| &s[..]);
+ if attr.is_word() {
+ if name == Some("no_default_passes") {
+ report_deprecated_attr("no_default_passes", diag);
+ if default_passes == passes::DefaultPassOption::Default {
+ default_passes = passes::DefaultPassOption::None;
+ }
+ }
+ } else if let Some(value) = attr.value_str() {
+ let sink = match name {
+ Some("passes") => {
+ report_deprecated_attr("passes = \"...\"", diag);
+ &mut manual_passes
+ },
+ Some("plugins") => {
+ report_deprecated_attr("plugins = \"...\"", diag);
+ eprintln!("WARNING: #![doc(plugins = \"...\")] no longer functions; \
+ see CVE-2018-1000622");
+ continue
+ },
+ _ => continue,
+ };
+ for p in value.as_str().split_whitespace() {
+ sink.push(p.to_string());
+ }
+ }
+
+ if attr.is_word() && name == Some("document_private_items") {
+ if default_passes == passes::DefaultPassOption::Default {
+ default_passes = passes::DefaultPassOption::Private;
+ }
+ }
+ }
+
+ let mut passes: Vec<String> =
+ passes::defaults(default_passes).iter().map(|p| p.to_string()).collect();
+ passes.extend(manual_passes);
+
+ for pass in &passes {
+ // the "unknown pass" error will be reported when late passes are run
+ if let Some(pass) = passes::find_pass(pass).and_then(|p| p.early_fn()) {
+ krate = pass(krate, &ctxt);
+ }
+ }
+
+ ctxt.sess().abort_if_errors();
+
+ (krate, ctxt.renderinfo.into_inner(), passes)
}), &sess)
})
}
use std::path::Path;
use std::str;
use errors;
-use html::markdown::Markdown;
+use syntax::feature_gate::UnstableFeatures;
+use html::markdown::{IdMap, ErrorCodes, Markdown};
+use std::cell::RefCell;
#[derive(Clone)]
pub struct ExternalHtml {
impl ExternalHtml {
pub fn load(in_header: &[String], before_content: &[String], after_content: &[String],
- md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler)
+ md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler,
+ id_map: &mut IdMap)
-> Option<ExternalHtml> {
+ let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
load_external_files(in_header, diag)
.and_then(|ih|
load_external_files(before_content, diag)
)
.and_then(|(ih, bc)|
load_external_files(md_before_content, diag)
- .map(|m_bc| (ih, format!("{}{}", bc, Markdown(&m_bc, &[]))))
+ .map(|m_bc| (ih,
+ format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map), codes))))
)
.and_then(|(ih, bc)|
load_external_files(after_content, diag)
)
.and_then(|(ih, bc, ac)|
load_external_files(md_after_content, diag)
- .map(|m_ac| (ih, bc, format!("{}{}", ac, Markdown(&m_ac, &[]))))
+ .map(|m_ac| (ih, bc,
+ format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map), codes))))
)
.map(|(ih, bc, ac)|
ExternalHtml {
//! This module uses libsyntax's lexer to provide token-based highlighting for
//! the HTML documentation generated by rustdoc.
//!
-//! If you just want to syntax highlighting for a Rust program, then you can use
-//! the `render_inner_with_highlighting` or `render_with_highlighting`
-//! functions. For more advanced use cases (if you want to supply your own css
-//! classes or control how the HTML is generated, or even generate something
-//! other then HTML), then you should implement the `Writer` trait and use a
-//! `Classifier`.
+//! Use the `render_with_highlighting` to highlight some rust code.
use html::escape::Escape;
use syntax_pos::{Span, FileName};
/// Highlights `src`, returning the HTML output.
-pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>,
+pub fn render_with_highlighting(src: &str, class: Option<&str>,
extension: Option<&str>,
tooltip: Option<(&str, &str)>) -> String {
debug!("highlighting: ================\n{}\n==============", src);
class='tooltiptext'>{}</span></div></div>",
class, tooltip).unwrap();
}
- write_header(class, id, &mut out).unwrap();
+ write_header(class, &mut out).unwrap();
let mut classifier = Classifier::new(lexer::StringReader::new(&sess, fm, None), sess.codemap());
if let Err(_) = classifier.write_source(&mut out) {
/// Processes a program (nested in the internal `lexer`), classifying strings of
/// text by highlighting category (`Class`). Calls out to a `Writer` to write
/// each span of text in sequence.
-pub struct Classifier<'a> {
+struct Classifier<'a> {
lexer: lexer::StringReader<'a>,
codemap: &'a CodeMap,
/// How a span of text is classified. Mostly corresponds to token kinds.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum Class {
+enum Class {
None,
Comment,
DocComment,
/// The classifier will call into the `Writer` implementation as it finds spans
/// of text to highlight. Exactly how that text should be highlighted is up to
/// the implementation.
-pub trait Writer {
+trait Writer {
/// Called when we start processing a span of text that should be highlighted.
/// The `Class` argument specifies how it should be highlighted.
fn enter_span(&mut self, _: Class) -> io::Result<()>;
/// Called at the end of a span of highlighted text.
fn exit_span(&mut self) -> io::Result<()>;
- /// Called for a span of text, usually, but not always, a single token. If
- /// the string of text (`T`) does correspond to a token, then the token will
- /// also be passed. If the text should be highlighted differently from the
- /// surrounding text, then the `Class` argument will be a value other than
- /// `None`.
+ /// Called for a span of text. If the text should be highlighted differently from the
+ /// surrounding text, then the `Class` argument will be a value other than `None`.
+ ///
/// The following sequences of callbacks are equivalent:
/// ```plain
/// enter_span(Foo), string("text", None), exit_span()
/// more flexible.
fn string<T: Display>(&mut self,
text: T,
- klass: Class,
- tok: Option<&TokenAndSpan>)
+ klass: Class)
-> io::Result<()>;
}
impl<U: Write> Writer for U {
fn string<T: Display>(&mut self,
text: T,
- klass: Class,
- _tas: Option<&TokenAndSpan>)
+ klass: Class)
-> io::Result<()> {
match klass {
Class::None => write!(self, "{}", text),
}
impl<'a> Classifier<'a> {
- pub fn new(lexer: lexer::StringReader<'a>, codemap: &'a CodeMap) -> Classifier<'a> {
+ fn new(lexer: lexer::StringReader<'a>, codemap: &'a CodeMap) -> Classifier<'a> {
Classifier {
lexer,
codemap,
/// is used. All source code emission is done as slices from the source map,
/// not from the tokens themselves, in order to stay true to the original
/// source.
- pub fn write_source<W: Writer>(&mut self,
+ fn write_source<W: Writer>(&mut self,
out: &mut W)
-> io::Result<()> {
loop {
-> io::Result<()> {
let klass = match tas.tok {
token::Shebang(s) => {
- out.string(Escape(&s.as_str()), Class::None, Some(&tas))?;
+ out.string(Escape(&s.as_str()), Class::None)?;
return Ok(());
},
self.in_attribute = true;
out.enter_span(Class::Attribute)?;
}
- out.string("#", Class::None, None)?;
- out.string("!", Class::None, None)?;
+ out.string("#", Class::None)?;
+ out.string("!", Class::None)?;
return Ok(());
}
self.in_attribute = true;
out.enter_span(Class::Attribute)?;
}
- out.string("#", Class::None, None)?;
+ out.string("#", Class::None)?;
return Ok(());
}
token::CloseDelim(token::Bracket) => {
if self.in_attribute {
self.in_attribute = false;
- out.string("]", Class::None, None)?;
+ out.string("]", Class::None)?;
out.exit_span()?;
return Ok(());
} else {
// Anything that didn't return above is the simple case where we the
// class just spans a single token, so we can use the `string` method.
- out.string(Escape(&self.snip(tas.sp)), klass, Some(&tas))
+ out.string(Escape(&self.snip(tas.sp)), klass)
}
// Helper function to get a snippet from the codemap.
impl Class {
/// Returns the css class expected by rustdoc for each `Class`.
- pub fn rustdoc_class(self) -> &'static str {
+ fn rustdoc_class(self) -> &'static str {
match self {
Class::None => "",
Class::Comment => "comment",
}
}
-fn write_header(class: Option<&str>,
- id: Option<&str>,
- out: &mut dyn Write)
- -> io::Result<()> {
- write!(out, "<pre ")?;
- if let Some(id) = id {
- write!(out, "id='{}' ", id)?;
- }
- write!(out, "class=\"rust {}\">\n", class.unwrap_or(""))
+fn write_header(class: Option<&str>, out: &mut dyn Write) -> io::Result<()> {
+ write!(out, "<pre class=\"rust {}\">\n", class.unwrap_or(""))
}
fn write_footer(out: &mut dyn Write) -> io::Result<()> {
//! ```
//! #![feature(rustc_private)]
//!
-//! use rustdoc::html::markdown::Markdown;
+//! use rustdoc::html::markdown::{IdMap, Markdown, ErrorCodes};
+//! use std::cell::RefCell;
//!
//! let s = "My *markdown* _text_";
-//! let html = format!("{}", Markdown(s, &[]));
+//! let mut id_map = IdMap::new();
+//! let html = format!("{}", Markdown(s, &[], RefCell::new(&mut id_map), ErrorCodes::Yes));
//! // ... something using html
//! ```
#![allow(non_camel_case_types)]
-use rustc::session;
use std::cell::RefCell;
use std::collections::{HashMap, VecDeque};
use std::default::Default;
use std::borrow::Cow;
use std::ops::Range;
use std::str;
-use syntax::feature_gate::UnstableFeatures;
-use syntax::codemap::Span;
-use html::render::derive_id;
use html::toc::TocBuilder;
use html::highlight;
use test;
/// formatted, this struct will emit the HTML corresponding to the rendered
/// version of the contained markdown string.
/// The second parameter is a list of link replacements
-pub struct Markdown<'a>(pub &'a str, pub &'a [(String, String)]);
+pub struct Markdown<'a>(
+ pub &'a str, pub &'a [(String, String)], pub RefCell<&'a mut IdMap>, pub ErrorCodes);
/// A unit struct like `Markdown`, that renders the markdown with a
/// table of contents.
-pub struct MarkdownWithToc<'a>(pub &'a str);
+pub struct MarkdownWithToc<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes);
/// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
-pub struct MarkdownHtml<'a>(pub &'a str);
+pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes);
/// A unit struct like `Markdown`, that renders only the first paragraph.
pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]);
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum ErrorCodes {
+ Yes,
+ No,
+}
+
+impl ErrorCodes {
+ pub fn from(b: bool) -> Self {
+ match b {
+ true => ErrorCodes::Yes,
+ false => ErrorCodes::No,
+ }
+ }
+
+ pub fn as_bool(self) -> bool {
+ match self {
+ ErrorCodes::Yes => true,
+ ErrorCodes::No => false,
+ }
+ }
+}
+
/// Controls whether a line will be hidden or shown in HTML output.
///
/// All lines are used in documentation tests.
/// Adds syntax highlighting and playground Run buttons to rust code blocks.
struct CodeBlocks<'a, I: Iterator<Item = Event<'a>>> {
inner: I,
+ check_error_codes: ErrorCodes,
}
impl<'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'a, I> {
- fn new(iter: I) -> Self {
+ fn new(iter: I, error_codes: ErrorCodes) -> Self {
CodeBlocks {
inner: iter,
+ check_error_codes: error_codes,
}
}
}
let compile_fail;
let ignore;
if let Some(Event::Start(Tag::CodeBlock(lang))) = event {
- let parse_result = LangString::parse(&lang);
+ let parse_result = LangString::parse(&lang, self.check_error_codes);
if !parse_result.rust {
return Some(Event::Start(Tag::CodeBlock(lang)));
}
if ignore { " ignore" }
else if compile_fail { " compile_fail" }
else { "" })),
- None,
playground_button.as_ref().map(String::as_str),
tooltip));
Some(Event::Html(s.into()))
}
/// Make headings links with anchor ids and build up TOC.
-struct HeadingLinks<'a, 'b, I: Iterator<Item = Event<'a>>> {
+struct HeadingLinks<'a, 'b, 'ids, I: Iterator<Item = Event<'a>>> {
inner: I,
toc: Option<&'b mut TocBuilder>,
buf: VecDeque<Event<'a>>,
+ id_map: &'ids mut IdMap,
}
-impl<'a, 'b, I: Iterator<Item = Event<'a>>> HeadingLinks<'a, 'b, I> {
- fn new(iter: I, toc: Option<&'b mut TocBuilder>) -> Self {
+impl<'a, 'b, 'ids, I: Iterator<Item = Event<'a>>> HeadingLinks<'a, 'b, 'ids, I> {
+ fn new(iter: I, toc: Option<&'b mut TocBuilder>, ids: &'ids mut IdMap) -> Self {
HeadingLinks {
inner: iter,
toc,
buf: VecDeque::new(),
+ id_map: ids,
}
}
}
-impl<'a, 'b, I: Iterator<Item = Event<'a>>> Iterator for HeadingLinks<'a, 'b, I> {
+impl<'a, 'b, 'ids, I: Iterator<Item = Event<'a>>> Iterator for HeadingLinks<'a, 'b, 'ids, I> {
type Item = Event<'a>;
fn next(&mut self) -> Option<Self::Item> {
}
self.buf.push_back(event);
}
- let id = derive_id(id);
+ let id = self.id_map.derive(id);
if let Some(ref mut builder) = self.toc {
let mut html_header = String::new();
}
}
-pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span,
- sess: Option<&session::Session>) {
- tests.set_position(position);
+pub struct TestableCodeError(());
+impl fmt::Display for TestableCodeError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "invalid start of a new code block")
+ }
+}
+
+pub fn find_testable_code(
+ doc: &str, tests: &mut test::Collector, error_codes: ErrorCodes,
+) -> Result<(), TestableCodeError> {
let mut parser = Parser::new(doc);
let mut prev_offset = 0;
let mut nb_lines = 0;
let block_info = if s.is_empty() {
LangString::all_false()
} else {
- LangString::parse(&*s)
+ LangString::parse(&*s, error_codes)
};
if !block_info.rust {
continue
let text = lines.collect::<Vec<Cow<str>>>().join("\n");
nb_lines += doc[prev_offset..offset].lines().count();
let line = tests.get_line() + (nb_lines - 1);
- let filename = tests.get_filename();
- tests.add_test(text.to_owned(),
- block_info.should_panic, block_info.no_run,
- block_info.ignore, block_info.test_harness,
- block_info.compile_fail, block_info.error_codes,
- line, filename, block_info.allow_fail);
+ tests.add_test(text, block_info, line);
prev_offset = offset;
} else {
- if let Some(ref sess) = sess {
- sess.span_warn(position, "invalid start of a new code block");
- }
- break;
+ return Err(TestableCodeError(()));
}
}
Event::Start(Tag::Header(level)) => {
_ => {}
}
}
+ Ok(())
}
#[derive(Eq, PartialEq, Clone, Debug)]
-struct LangString {
+pub struct LangString {
original: String,
- should_panic: bool,
- no_run: bool,
- ignore: bool,
- rust: bool,
- test_harness: bool,
- compile_fail: bool,
- error_codes: Vec<String>,
- allow_fail: bool,
+ pub should_panic: bool,
+ pub no_run: bool,
+ pub ignore: bool,
+ pub rust: bool,
+ pub test_harness: bool,
+ pub compile_fail: bool,
+ pub error_codes: Vec<String>,
+ pub allow_fail: bool,
}
impl LangString {
}
}
- fn parse(string: &str) -> LangString {
+ fn parse(string: &str, allow_error_code_check: ErrorCodes) -> LangString {
+ let allow_error_code_check = allow_error_code_check.as_bool();
let mut seen_rust_tags = false;
let mut seen_other_tags = false;
let mut data = LangString::all_false();
- let mut allow_error_code_check = false;
- if UnstableFeatures::from_environment().is_nightly_build() {
- allow_error_code_check = true;
- }
data.original = string.to_owned();
let tokens = string.split(|c: char|
impl<'a> fmt::Display for Markdown<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- let Markdown(md, links) = *self;
+ let Markdown(md, links, ref ids, codes) = *self;
+ let mut ids = ids.borrow_mut();
// This is actually common enough to special-case
if md.is_empty() { return Ok(()) }
let mut s = String::with_capacity(md.len() * 3 / 2);
- html::push_html(&mut s,
- Footnotes::new(
- CodeBlocks::new(
- LinkReplacer::new(
- HeadingLinks::new(p, None),
- links))));
+ let p = HeadingLinks::new(p, None, &mut ids);
+ let p = LinkReplacer::new(p, links);
+ let p = CodeBlocks::new(p, codes);
+ let p = Footnotes::new(p);
+ html::push_html(&mut s, p);
fmt.write_str(&s)
}
impl<'a> fmt::Display for MarkdownWithToc<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- let MarkdownWithToc(md) = *self;
+ let MarkdownWithToc(md, ref ids, codes) = *self;
+ let mut ids = ids.borrow_mut();
let mut opts = Options::empty();
opts.insert(OPTION_ENABLE_TABLES);
let mut toc = TocBuilder::new();
- html::push_html(&mut s,
- Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc)))));
+ {
+ let p = HeadingLinks::new(p, Some(&mut toc), &mut ids);
+ let p = CodeBlocks::new(p, codes);
+ let p = Footnotes::new(p);
+ html::push_html(&mut s, p);
+ }
write!(fmt, "<nav id=\"TOC\">{}</nav>", toc.into_toc())?;
impl<'a> fmt::Display for MarkdownHtml<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- let MarkdownHtml(md) = *self;
+ let MarkdownHtml(md, ref ids, codes) = *self;
+ let mut ids = ids.borrow_mut();
// This is actually common enough to special-case
if md.is_empty() { return Ok(()) }
let mut s = String::with_capacity(md.len() * 3 / 2);
- html::push_html(&mut s,
- Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
+ let p = HeadingLinks::new(p, None, &mut ids);
+ let p = CodeBlocks::new(p, codes);
+ let p = Footnotes::new(p);
+ html::push_html(&mut s, p);
fmt.write_str(&s)
}
let p = Parser::new_with_broken_link_callback(md, opts,
Some(&push));
- let iter = Footnotes::new(HeadingLinks::new(p, None));
+ // There's no need to thread an IdMap through to here because
+ // the IDs generated aren't going to be emitted anywhere.
+ let mut ids = IdMap::new();
+ let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids));
for ev in iter {
if let Event::Start(Tag::Link(dest, _)) = ev {
links
}
+#[derive(Default)]
+pub struct IdMap {
+ map: HashMap<String, usize>,
+}
+
+impl IdMap {
+ pub fn new() -> Self {
+ IdMap::default()
+ }
+
+ pub fn populate<I: IntoIterator<Item=String>>(&mut self, ids: I) {
+ for id in ids {
+ let _ = self.derive(id);
+ }
+ }
+
+ pub fn reset(&mut self) {
+ self.map = HashMap::new();
+ }
+
+ pub fn derive(&mut self, candidate: String) -> String {
+ let id = match self.map.get_mut(&candidate) {
+ None => candidate,
+ Some(a) => {
+ let id = format!("{}-{}", candidate, *a);
+ *a += 1;
+ id
+ }
+ };
+
+ self.map.insert(id.clone(), 1);
+ id
+ }
+}
+
+#[cfg(test)]
+#[test]
+fn test_unique_id() {
+ let input = ["foo", "examples", "examples", "method.into_iter","examples",
+ "method.into_iter", "foo", "main", "search", "methods",
+ "examples", "method.into_iter", "assoc_type.Item", "assoc_type.Item"];
+ let expected = ["foo", "examples", "examples-1", "method.into_iter", "examples-2",
+ "method.into_iter-1", "foo-1", "main", "search", "methods",
+ "examples-3", "method.into_iter-2", "assoc_type.Item", "assoc_type.Item-1"];
+
+ let map = RefCell::new(IdMap::new());
+ let test = || {
+ let mut map = map.borrow_mut();
+ let actual: Vec<String> = input.iter().map(|s| map.derive(s.to_string())).collect();
+ assert_eq!(&actual[..], expected);
+ };
+ test();
+ map.borrow_mut().reset();
+ test();
+}
+
#[cfg(test)]
mod tests {
- use super::{LangString, Markdown, MarkdownHtml};
+ use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap};
use super::plain_summary_line;
- use html::render::reset_ids;
+ use std::cell::RefCell;
#[test]
fn test_lang_string_parse() {
fn t(s: &str,
should_panic: bool, no_run: bool, ignore: bool, rust: bool, test_harness: bool,
compile_fail: bool, allow_fail: bool, error_codes: Vec<String>) {
- assert_eq!(LangString::parse(s), LangString {
+ assert_eq!(LangString::parse(s, ErrorCodes::Yes), LangString {
should_panic,
no_run,
ignore,
t("text,no_run", false, true, false, false, false, false, false, v());
}
- #[test]
- fn issue_17736() {
- let markdown = "# title";
- Markdown(markdown, &[]).to_string();
- reset_ids(true);
- }
-
#[test]
fn test_header() {
fn t(input: &str, expect: &str) {
- let output = Markdown(input, &[]).to_string();
+ let mut map = IdMap::new();
+ let output = Markdown(input, &[], RefCell::new(&mut map), ErrorCodes::Yes).to_string();
assert_eq!(output, expect, "original: {}", input);
- reset_ids(true);
}
t("# Foo bar", "<h1 id=\"foo-bar\" class=\"section-header\">\
#[test]
fn test_header_ids_multiple_blocks() {
- fn t(input: &str, expect: &str) {
- let output = Markdown(input, &[]).to_string();
+ let mut map = IdMap::new();
+ fn t(map: &mut IdMap, input: &str, expect: &str) {
+ let output = Markdown(input, &[], RefCell::new(map), ErrorCodes::Yes).to_string();
assert_eq!(output, expect, "original: {}", input);
}
- let test = || {
- t("# Example", "<h1 id=\"example\" class=\"section-header\">\
- <a href=\"#example\">Example</a></h1>");
- t("# Panics", "<h1 id=\"panics\" class=\"section-header\">\
- <a href=\"#panics\">Panics</a></h1>");
- t("# Example", "<h1 id=\"example-1\" class=\"section-header\">\
- <a href=\"#example-1\">Example</a></h1>");
- t("# Main", "<h1 id=\"main-1\" class=\"section-header\">\
- <a href=\"#main-1\">Main</a></h1>");
- t("# Example", "<h1 id=\"example-2\" class=\"section-header\">\
- <a href=\"#example-2\">Example</a></h1>");
- t("# Panics", "<h1 id=\"panics-1\" class=\"section-header\">\
- <a href=\"#panics-1\">Panics</a></h1>");
- };
- test();
- reset_ids(true);
- test();
+ t(&mut map, "# Example", "<h1 id=\"example\" class=\"section-header\">\
+ <a href=\"#example\">Example</a></h1>");
+ t(&mut map, "# Panics", "<h1 id=\"panics\" class=\"section-header\">\
+ <a href=\"#panics\">Panics</a></h1>");
+ t(&mut map, "# Example", "<h1 id=\"example-1\" class=\"section-header\">\
+ <a href=\"#example-1\">Example</a></h1>");
+ t(&mut map, "# Main", "<h1 id=\"main\" class=\"section-header\">\
+ <a href=\"#main\">Main</a></h1>");
+ t(&mut map, "# Example", "<h1 id=\"example-2\" class=\"section-header\">\
+ <a href=\"#example-2\">Example</a></h1>");
+ t(&mut map, "# Panics", "<h1 id=\"panics-1\" class=\"section-header\">\
+ <a href=\"#panics-1\">Panics</a></h1>");
}
#[test]
#[test]
fn test_markdown_html_escape() {
fn t(input: &str, expect: &str) {
- let output = MarkdownHtml(input).to_string();
+ let mut idmap = IdMap::new();
+ let output = MarkdownHtml(input, RefCell::new(&mut idmap), ErrorCodes::Yes).to_string();
assert_eq!(output, expect, "original: {}", input);
}
use std::path::{PathBuf, Path, Component};
use std::str;
use std::sync::Arc;
+use std::rc::Rc;
use externalfiles::ExternalHtml;
use serialize::json::{ToJson, Json, as_json};
use syntax::ast;
use syntax::codemap::FileName;
+use syntax::feature_gate::UnstableFeatures;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
use rustc::middle::privacy::AccessLevels;
use rustc::middle::stability;
use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
use html::format::fmt_impl_for_trait_page;
use html::item_type::ItemType;
-use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine};
+use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, ErrorCodes, IdMap};
use html::{highlight, layout};
use minifier;
/// easily cloned because it is cloned per work-job (about once per item in the
/// rustdoc tree).
#[derive(Clone)]
-pub struct Context {
+struct Context {
/// Current hierarchy of components leading down to what's currently being
/// rendered
pub current: Vec<String>,
/// real location of an item. This is used to allow external links to
/// publicly reused items to redirect to the right location.
pub render_redirect_pages: bool,
+ pub codes: ErrorCodes,
+ /// The map used to ensure all generated 'id=' attributes are unique.
+ id_map: Rc<RefCell<IdMap>>,
pub shared: Arc<SharedContext>,
}
-pub struct SharedContext {
+struct SharedContext {
/// The path to the crate root source minus the file name.
/// Used for simplifying paths to the highlighted source code files.
pub src_root: PathBuf,
thread_local!(static CACHE_KEY: RefCell<Arc<Cache>> = Default::default());
thread_local!(pub static CURRENT_LOCATION_KEY: RefCell<Vec<String>> = RefCell::new(Vec::new()));
-thread_local!(pub static USED_ID_MAP: RefCell<FxHashMap<String, usize>> = RefCell::new(init_ids()));
-fn init_ids() -> FxHashMap<String, usize> {
+pub fn initial_ids() -> Vec<String> {
[
"main",
"search",
"methods",
"deref-methods",
"implementations",
- ].into_iter().map(|id| (String::from(*id), 1)).collect()
-}
-
-/// This method resets the local table of used ID attributes. This is typically
-/// used at the beginning of rendering an entire HTML page to reset from the
-/// previous state (if any).
-pub fn reset_ids(embedded: bool) {
- USED_ID_MAP.with(|s| {
- *s.borrow_mut() = if embedded {
- init_ids()
- } else {
- FxHashMap()
- };
- });
-}
-
-pub fn derive_id(candidate: String) -> String {
- USED_ID_MAP.with(|map| {
- let id = match map.borrow_mut().get_mut(&candidate) {
- None => candidate,
- Some(a) => {
- let id = format!("{}-{}", candidate, *a);
- *a += 1;
- id
- }
- };
-
- map.borrow_mut().insert(id.clone(), 1);
- id
- })
+ ].into_iter().map(|id| (String::from(*id))).collect()
}
/// Generates the documentation for `crate` into the directory `dst`
renderinfo: RenderInfo,
sort_modules_alphabetically: bool,
themes: Vec<PathBuf>,
- enable_minification: bool) -> Result<(), Error> {
+ enable_minification: bool,
+ id_map: IdMap) -> Result<(), Error> {
let src_root = match krate.src {
FileName::Real(ref p) => match p.parent() {
Some(p) => p.to_path_buf(),
current: Vec::new(),
dst,
render_redirect_pages: false,
+ codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()),
+ id_map: Rc::new(RefCell::new(id_map)),
shared: Arc::new(scx),
};
}
impl Context {
+ fn derive_id(&self, id: String) -> String {
+ let mut map = self.id_map.borrow_mut();
+ map.derive(id)
+ }
+
/// String representation of how to get back to the root path of the 'doc/'
/// folder in terms of a relative URL.
fn root_path(&self) -> String {
resource_suffix: &self.shared.resource_suffix,
};
- reset_ids(true);
+ {
+ self.id_map.borrow_mut().reset();
+ self.id_map.borrow_mut().populate(initial_ids());
+ }
if !self.render_redirect_pages {
layout::render(writer, &self.shared.layout, &page,
/// Render md_text as markdown.
fn render_markdown(w: &mut fmt::Formatter,
+ cx: &Context,
md_text: &str,
links: Vec<(String, String)>,
- prefix: &str,)
+ prefix: &str)
-> fmt::Result {
- write!(w, "<div class='docblock'>{}{}</div>", prefix, Markdown(md_text, &links))
+ let mut ids = cx.id_map.borrow_mut();
+ write!(w, "<div class='docblock'>{}{}</div>",
+ prefix, Markdown(md_text, &links, RefCell::new(&mut ids), cx.codes))
}
-fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink,
+fn document_short(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, link: AssocItemLink,
prefix: &str) -> fmt::Result {
if let Some(s) = item.doc_value() {
let markdown = if s.contains('\n') {
} else {
plain_summary_line(Some(s)).to_string()
};
- render_markdown(w, &markdown, item.links(), prefix)?;
+ render_markdown(w, cx, &markdown, item.links(), prefix)?;
} else if !prefix.is_empty() {
write!(w, "<div class='docblock'>{}</div>", prefix)?;
}
None,
None,
None,
- None,
)
}
_ => String::new(),
cx: &Context, prefix: &str) -> fmt::Result {
if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
debug!("Doc block: =====\n{}\n=====", s);
- render_markdown(w, &*s, item.links(), prefix)?;
+ render_markdown(w, cx, &*s, item.links(), prefix)?;
} else if !prefix.is_empty() {
write!(w, "<div class='docblock'>{}</div>", prefix)?;
}
let (short, name) = item_ty_to_strs(&myty.unwrap());
write!(w, "<h2 id='{id}' class='section-header'>\
<a href=\"#{id}\">{name}</a></h2>\n<table>",
- id = derive_id(short.to_owned()), name = name)?;
+ id = cx.derive_id(short.to_owned()), name = name)?;
}
match myitem.inner {
fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<String> {
let mut stability = vec![];
+ let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
if let Some(stab) = item.stability.as_ref() {
let deprecated_reason = if show_reason && !stab.deprecated_reason.is_empty() {
} else {
String::new()
};
+ let mut ids = cx.id_map.borrow_mut();
+ let html = MarkdownHtml(&deprecated_reason, RefCell::new(&mut ids), error_codes);
let text = if stability::deprecation_in_effect(&stab.deprecated_since) {
- format!("Deprecated{}{}",
- since,
- MarkdownHtml(&deprecated_reason))
+ format!("Deprecated{}{}", since, html)
} else {
- format!("Deprecating in {}{}",
- Escape(&stab.deprecated_since),
- MarkdownHtml(&deprecated_reason))
+ format!("Deprecating in {}{}", Escape(&stab.deprecated_since), html)
};
stability.push(format!("<div class='stab deprecated'>{}</div>", text))
};
</div>",
unstable_extra));
} else {
+ let mut ids = cx.id_map.borrow_mut();
let text = format!("<summary><span class=microscope>🔬</span> \
This is a nightly-only experimental API. {}\
</summary>{}",
unstable_extra,
- MarkdownHtml(&stab.unstable_reason));
+ MarkdownHtml(
+ &stab.unstable_reason,
+ RefCell::new(&mut ids),
+ error_codes));
stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
text));
}
String::new()
};
+ let mut ids = cx.id_map.borrow_mut();
let text = if stability::deprecation_in_effect(&depr.since) {
format!("Deprecated{}{}",
since,
- MarkdownHtml(¬e))
+ MarkdownHtml(¬e, RefCell::new(&mut ids), error_codes))
} else {
format!("Deprecating in {}{}",
Escape(&depr.since),
- MarkdownHtml(¬e))
+ MarkdownHtml(¬e, RefCell::new(&mut ids), error_codes))
};
stability.push(format!("<div class='stab deprecated'>{}</div>", text))
}
-> fmt::Result {
let name = m.name.as_ref().unwrap();
let item_type = m.type_();
- let id = derive_id(format!("{}.{}", item_type, name));
- let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
+ let id = cx.derive_id(format!("{}.{}", item_type, name));
+ let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "{extra}<h3 id='{id}' class='method'>\
<span id='{ns_id}' class='invisible'><code>",
extra = render_spotlight_traits(m)?,
document_non_exhaustive_header(it))?;
document_non_exhaustive(w, it)?;
for (field, ty) in fields {
- let id = derive_id(format!("{}.{}",
+ let id = cx.derive_id(format!("{}.{}",
ItemType::StructField,
field.name.as_ref().unwrap()));
- let ns_id = derive_id(format!("{}.{}",
+ let ns_id = cx.derive_id(format!("{}.{}",
field.name.as_ref().unwrap(),
ItemType::StructField.name_space()));
write!(w, "<span id=\"{id}\" class=\"{item_type} small-section-header\">
document_non_exhaustive_header(it))?;
document_non_exhaustive(w, it)?;
for variant in &e.variants {
- let id = derive_id(format!("{}.{}",
+ let id = cx.derive_id(format!("{}.{}",
ItemType::Variant,
variant.name.as_ref().unwrap()));
- let ns_id = derive_id(format!("{}.{}",
+ let ns_id = cx.derive_id(format!("{}.{}",
variant.name.as_ref().unwrap(),
ItemType::Variant.name_space()));
write!(w, "<span id=\"{id}\" class=\"variant small-section-header\">\
if let clean::VariantItem(Variant {
kind: VariantKind::Struct(ref s)
}) = variant.inner {
- let variant_id = derive_id(format!("{}.{}.fields",
+ let variant_id = cx.derive_id(format!("{}.{}.fields",
ItemType::Variant,
variant.name.as_ref().unwrap()));
write!(w, "<span class='docblock autohide sub-variant' id='{id}'>",
for field in &s.fields {
use clean::StructFieldItem;
if let StructFieldItem(ref ty) = field.inner {
- let id = derive_id(format!("variant.{}.field.{}",
+ let id = cx.derive_id(format!("variant.{}.field.{}",
variant.name.as_ref().unwrap(),
field.name.as_ref().unwrap()));
- let ns_id = derive_id(format!("{}.{}.{}.{}",
+ let ns_id = cx.derive_id(format!("{}.{}.{}.{}",
variant.name.as_ref().unwrap(),
ItemType::Variant.name_space(),
field.name.as_ref().unwrap(),
render_mode: RenderMode, outer_version: Option<&str>,
show_def_docs: bool) -> fmt::Result {
if render_mode == RenderMode::Normal {
- let id = derive_id(match i.inner_impl().trait_ {
+ let id = cx.derive_id(match i.inner_impl().trait_ {
Some(ref t) => format!("impl-{}", small_url_encode(&format!("{:#}", t))),
None => "impl".to_string(),
});
}
write!(w, "</span></td></tr></tbody></table></h3>")?;
if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
+ let mut ids = cx.id_map.borrow_mut();
write!(w, "<div class='docblock'>{}</div>",
- Markdown(&*dox, &i.impl_item.links()))?;
+ Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids), cx.codes))?;
}
}
clean::TyMethodItem(clean::TyMethod{ ref decl, .. }) => {
// Only render when the method is not static or we allow static methods
if render_method_item {
- let id = derive_id(format!("{}.{}", item_type, name));
- let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
+ let id = cx.derive_id(format!("{}.{}", item_type, name));
+ let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
write!(w, "{}", spotlight_decl(decl)?)?;
write!(w, "<span id='{}' class='invisible'>", ns_id)?;
}
}
clean::TypedefItem(ref tydef, _) => {
- let id = derive_id(format!("{}.{}", ItemType::AssociatedType, name));
- let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
+ let id = cx.derive_id(format!("{}.{}", ItemType::AssociatedType, name));
+ let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?;
write!(w, "</code></span></h4>\n")?;
}
clean::AssociatedConstItem(ref ty, ref default) => {
- let id = derive_id(format!("{}.{}", item_type, name));
- let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
+ let id = cx.derive_id(format!("{}.{}", item_type, name));
+ let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?;
write!(w, "</code></span></h4>\n")?;
}
clean::AssociatedTypeItem(ref bounds, ref default) => {
- let id = derive_id(format!("{}.{}", item_type, name));
- let ns_id = derive_id(format!("{}.{}", name, item_type.name_space()));
+ let id = cx.derive_id(format!("{}.{}", item_type, name));
+ let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?;
} else if show_def_docs {
// In case the item isn't documented,
// provide short documentation from the trait.
- document_short(w, it, link, &prefix)?;
+ document_short(w, cx, it, link, &prefix)?;
}
}
} else {
} else {
document_stability(w, cx, item)?;
if show_def_docs {
- document_short(w, item, link, &prefix)?;
+ document_short(w, cx, item, link, &prefix)?;
}
}
}
}
write!(fmt, "</pre>")?;
write!(fmt, "{}",
- highlight::render_with_highlighting(s, None, None, None, None))?;
+ highlight::render_with_highlighting(s, None, None, None))?;
Ok(())
}
}
w.write_str(&highlight::render_with_highlighting(&t.source,
Some("macro"),
None,
- None,
None))
})?;
document(w, cx, it)
CACHE_KEY.with(|c| c.borrow().clone())
}
-#[cfg(test)]
-#[test]
-fn test_unique_id() {
- let input = ["foo", "examples", "examples", "method.into_iter","examples",
- "method.into_iter", "foo", "main", "search", "methods",
- "examples", "method.into_iter", "assoc_type.Item", "assoc_type.Item"];
- let expected = ["foo", "examples", "examples-1", "method.into_iter", "examples-2",
- "method.into_iter-1", "foo-1", "main-1", "search-1", "methods-1",
- "examples-3", "method.into_iter-2", "assoc_type.Item", "assoc_type.Item-1"];
-
- let test = || {
- let actual: Vec<String> = input.iter().map(|s| derive_id(s.to_string())).collect();
- assert_eq!(&actual[..], expected);
- };
- test();
- reset_ids(true);
- test();
-}
-
#[cfg(test)]
#[test]
fn test_name_key() {
.content .search-results td:first-child {
padding-right: 0;
- width: 75%;
+ width: 50%;
}
.content .search-results td:first-child a {
padding-right: 10px;
}
+.content .search-results td:first-child a:after {
+ clear: both;
+ content: "";
+ display: block;
+}
.content .search-results td:first-child a span {
float: left;
}
background: rgba(0, 0, 0, 0);
}
-.docblock p > code, .docblock-short p > code {
+.docblock code, .docblock-short code {
background-color: #2A2A2A;
}
pre {
background: rgba(0, 0, 0, 0);
}
-.docblock p > code, .docblock-short p > code {
+.docblock code, .docblock-short code {
background-color: #F5F5F5;
}
pre {
#![feature(entry_and_modify)]
#![feature(ptr_offset_from)]
#![feature(crate_visibility_modifier)]
+#![feature(const_fn)]
#![recursion_limit="256"]
mod test;
mod theme;
-use clean::AttributesExt;
-
struct Output {
krate: clean::Crate,
renderinfo: html::render::RenderInfo,
"edition to use when compiling rust code (default: 2015)",
"EDITION")
}),
- unstable("color", |o| {
+ stable("color", |o| {
o.optopt("",
"color",
"Configure coloring of output:
never = never colorize output",
"auto|always|never")
}),
- unstable("error-format", |o| {
+ stable("error-format", |o| {
o.optopt("",
"error-format",
"How errors and other messages are produced",
if matches.opt_strs("passes") == ["list"] {
println!("Available passes for running rustdoc:");
- for &(name, _, description) in passes::PASSES {
- println!("{:>20} - {}", name, description);
+ for pass in passes::PASSES {
+ println!("{:>20} - {}", pass.name(), pass.description());
}
println!("\nDefault passes for rustdoc:");
for &name in passes::DEFAULT_PASSES {
}
}
+ let mut id_map = html::markdown::IdMap::new();
+ id_map.populate(html::render::initial_ids());
let external_html = match ExternalHtml::load(
&matches.opt_strs("html-in-header"),
&matches.opt_strs("html-before-content"),
&matches.opt_strs("html-after-content"),
&matches.opt_strs("markdown-before-content"),
- &matches.opt_strs("markdown-after-content"), &diag) {
+ &matches.opt_strs("markdown-after-content"), &diag, &mut id_map) {
Some(eh) => eh,
None => return 3,
};
renderinfo,
sort_modules_alphabetically,
themes,
- enable_minification)
+ enable_minification, id_map)
.expect("failed to generate documentation");
0
}
where R: 'static + Send,
F: 'static + Send + FnOnce(Output) -> R
{
- let mut default_passes = if matches.opt_present("no-defaults") {
+ let default_passes = if matches.opt_present("no-defaults") {
passes::DefaultPassOption::None
} else if matches.opt_present("document-private-items") {
passes::DefaultPassOption::Private
passes::DefaultPassOption::Default
};
- let mut manual_passes = matches.opt_strs("passes");
- let mut plugins = matches.opt_strs("plugins");
+ let manual_passes = matches.opt_strs("passes");
+ let plugins = matches.opt_strs("plugins");
// First, parse the crate and extract all relevant information.
let mut paths = SearchPaths::new();
let result = rustc_driver::monitor(move || syntax::with_globals(move || {
use rustc::session::config::Input;
- let (mut krate, renderinfo) =
+ let (mut krate, renderinfo, passes) =
core::run_core(paths, cfgs, externs, Input::File(cratefile), triple, maybe_sysroot,
display_warnings, crate_name.clone(),
force_unstable_if_unmarked, edition, cg, error_format,
- lint_opts, lint_cap, describe_lints);
+ lint_opts, lint_cap, describe_lints, manual_passes, default_passes);
info!("finished with rustc");
krate.version = crate_version;
- let diag = core::new_handler(error_format, None);
-
- fn report_deprecated_attr(name: &str, diag: &errors::Handler) {
- let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \
- considered deprecated", name));
- msg.warn("please see https://github.com/rust-lang/rust/issues/44136");
-
- if name == "no_default_passes" {
- msg.help("you may want to use `#![doc(document_private_items)]`");
- }
-
- msg.emit();
- }
-
- // Process all of the crate attributes, extracting plugin metadata along
- // with the passes which we are supposed to run.
- for attr in krate.module.as_ref().unwrap().attrs.lists("doc") {
- let name = attr.name().map(|s| s.as_str());
- let name = name.as_ref().map(|s| &s[..]);
- if attr.is_word() {
- if name == Some("no_default_passes") {
- report_deprecated_attr("no_default_passes", &diag);
- if default_passes == passes::DefaultPassOption::Default {
- default_passes = passes::DefaultPassOption::None;
- }
- }
- } else if let Some(value) = attr.value_str() {
- let sink = match name {
- Some("passes") => {
- report_deprecated_attr("passes = \"...\"", &diag);
- &mut manual_passes
- },
- Some("plugins") => {
- report_deprecated_attr("plugins = \"...\"", &diag);
- &mut plugins
- },
- _ => continue,
- };
- sink.extend(value.as_str().split_whitespace().map(|p| p.to_string()));
- }
-
- if attr.is_word() && name == Some("document_private_items") {
- if default_passes == passes::DefaultPassOption::Default {
- default_passes = passes::DefaultPassOption::Private;
- }
- }
- }
-
- let mut passes: Vec<String> =
- passes::defaults(default_passes).iter().map(|p| p.to_string()).collect();
- passes.extend(manual_passes);
-
if !plugins.is_empty() {
eprintln!("WARNING: --plugins no longer functions; see CVE-2018-1000622");
}
for pass in &passes {
// determine if we know about this pass
- let pass = match passes::PASSES.iter().find(|(p, ..)| p == pass) {
- Some(pass) => pass.1,
+ let pass = match passes::find_pass(pass) {
+ Some(pass) => if let Some(pass) = pass.late_fn() {
+ pass
+ } else {
+ // not a late pass, but still valid so don't report the error
+ continue
+ }
None => {
error!("unknown pass {}, skipping", *pass);
use std::fs::File;
use std::io::prelude::*;
use std::path::{PathBuf, Path};
+use std::cell::RefCell;
use errors;
use getopts;
use rustc::session::search_paths::SearchPaths;
use rustc::session::config::{Externs, CodegenOptions};
use syntax::codemap::DUMMY_SP;
+use syntax::feature_gate::UnstableFeatures;
use syntax::edition::Edition;
use externalfiles::{ExternalHtml, LoadStringError, load_string};
-use html::render::reset_ids;
use html::escape::Escape;
use html::markdown;
-use html::markdown::{Markdown, MarkdownWithToc, find_testable_code};
+use html::markdown::{ErrorCodes, IdMap, Markdown, MarkdownWithToc, find_testable_code};
use test::{TestOptions, Collector};
/// Separate any lines at the start of the file that begin with `# ` or `%`.
}
let title = metadata[0];
- reset_ids(false);
-
+ let mut ids = IdMap::new();
+ let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
let text = if include_toc {
- MarkdownWithToc(text).to_string()
+ MarkdownWithToc(text, RefCell::new(&mut ids), error_codes).to_string()
} else {
- Markdown(text, &[]).to_string()
+ Markdown(text, &[], RefCell::new(&mut ids), error_codes).to_string()
};
let err = write!(
true, opts, maybe_sysroot, None,
Some(PathBuf::from(input)),
linker, edition);
- find_testable_code(&input_str, &mut collector, DUMMY_SP, None);
+ collector.set_position(DUMMY_SP);
+ let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
+ let res = find_testable_code(&input_str, &mut collector, codes);
+ if let Err(err) = res {
+ diag.span_warn(DUMMY_SP, &err.to_string());
+ }
test_args.insert(0, "rustdoctest".to_string());
testing::test_main(&test_args, collector.tests,
testing::Options::new().display_output(display_warnings));
use clean::{self, DocFragment, Item};
use fold;
use fold::DocFolder;
+use passes::Pass;
use std::mem::replace;
+pub const COLLAPSE_DOCS: Pass =
+ Pass::late("collapse-docs", collapse_docs,
+ "concatenates all document attributes into one document attribute");
+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum DocFragmentKind {
Sugared,
--- /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 clean::*;
+
+use rustc::lint as lint;
+use rustc::hir;
+use rustc::hir::def::Def;
+use rustc::ty;
+use syntax;
+use syntax::ast::{self, Ident, NodeId};
+use syntax::feature_gate::UnstableFeatures;
+use syntax::symbol::Symbol;
+use syntax_pos::{self, DUMMY_SP};
+
+use std::ops::Range;
+
+use core::DocContext;
+use fold::DocFolder;
+use html::markdown::markdown_links;
+use passes::Pass;
+
+pub const COLLECT_INTRA_DOC_LINKS: Pass =
+ Pass::early("collect-intra-doc-links", collect_intra_doc_links,
+ "reads a crate's documentation to resolve intra-doc-links");
+
+pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext) -> Crate {
+ if !UnstableFeatures::from_environment().is_nightly_build() {
+ krate
+ } else {
+ let mut coll = LinkCollector::new(cx);
+
+ coll.fold_crate(krate)
+ }
+}
+
+#[derive(Debug)]
+enum PathKind {
+ /// can be either value or type, not a macro
+ Unknown,
+ /// macro
+ Macro,
+ /// values, functions, consts, statics, everything in the value namespace
+ Value,
+ /// types, traits, everything in the type namespace
+ Type,
+}
+
+struct LinkCollector<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
+ cx: &'a DocContext<'a, 'tcx, 'rcx, 'cstore>,
+ mod_ids: Vec<NodeId>,
+}
+
+impl<'a, 'tcx, 'rcx, 'cstore> LinkCollector<'a, 'tcx, 'rcx, 'cstore> {
+ fn new(cx: &'a DocContext<'a, 'tcx, 'rcx, 'cstore>) -> Self {
+ LinkCollector {
+ cx,
+ mod_ids: Vec::new(),
+ }
+ }
+
+ /// Resolve a given string as a path, along with whether or not it is
+ /// in the value namespace. Also returns an optional URL fragment in the case
+ /// of variants and methods
+ fn resolve(&self, path_str: &str, is_val: bool, current_item: &Option<String>)
+ -> Result<(Def, Option<String>), ()>
+ {
+ let cx = self.cx;
+
+ // In case we're in a module, try to resolve the relative
+ // path
+ if let Some(id) = self.mod_ids.last() {
+ let result = cx.resolver.borrow_mut()
+ .with_scope(*id,
+ |resolver| {
+ resolver.resolve_str_path_error(DUMMY_SP,
+ &path_str, is_val)
+ });
+
+ if let Ok(result) = result {
+ // In case this is a trait item, skip the
+ // early return and try looking for the trait
+ let value = match result.def {
+ Def::Method(_) | Def::AssociatedConst(_) => true,
+ Def::AssociatedTy(_) => false,
+ Def::Variant(_) => return handle_variant(cx, result.def),
+ // not a trait item, just return what we found
+ _ => return Ok((result.def, None))
+ };
+
+ if value != is_val {
+ return Err(())
+ }
+ } else if let Some(prim) = is_primitive(path_str, is_val) {
+ return Ok((prim, Some(path_str.to_owned())))
+ } else {
+ // If resolution failed, it may still be a method
+ // because methods are not handled by the resolver
+ // If so, bail when we're not looking for a value
+ if !is_val {
+ return Err(())
+ }
+ }
+
+ // Try looking for methods and associated items
+ let mut split = path_str.rsplitn(2, "::");
+ let item_name = if let Some(first) = split.next() {
+ first
+ } else {
+ return Err(())
+ };
+
+ let mut path = if let Some(second) = split.next() {
+ second.to_owned()
+ } else {
+ return Err(())
+ };
+
+ if path == "self" || path == "Self" {
+ if let Some(name) = current_item.as_ref() {
+ path = name.clone();
+ }
+ }
+
+ let ty = cx.resolver.borrow_mut()
+ .with_scope(*id,
+ |resolver| {
+ resolver.resolve_str_path_error(DUMMY_SP, &path, false)
+ })?;
+ match ty.def {
+ Def::Struct(did) | Def::Union(did) | Def::Enum(did) | Def::TyAlias(did) => {
+ let item = cx.tcx.inherent_impls(did)
+ .iter()
+ .flat_map(|imp| cx.tcx.associated_items(*imp))
+ .find(|item| item.ident.name == item_name);
+ if let Some(item) = item {
+ let out = match item.kind {
+ ty::AssociatedKind::Method if is_val => "method",
+ ty::AssociatedKind::Const if is_val => "associatedconstant",
+ _ => return Err(())
+ };
+ Ok((ty.def, Some(format!("{}.{}", out, item_name))))
+ } else {
+ match cx.tcx.type_of(did).sty {
+ ty::TyAdt(def, _) => {
+ if let Some(item) = if def.is_enum() {
+ def.all_fields().find(|item| item.ident.name == item_name)
+ } else {
+ def.non_enum_variant()
+ .fields
+ .iter()
+ .find(|item| item.ident.name == item_name)
+ } {
+ Ok((ty.def,
+ Some(format!("{}.{}",
+ if def.is_enum() {
+ "variant"
+ } else {
+ "structfield"
+ },
+ item.ident))))
+ } else {
+ Err(())
+ }
+ }
+ _ => Err(()),
+ }
+ }
+ }
+ Def::Trait(did) => {
+ let item = cx.tcx.associated_item_def_ids(did).iter()
+ .map(|item| cx.tcx.associated_item(*item))
+ .find(|item| item.ident.name == item_name);
+ if let Some(item) = item {
+ let kind = match item.kind {
+ ty::AssociatedKind::Const if is_val => "associatedconstant",
+ ty::AssociatedKind::Type if !is_val => "associatedtype",
+ ty::AssociatedKind::Method if is_val => {
+ if item.defaultness.has_value() {
+ "method"
+ } else {
+ "tymethod"
+ }
+ }
+ _ => return Err(())
+ };
+
+ Ok((ty.def, Some(format!("{}.{}", kind, item_name))))
+ } else {
+ Err(())
+ }
+ }
+ _ => Err(())
+ }
+ } else {
+ Err(())
+ }
+ }
+}
+
+impl<'a, 'tcx, 'rcx, 'cstore> DocFolder for LinkCollector<'a, 'tcx, 'rcx, 'cstore> {
+ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
+ let item_node_id = if item.is_mod() {
+ if let Some(id) = self.cx.tcx.hir.as_local_node_id(item.def_id) {
+ Some(id)
+ } else {
+ debug!("attempting to fold on a non-local item: {:?}", item);
+ return self.fold_item_recur(item);
+ }
+ } else {
+ None
+ };
+
+ let current_item = match item.inner {
+ ModuleItem(..) => {
+ if item.attrs.inner_docs {
+ if item_node_id.unwrap() != NodeId::new(0) {
+ item.name.clone()
+ } else {
+ None
+ }
+ } else {
+ match self.mod_ids.last() {
+ Some(parent) if *parent != NodeId::new(0) => {
+ //FIXME: can we pull the parent module's name from elsewhere?
+ Some(self.cx.tcx.hir.name(*parent).to_string())
+ }
+ _ => None,
+ }
+ }
+ }
+ ImplItem(Impl { ref for_, .. }) => {
+ for_.def_id().map(|did| self.cx.tcx.item_name(did).to_string())
+ }
+ // we don't display docs on `extern crate` items anyway, so don't process them
+ ExternCrateItem(..) => return self.fold_item_recur(item),
+ ImportItem(Import::Simple(ref name, ..)) => Some(name.clone()),
+ MacroItem(..) => None,
+ _ => item.name.clone(),
+ };
+
+ if item.is_mod() && item.attrs.inner_docs {
+ self.mod_ids.push(item_node_id.unwrap());
+ }
+
+ let cx = self.cx;
+ let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
+
+ for (ori_link, link_range) in markdown_links(&dox) {
+ // bail early for real links
+ if ori_link.contains('/') {
+ continue;
+ }
+ let link = ori_link.replace("`", "");
+ let (def, fragment) = {
+ let mut kind = PathKind::Unknown;
+ let path_str = if let Some(prefix) =
+ ["struct@", "enum@", "type@",
+ "trait@", "union@"].iter()
+ .find(|p| link.starts_with(**p)) {
+ kind = PathKind::Type;
+ link.trim_left_matches(prefix)
+ } else if let Some(prefix) =
+ ["const@", "static@",
+ "value@", "function@", "mod@",
+ "fn@", "module@", "method@"]
+ .iter().find(|p| link.starts_with(**p)) {
+ kind = PathKind::Value;
+ link.trim_left_matches(prefix)
+ } else if link.ends_with("()") {
+ kind = PathKind::Value;
+ link.trim_right_matches("()")
+ } else if link.starts_with("macro@") {
+ kind = PathKind::Macro;
+ link.trim_left_matches("macro@")
+ } else if link.ends_with('!') {
+ kind = PathKind::Macro;
+ link.trim_right_matches('!')
+ } else {
+ &link[..]
+ }.trim();
+
+ if path_str.contains(|ch: char| !(ch.is_alphanumeric() ||
+ ch == ':' || ch == '_')) {
+ continue;
+ }
+
+ match kind {
+ PathKind::Value => {
+ if let Ok(def) = self.resolve(path_str, true, ¤t_item) {
+ def
+ } else {
+ resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+ // this could just be a normal link or a broken link
+ // we could potentially check if something is
+ // "intra-doc-link-like" and warn in that case
+ continue;
+ }
+ }
+ PathKind::Type => {
+ if let Ok(def) = self.resolve(path_str, false, ¤t_item) {
+ def
+ } else {
+ resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+ // this could just be a normal link
+ continue;
+ }
+ }
+ PathKind::Unknown => {
+ // try everything!
+ if let Some(macro_def) = macro_resolve(cx, path_str) {
+ if let Ok(type_def) = self.resolve(path_str, false, ¤t_item) {
+ let (type_kind, article, type_disambig)
+ = type_ns_kind(type_def.0, path_str);
+ ambiguity_error(cx, &item.attrs, path_str,
+ article, type_kind, &type_disambig,
+ "a", "macro", &format!("macro@{}", path_str));
+ continue;
+ } else if let Ok(value_def) = self.resolve(path_str,
+ true,
+ ¤t_item) {
+ let (value_kind, value_disambig)
+ = value_ns_kind(value_def.0, path_str)
+ .expect("struct and mod cases should have been \
+ caught in previous branch");
+ ambiguity_error(cx, &item.attrs, path_str,
+ "a", value_kind, &value_disambig,
+ "a", "macro", &format!("macro@{}", path_str));
+ }
+ (macro_def, None)
+ } else if let Ok(type_def) = self.resolve(path_str, false, ¤t_item) {
+ // It is imperative we search for not-a-value first
+ // Otherwise we will find struct ctors for when we are looking
+ // for structs, and the link won't work.
+ // if there is something in both namespaces
+ if let Ok(value_def) = self.resolve(path_str, true, ¤t_item) {
+ let kind = value_ns_kind(value_def.0, path_str);
+ if let Some((value_kind, value_disambig)) = kind {
+ let (type_kind, article, type_disambig)
+ = type_ns_kind(type_def.0, path_str);
+ ambiguity_error(cx, &item.attrs, path_str,
+ article, type_kind, &type_disambig,
+ "a", value_kind, &value_disambig);
+ continue;
+ }
+ }
+ type_def
+ } else if let Ok(value_def) = self.resolve(path_str, true, ¤t_item) {
+ value_def
+ } else {
+ resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+ // this could just be a normal link
+ continue;
+ }
+ }
+ PathKind::Macro => {
+ if let Some(def) = macro_resolve(cx, path_str) {
+ (def, None)
+ } else {
+ resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
+ continue
+ }
+ }
+ }
+ };
+
+ if let Def::PrimTy(_) = def {
+ item.attrs.links.push((ori_link, None, fragment));
+ } else {
+ let id = register_def(cx, def);
+ item.attrs.links.push((ori_link, Some(id), fragment));
+ }
+ }
+
+ if item.is_mod() && !item.attrs.inner_docs {
+ self.mod_ids.push(item_node_id.unwrap());
+ }
+
+ if item.is_mod() {
+ let ret = self.fold_item_recur(item);
+
+ self.mod_ids.pop();
+
+ ret
+ } else {
+ self.fold_item_recur(item)
+ }
+ }
+}
+
+/// Resolve a string as a macro
+fn macro_resolve(cx: &DocContext, path_str: &str) -> Option<Def> {
+ use syntax::ext::base::{MacroKind, SyntaxExtension};
+ use syntax::ext::hygiene::Mark;
+ let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
+ let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
+ let mut resolver = cx.resolver.borrow_mut();
+ let mark = Mark::root();
+ let res = resolver
+ .resolve_macro_to_def_inner(mark, &path, MacroKind::Bang, false);
+ if let Ok(def) = res {
+ if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) {
+ return Some(def);
+ }
+ }
+ if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) {
+ return Some(*def);
+ }
+ None
+}
+
+fn span_of_attrs(attrs: &Attributes) -> syntax_pos::Span {
+ if attrs.doc_strings.is_empty() {
+ return DUMMY_SP;
+ }
+ let start = attrs.doc_strings[0].span();
+ let end = attrs.doc_strings.last().expect("No doc strings provided").span();
+ start.to(end)
+}
+
+fn resolution_failure(
+ cx: &DocContext,
+ attrs: &Attributes,
+ path_str: &str,
+ dox: &str,
+ link_range: Option<Range<usize>>,
+) {
+ let sp = span_of_attrs(attrs);
+ let msg = format!("`[{}]` cannot be resolved, ignoring it...", path_str);
+
+ let code_dox = sp.to_src(cx);
+
+ let doc_comment_padding = 3;
+ let mut diag = if let Some(link_range) = link_range {
+ // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
+ // ^ ~~~~~~
+ // | link_range
+ // last_new_line_offset
+
+ let mut diag;
+ if dox.lines().count() == code_dox.lines().count() {
+ let line_offset = dox[..link_range.start].lines().count();
+ // The span starts in the `///`, so we don't have to account for the leading whitespace
+ let code_dox_len = if line_offset <= 1 {
+ doc_comment_padding
+ } else {
+ // The first `///`
+ doc_comment_padding +
+ // Each subsequent leading whitespace and `///`
+ code_dox.lines().skip(1).take(line_offset - 1).fold(0, |sum, line| {
+ sum + doc_comment_padding + line.len() - line.trim().len()
+ })
+ };
+
+ // Extract the specific span
+ let sp = sp.from_inner_byte_pos(
+ link_range.start + code_dox_len,
+ link_range.end + code_dox_len,
+ );
+
+ diag = cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
+ NodeId::new(0),
+ sp,
+ &msg);
+ diag.span_label(sp, "cannot be resolved, ignoring");
+ } else {
+ diag = cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
+ NodeId::new(0),
+ sp,
+ &msg);
+
+ let last_new_line_offset = dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
+ let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
+
+ // Print the line containing the `link_range` and manually mark it with '^'s
+ diag.note(&format!(
+ "the link appears in this line:\n\n{line}\n\
+ {indicator: <before$}{indicator:^<found$}",
+ line=line,
+ indicator="",
+ before=link_range.start - last_new_line_offset,
+ found=link_range.len(),
+ ));
+ }
+ diag
+ } else {
+ cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
+ NodeId::new(0),
+ sp,
+ &msg)
+ };
+ diag.help("to escape `[` and `]` characters, just add '\\' before them like \
+ `\\[` or `\\]`");
+ diag.emit();
+}
+
+fn ambiguity_error(cx: &DocContext, attrs: &Attributes,
+ path_str: &str,
+ article1: &str, kind1: &str, disambig1: &str,
+ article2: &str, kind2: &str, disambig2: &str) {
+ let sp = span_of_attrs(attrs);
+ cx.sess()
+ .struct_span_warn(sp,
+ &format!("`{}` is both {} {} and {} {}",
+ path_str, article1, kind1,
+ article2, kind2))
+ .help(&format!("try `{}` if you want to select the {}, \
+ or `{}` if you want to \
+ select the {}",
+ disambig1, kind1, disambig2,
+ kind2))
+ .emit();
+}
+
+/// Given a def, returns its name and disambiguator
+/// for a value namespace
+///
+/// Returns None for things which cannot be ambiguous since
+/// they exist in both namespaces (structs and modules)
+fn value_ns_kind(def: Def, path_str: &str) -> Option<(&'static str, String)> {
+ match def {
+ // structs, variants, and mods exist in both namespaces. skip them
+ Def::StructCtor(..) | Def::Mod(..) | Def::Variant(..) | Def::VariantCtor(..) => None,
+ Def::Fn(..)
+ => Some(("function", format!("{}()", path_str))),
+ Def::Method(..)
+ => Some(("method", format!("{}()", path_str))),
+ Def::Const(..)
+ => Some(("const", format!("const@{}", path_str))),
+ Def::Static(..)
+ => Some(("static", format!("static@{}", path_str))),
+ _ => Some(("value", format!("value@{}", path_str))),
+ }
+}
+
+/// Given a def, returns its name, the article to be used, and a disambiguator
+/// for the type namespace
+fn type_ns_kind(def: Def, path_str: &str) -> (&'static str, &'static str, String) {
+ let (kind, article) = match def {
+ // we can still have non-tuple structs
+ Def::Struct(..) => ("struct", "a"),
+ Def::Enum(..) => ("enum", "an"),
+ Def::Trait(..) => ("trait", "a"),
+ Def::Union(..) => ("union", "a"),
+ _ => ("type", "a"),
+ };
+ (kind, article, format!("{}@{}", kind, path_str))
+}
+
+/// Given an enum variant's def, return the def of its enum and the associated fragment
+fn handle_variant(cx: &DocContext, def: Def) -> Result<(Def, Option<String>), ()> {
+ use rustc::ty::DefIdTree;
+
+ let parent = if let Some(parent) = cx.tcx.parent(def.def_id()) {
+ parent
+ } else {
+ return Err(())
+ };
+ let parent_def = Def::Enum(parent);
+ let variant = cx.tcx.expect_variant_def(def);
+ Ok((parent_def, Some(format!("{}.v", variant.name))))
+}
+
+const PRIMITIVES: &[(&str, Def)] = &[
+ ("u8", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U8))),
+ ("u16", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U16))),
+ ("u32", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U32))),
+ ("u64", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U64))),
+ ("u128", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::U128))),
+ ("usize", Def::PrimTy(hir::PrimTy::TyUint(syntax::ast::UintTy::Usize))),
+ ("i8", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I8))),
+ ("i16", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I16))),
+ ("i32", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I32))),
+ ("i64", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I64))),
+ ("i128", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::I128))),
+ ("isize", Def::PrimTy(hir::PrimTy::TyInt(syntax::ast::IntTy::Isize))),
+ ("f32", Def::PrimTy(hir::PrimTy::TyFloat(syntax::ast::FloatTy::F32))),
+ ("f64", Def::PrimTy(hir::PrimTy::TyFloat(syntax::ast::FloatTy::F64))),
+ ("str", Def::PrimTy(hir::PrimTy::TyStr)),
+ ("bool", Def::PrimTy(hir::PrimTy::TyBool)),
+ ("char", Def::PrimTy(hir::PrimTy::TyChar)),
+];
+
+fn is_primitive(path_str: &str, is_val: bool) -> Option<Def> {
+ if is_val {
+ None
+ } else {
+ PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1)
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+//! Contains information about "passes", used to modify crate information during the documentation
+//! process.
+
use rustc::hir::def_id::DefId;
use rustc::middle::privacy::AccessLevels;
use rustc::util::nodemap::DefIdSet;
use std::mem;
+use std::fmt;
use clean::{self, GetDefId, Item};
+use core::DocContext;
use fold;
use fold::StripItem;
mod collapse_docs;
-pub use self::collapse_docs::collapse_docs;
+pub use self::collapse_docs::COLLAPSE_DOCS;
mod strip_hidden;
-pub use self::strip_hidden::strip_hidden;
+pub use self::strip_hidden::STRIP_HIDDEN;
mod strip_private;
-pub use self::strip_private::strip_private;
+pub use self::strip_private::STRIP_PRIVATE;
mod strip_priv_imports;
-pub use self::strip_priv_imports::strip_priv_imports;
+pub use self::strip_priv_imports::STRIP_PRIV_IMPORTS;
mod unindent_comments;
-pub use self::unindent_comments::unindent_comments;
+pub use self::unindent_comments::UNINDENT_COMMENTS;
mod propagate_doc_cfg;
-pub use self::propagate_doc_cfg::propagate_doc_cfg;
+pub use self::propagate_doc_cfg::PROPAGATE_DOC_CFG;
+
+mod collect_intra_doc_links;
+pub use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS;
+
+/// Represents a single pass.
+#[derive(Copy, Clone)]
+pub enum Pass {
+ /// An "early pass" is run in the compiler context, and can gather information about types and
+ /// traits and the like.
+ EarlyPass {
+ name: &'static str,
+ pass: fn(clean::Crate, &DocContext) -> clean::Crate,
+ description: &'static str,
+ },
+ /// A "late pass" is run between crate cleaning and page generation.
+ LatePass {
+ name: &'static str,
+ pass: fn(clean::Crate) -> clean::Crate,
+ description: &'static str,
+ },
+}
+
+impl fmt::Debug for Pass {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut dbg = match *self {
+ Pass::EarlyPass { .. } => f.debug_struct("EarlyPass"),
+ Pass::LatePass { .. } => f.debug_struct("LatePass"),
+ };
+
+ dbg.field("name", &self.name())
+ .field("pass", &"...")
+ .field("description", &self.description())
+ .finish()
+ }
+}
-type Pass = (
- &'static str, // name
- fn(clean::Crate) -> clean::Crate, // fn
- &'static str,
-); // description
+impl Pass {
+ /// Constructs a new early pass.
+ pub const fn early(name: &'static str,
+ pass: fn(clean::Crate, &DocContext) -> clean::Crate,
+ description: &'static str) -> Pass {
+ Pass::EarlyPass { name, pass, description }
+ }
+ /// Constructs a new late pass.
+ pub const fn late(name: &'static str,
+ pass: fn(clean::Crate) -> clean::Crate,
+ description: &'static str) -> Pass {
+ Pass::LatePass { name, pass, description }
+ }
+
+ /// Returns the name of this pass.
+ pub fn name(self) -> &'static str {
+ match self {
+ Pass::EarlyPass { name, .. } |
+ Pass::LatePass { name, .. } => name,
+ }
+ }
+
+ /// Returns the description of this pass.
+ pub fn description(self) -> &'static str {
+ match self {
+ Pass::EarlyPass { description, .. } |
+ Pass::LatePass { description, .. } => description,
+ }
+ }
+
+ /// If this pass is an early pass, returns the pointer to its function.
+ pub fn early_fn(self) -> Option<fn(clean::Crate, &DocContext) -> clean::Crate> {
+ match self {
+ Pass::EarlyPass { pass, .. } => Some(pass),
+ _ => None,
+ }
+ }
+
+ /// If this pass is a late pass, returns the pointer to its function.
+ pub fn late_fn(self) -> Option<fn(clean::Crate) -> clean::Crate> {
+ match self {
+ Pass::LatePass { pass, .. } => Some(pass),
+ _ => None,
+ }
+ }
+}
+
+/// The full list of passes.
pub const PASSES: &'static [Pass] = &[
- (
- "strip-hidden",
- strip_hidden,
- "strips all doc(hidden) items from the output",
- ),
- (
- "unindent-comments",
- unindent_comments,
- "removes excess indentation on comments in order for markdown to like it",
- ),
- (
- "collapse-docs",
- collapse_docs,
- "concatenates all document attributes into one document attribute",
- ),
- (
- "strip-private",
- strip_private,
- "strips all private items from a crate which cannot be seen externally, \
- implies strip-priv-imports",
- ),
- (
- "strip-priv-imports",
- strip_priv_imports,
- "strips all private import statements (`use`, `extern crate`) from a crate",
- ),
- (
- "propagate-doc-cfg",
- propagate_doc_cfg,
- "propagates `#[doc(cfg(...))]` to child items",
- ),
+ STRIP_HIDDEN,
+ UNINDENT_COMMENTS,
+ COLLAPSE_DOCS,
+ STRIP_PRIVATE,
+ STRIP_PRIV_IMPORTS,
+ PROPAGATE_DOC_CFG,
+ COLLECT_INTRA_DOC_LINKS,
];
+/// The list of passes run by default.
pub const DEFAULT_PASSES: &'static [&'static str] = &[
"strip-hidden",
"strip-private",
+ "collect-intra-doc-links",
"collapse-docs",
"unindent-comments",
"propagate-doc-cfg",
];
+/// The list of default passes run with `--document-private-items` is passed to rustdoc.
pub const DEFAULT_PRIVATE_PASSES: &'static [&'static str] = &[
"strip-priv-imports",
+ "collect-intra-doc-links",
"collapse-docs",
"unindent-comments",
"propagate-doc-cfg",
];
+/// A shorthand way to refer to which set of passes to use, based on the presence of
+/// `--no-defaults` or `--document-private-items`.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum DefaultPassOption {
Default,
None,
}
+/// Returns the given default set of passes.
pub fn defaults(default_set: DefaultPassOption) -> &'static [&'static str] {
match default_set {
DefaultPassOption::Default => DEFAULT_PASSES,
}
}
+/// If the given name matches a known pass, returns its information.
+pub fn find_pass(pass_name: &str) -> Option<Pass> {
+ PASSES.iter().find(|p| p.name() == pass_name).cloned()
+}
+
struct Stripper<'a> {
retained: &'a mut DefIdSet,
access_levels: &'a AccessLevels<DefId>,
use clean::{Crate, Item};
use clean::cfg::Cfg;
use fold::DocFolder;
+use passes::Pass;
+
+pub const PROPAGATE_DOC_CFG: Pass =
+ Pass::late("propagate-doc-cfg", propagate_doc_cfg,
+ "propagates `#[doc(cfg(...))]` to child items");
pub fn propagate_doc_cfg(cr: Crate) -> Crate {
CfgPropagator { parent_cfg: None }.fold_crate(cr)
use clean::{self, AttributesExt, NestedAttributesExt};
use clean::Item;
+use core::DocContext;
use fold;
use fold::DocFolder;
use fold::StripItem;
-use passes::ImplStripper;
+use passes::{ImplStripper, Pass};
+
+pub const STRIP_HIDDEN: Pass =
+ Pass::early("strip-hidden", strip_hidden,
+ "strips all doc(hidden) items from the output");
/// Strip items marked `#[doc(hidden)]`
-pub fn strip_hidden(krate: clean::Crate) -> clean::Crate {
+pub fn strip_hidden(krate: clean::Crate, _: &DocContext) -> clean::Crate {
let mut retained = DefIdSet();
// strip all #[doc(hidden)] items
// except according to those terms.
use clean;
+use core::DocContext;
use fold::DocFolder;
-use passes::ImportStripper;
+use passes::{ImportStripper, Pass};
-pub fn strip_priv_imports(krate: clean::Crate) -> clean::Crate {
+pub const STRIP_PRIV_IMPORTS: Pass = Pass::early("strip-priv-imports", strip_priv_imports,
+ "strips all private import statements (`use`, `extern crate`) from a crate");
+
+pub fn strip_priv_imports(krate: clean::Crate, _: &DocContext) -> clean::Crate {
ImportStripper.fold_crate(krate)
}
use rustc::util::nodemap::DefIdSet;
use clean;
+use core::DocContext;
use fold::DocFolder;
-use passes::{ImplStripper, ImportStripper, Stripper};
+use passes::{ImplStripper, ImportStripper, Stripper, Pass};
+
+pub const STRIP_PRIVATE: Pass =
+ Pass::early("strip-private", strip_private,
+ "strips all private items from a crate which cannot be seen externally, \
+ implies strip-priv-imports");
/// Strip private items from the point of view of a crate or externally from a
/// crate, specified by the `xcrate` flag.
-pub fn strip_private(mut krate: clean::Crate) -> clean::Crate {
+pub fn strip_private(mut krate: clean::Crate, _: &DocContext) -> clean::Crate {
// This stripper collects all *retained* nodes.
let mut retained = DefIdSet();
let access_levels = krate.access_levels.clone();
use clean::{self, DocFragment, Item};
use fold::{self, DocFolder};
+use passes::Pass;
+
+pub const UNINDENT_COMMENTS: Pass =
+ Pass::late("unindent-comments", unindent_comments,
+ "removes excess indentation on comments in order for markdown to like it");
pub fn unindent_comments(krate: clean::Crate) -> clean::Crate {
CommentCleaner.fold_crate(krate)
use errors::emitter::ColorConfig;
use clean::Attributes;
-use html::markdown;
+use html::markdown::{self, ErrorCodes, LangString};
#[derive(Clone, Default)]
pub struct TestOptions {
maybe_sysroot: maybe_sysroot.clone().or_else(
|| Some(env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_path_buf())),
search_paths: libs.clone(),
- crate_types: vec![config::CrateTypeDylib],
+ crate_types: vec![config::CrateType::Dylib],
cg: cg.clone(),
externs: externs.clone(),
unstable_features: UnstableFeatures::from_environment(),
..config::basic_debugging_options()
},
edition,
- ..config::basic_options().clone()
+ ..config::Options::default()
};
driver::spawn_thread_pool(sessopts, |sessopts| {
let codemap = Lrc::new(CodeMap::new(sessopts.file_path_mapping()));
let mut hir_collector = HirCollector {
sess: &sess,
collector: &mut collector,
- map: &map
+ map: &map,
+ codes: ErrorCodes::from(sess.opts.unstable_features.is_nightly_build()),
};
hir_collector.visit_testable("".to_string(), &krate.attrs, |this| {
intravisit::walk_crate(this, krate);
maybe_sysroot: maybe_sysroot.or_else(
|| Some(env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_path_buf())),
search_paths: libs,
- crate_types: vec![config::CrateTypeExecutable],
+ crate_types: vec![config::CrateType::Executable],
output_types: outputs,
externs,
cg: config::CodegenOptions {
..config::basic_debugging_options()
},
edition,
- ..config::basic_options().clone()
+ ..config::Options::default()
};
// Shuffle around a few input and output handles here. We're going to pass
format!("{} - {} (line {})", filename, self.names.join("::"), line)
}
- pub fn add_test(&mut self, test: String,
- should_panic: bool, no_run: bool, should_ignore: bool,
- as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
- line: usize, filename: FileName, allow_fail: bool) {
+ pub fn add_test(&mut self, test: String, config: LangString, line: usize) {
+ let filename = self.get_filename();
let name = self.generate_name(line, &filename);
let cfgs = self.cfgs.clone();
let libs = self.libs.clone();
self.tests.push(testing::TestDescAndFn {
desc: testing::TestDesc {
name: testing::DynTestName(name.clone()),
- ignore: should_ignore,
+ ignore: config.ignore,
// compiler failures are test failures
should_panic: testing::ShouldPanic::No,
- allow_fail,
+ allow_fail: config.allow_fail,
},
testfn: testing::DynTestFn(box move || {
let panic = io::set_panic(None);
libs,
cg,
externs,
- should_panic,
- no_run,
- as_test_harness,
- compile_fail,
- error_codes,
+ config.should_panic,
+ config.no_run,
+ config.test_harness,
+ config.compile_fail,
+ config.error_codes,
&opts,
maybe_sysroot,
linker,
self.position = position;
}
- pub fn get_filename(&self) -> FileName {
+ fn get_filename(&self) -> FileName {
if let Some(ref codemap) = self.codemap {
let filename = codemap.span_to_filename(self.position);
if let FileName::Real(ref filename) = filename {
struct HirCollector<'a, 'hir: 'a> {
sess: &'a session::Session,
collector: &'a mut Collector,
- map: &'a hir::map::Map<'hir>
+ map: &'a hir::map::Map<'hir>,
+ codes: ErrorCodes,
}
impl<'a, 'hir> HirCollector<'a, 'hir> {
// the collapse-docs pass won't combine sugared/raw doc attributes, or included files with
// anything else, this will combine them for us
if let Some(doc) = attrs.collapsed_doc_value() {
- markdown::find_testable_code(&doc,
- self.collector,
- attrs.span.unwrap_or(DUMMY_SP),
- Some(self.sess));
+ self.collector.set_position(attrs.span.unwrap_or(DUMMY_SP));
+ let res = markdown::find_testable_code(&doc, self.collector, self.codes);
+ if let Err(err) = res {
+ self.sess.diagnostic().span_warn(attrs.span.unwrap_or(DUMMY_SP),
+ &err.to_string());
+ }
}
nested(self);
// also, is there some reason that this doesn't use the 'visit'
// framework from syntax?
-pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a> {
+pub struct RustdocVisitor<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
pub module: Module,
pub attrs: hir::HirVec<ast::Attribute>,
- pub cx: &'a core::DocContext<'a, 'tcx, 'rcx>,
+ pub cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>,
view_item_stack: FxHashSet<ast::NodeId>,
inlining: bool,
/// Is the current module and all of its parents public?
exact_paths: Option<FxHashMap<DefId, Vec<String>>>,
}
-impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
- pub fn new(cx: &'a core::DocContext<'a, 'tcx, 'rcx>) -> RustdocVisitor<'a, 'tcx, 'rcx> {
+impl<'a, 'tcx, 'rcx, 'cstore> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> {
+ pub fn new(
+ cx: &'a core::DocContext<'a, 'tcx, 'rcx, 'cstore>
+ ) -> RustdocVisitor<'a, 'tcx, 'rcx, 'cstore> {
// If the root is re-exported, terminate all recursion.
let mut stack = FxHashSet();
stack.insert(ast::CRATE_NODE_ID);
}
pub fn visit_variant_data(&mut self, item: &hir::Item,
- name: ast::Name, sd: &hir::VariantData,
- generics: &hir::Generics) -> Struct {
+ name: ast::Name, sd: &hir::VariantData,
+ generics: &hir::Generics) -> Struct {
debug!("Visiting struct");
let struct_type = struct_type_from_def(&*sd);
Struct {
/// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
/// specific rustdoc annotations into account (i.e. `doc(hidden)`)
-pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a> {
- cx: &'a ::core::DocContext<'a, 'tcx, 'rcx>,
+pub struct LibEmbargoVisitor<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
+ cx: &'a ::core::DocContext<'a, 'tcx, 'rcx, 'cstore>,
// Accessibility levels for reachable nodes
access_levels: RefMut<'a, AccessLevels<DefId>>,
// Previous accessibility level, None means unreachable
visited_mods: FxHashSet<DefId>,
}
-impl<'a, 'tcx, 'rcx> LibEmbargoVisitor<'a, 'tcx, 'rcx> {
- pub fn new(cx: &'a ::core::DocContext<'a, 'tcx, 'rcx>) -> LibEmbargoVisitor<'a, 'tcx, 'rcx> {
+impl<'a, 'tcx, 'rcx, 'cstore> LibEmbargoVisitor<'a, 'tcx, 'rcx, 'cstore> {
+ pub fn new(
+ cx: &'a ::core::DocContext<'a, 'tcx, 'rcx, 'cstore>
+ ) -> LibEmbargoVisitor<'a, 'tcx, 'rcx, 'cstore> {
LibEmbargoVisitor {
cx,
access_levels: cx.access_levels.borrow_mut(),
// Compound types:
fn emit_enum<F>(&mut self, _name: &str, f: F) -> Result<(), Self::Error>
- where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
-
- fn emit_enum_variant<F>(&mut self, _v_name: &str,
- v_id: usize,
- _len: usize,
- f: F) -> Result<(), Self::Error>
where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+ {
+ f(self)
+ }
+
+ fn emit_enum_variant<F>(&mut self, _v_name: &str, v_id: usize, _len: usize, f: F)
+ -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>
{
self.emit_usize(v_id)?;
f(self)
}
- fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, f: F)
- -> Result<(), Self::Error>
- where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
- fn emit_enum_struct_variant<F>(&mut self, v_name: &str,
- v_id: usize,
- len: usize,
- f: F) -> Result<(), Self::Error>
+ fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, f: F) -> Result<(), Self::Error>
where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+ {
+ f(self)
+ }
+
+ fn emit_enum_struct_variant<F>(&mut self, v_name: &str, v_id: usize, len: usize, f: F)
+ -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>
{
self.emit_enum_variant(v_name, v_id, len, f)
}
- fn emit_enum_struct_variant_field<F>(&mut self,
- _f_name: &str,
- f_idx: usize,
- f: F) -> Result<(), Self::Error>
- where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+
+ fn emit_enum_struct_variant_field<F>(&mut self, _f_name: &str, f_idx: usize, f: F)
+ -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>
{
self.emit_enum_variant_arg(f_idx, f)
}
- fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F)
- -> Result<(), Self::Error>
- where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
+ fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error>
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+ {
+ f(self)
+ }
+
fn emit_struct_field<F>(&mut self, _f_name: &str, _f_idx: usize, f: F)
- -> Result<(), Self::Error>
- where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
+ -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+ {
+ f(self)
+ }
fn emit_tuple<F>(&mut self, _len: usize, f: F) -> Result<(), Self::Error>
- where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+ {
+ f(self)
+ }
+
fn emit_tuple_arg<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
- where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+ {
+ f(self)
+ }
- fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F)
- -> Result<(), Self::Error>
+ fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> Result<(), Self::Error>
where F: FnOnce(&mut Self) -> Result<(), Self::Error>
{
self.emit_tuple(len, f)
}
- fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F)
- -> Result<(), Self::Error>
+
+ fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F) -> Result<(), Self::Error>
where F: FnOnce(&mut Self) -> Result<(), Self::Error>
{
self.emit_tuple_arg(f_idx, f)
{
self.emit_enum("Option", f)
}
+
fn emit_option_none(&mut self) -> Result<(), Self::Error> {
self.emit_enum_variant("None", 0, 0, |_| Ok(()))
}
+
fn emit_option_some<F>(&mut self, f: F) -> Result<(), Self::Error>
where F: FnOnce(&mut Self) -> Result<(), Self::Error>
{
-
self.emit_enum_variant("Some", 1, 1, f)
}
self.emit_usize(len)?;
f(self)
}
+
fn emit_seq_elt<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
- where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+ {
+ f(self)
+ }
fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error>
where F: FnOnce(&mut Self) -> Result<(), Self::Error>
self.emit_usize(len)?;
f(self)
}
+
fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
- where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+ {
+ f(self)
+ }
+
fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
- where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) }
+ where F: FnOnce(&mut Self) -> Result<(), Self::Error>
+ {
+ f(self)
+ }
}
pub trait Decoder {
// Compound types:
fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
- where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+ {
+ f(self)
+ }
- fn read_enum_variant<T, F>(&mut self, _names: &[&str], mut f: F)
- -> Result<T, Self::Error>
+ fn read_enum_variant<T, F>(&mut self, _names: &[&str], mut f: F) -> Result<T, Self::Error>
where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
{
let disr = self.read_usize()?;
f(self, disr)
}
- fn read_enum_variant_arg<T, F>(&mut self, _a_idx: usize, f: F)
- -> Result<T, Self::Error>
- where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
- fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F)
- -> Result<T, Self::Error>
+ fn read_enum_variant_arg<T, F>(&mut self, _a_idx: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+ {
+ f(self)
+ }
+
+ fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error>
where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
{
self.read_enum_variant(names, f)
}
- fn read_enum_struct_variant_field<T, F>(&mut self,
- _f_name: &str,
- f_idx: usize,
- f: F)
- -> Result<T, Self::Error>
- where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+
+ fn read_enum_struct_variant_field<T, F>(&mut self, _f_name: &str, f_idx: usize, f: F)
+ -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error>
{
self.read_enum_variant_arg(f_idx, f)
}
- fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F)
- -> Result<T, Self::Error>
- where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
- fn read_struct_field<T, F>(&mut self,
- _f_name: &str,
- _f_idx: usize,
- f: F)
- -> Result<T, Self::Error>
- where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
+ fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+ {
+ f(self)
+ }
+
+ fn read_struct_field<T, F>(&mut self, _f_name: &str, _f_idx: usize, f: F)
+ -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+ {
+ f(self)
+ }
fn read_tuple<T, F>(&mut self, _len: usize, f: F) -> Result<T, Self::Error>
- where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
- fn read_tuple_arg<T, F>(&mut self, _a_idx: usize, f: F)
- -> Result<T, Self::Error>
- where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+ {
+ f(self)
+ }
+
+ fn read_tuple_arg<T, F>(&mut self, _a_idx: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+ {
+ f(self)
+ }
- fn read_tuple_struct<T, F>(&mut self, _s_name: &str, len: usize, f: F)
- -> Result<T, Self::Error>
+ fn read_tuple_struct<T, F>(&mut self, _s_name: &str, len: usize, f: F) -> Result<T, Self::Error>
where F: FnOnce(&mut Self) -> Result<T, Self::Error>
{
self.read_tuple(len, f)
}
- fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F)
- -> Result<T, Self::Error>
+
+ fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error>
where F: FnOnce(&mut Self) -> Result<T, Self::Error>
{
self.read_tuple_arg(a_idx, f)
let len = self.read_usize()?;
f(self, len)
}
+
fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
- where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+ {
+ f(self)
+ }
fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>
let len = self.read_usize()?;
f(self, len)
}
- fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F)
- -> Result<T, Self::Error>
- where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
- fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F)
- -> Result<T, Self::Error>
- where F: FnOnce(&mut Self) -> Result<T, Self::Error> { f(self) }
+
+ fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+ {
+ f(self)
+ }
+
+ fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+ where F: FnOnce(&mut Self) -> Result<T, Self::Error>
+ {
+ f(self)
+ }
// Failure
fn error(&mut self, err: &str) -> Self::Error;
}
}
-impl<'a, T:Encodable> Encodable for Cow<'a, [T]>
-where [T]: ToOwned<Owned = Vec<T>>
-{
+impl<'a, T:Encodable> Encodable for Cow<'a, [T]> where [T]: ToOwned<Owned = Vec<T>> {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_seq(self.len(), |s| {
for (i, e) in self.iter().enumerate() {
}
}
-impl<T:Decodable+ToOwned> Decodable for Cow<'static, [T]>
-where [T]: ToOwned<Owned = Vec<T>>
-{
+impl<T:Decodable+ToOwned> Decodable for Cow<'static, [T]> where [T]: ToOwned<Owned = Vec<T>> {
fn decode<D: Decoder>(d: &mut D) -> Result<Cow<'static, [T]>, D::Error> {
d.read_seq(|d, len| {
let mut v = Vec::with_capacity(len);
let len: usize = count_idents!($($name,)*);
d.read_tuple(len, |d| {
let mut i = 0;
- let ret = ($(d.read_tuple_arg({ i+=1; i-1 },
- |d| -> Result<$name,D::Error> {
+ let ret = ($(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name, D::Error> {
Decodable::decode(d)
})?,)*);
Ok(ret)
/// `T` is the type being encoded/decoded, and
/// the arguments are the names of the trait
/// and method that should've been overridden.
- fn not_found<S, T: ?Sized>(trait_name: &'static str,
- method_name: &'static str) -> Self;
+ fn not_found<S, T: ?Sized>(trait_name: &'static str, method_name: &'static str) -> Self;
}
impl<E> SpecializationError for E {
- default fn not_found<S, T: ?Sized>(trait_name: &'static str,
- method_name: &'static str) -> E {
+ default fn not_found<S, T: ?Sized>(trait_name: &'static str, method_name: &'static str) -> E {
panic!("missing specialization: `<{} as {}<{}>>::{}` not overridden",
unsafe { intrinsics::type_name::<S>() },
trait_name,
libc = { path = "../rustc/libc_shim" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
profiler_builtins = { path = "../libprofiler_builtins", optional = true }
-std_unicode = { path = "../libstd_unicode" }
unwind = { path = "../libunwind" }
[dev-dependencies]
#[cfg(not(test))]
#[doc(hidden)]
-#[cfg_attr(stage0, lang = "oom")]
-#[cfg_attr(not(stage0), alloc_error_handler)]
+#[alloc_error_handler]
#[unstable(feature = "alloc_internals", issue = "0")]
pub fn rust_oom(layout: Layout) -> ! {
let hook = HOOK.load(Ordering::SeqCst);
/// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase
#[stable(feature = "ascii", since = "1.9.0")]
fn make_ascii_lowercase(&mut self);
-
- /// Checks if the value is an ASCII alphabetic character:
- /// U+0041 'A' ... U+005A 'Z' or U+0061 'a' ... U+007A 'z'.
- /// For strings, true if all characters in the string are
- /// ASCII alphabetic.
- ///
- /// # Note
- ///
- /// This method will be deprecated in favor of the identically-named
- /// inherent methods on `u8` and `char`.
- /// For `[u8]` use `.iter().all(u8::is_ascii_alphabetic)`.
- /// For `str` use `.bytes().all(u8::is_ascii_alphabetic)`.
- #[unstable(feature = "ascii_ctype", issue = "39658")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); }
-
- /// Checks if the value is an ASCII uppercase character:
- /// U+0041 'A' ... U+005A 'Z'.
- /// For strings, true if all characters in the string are
- /// ASCII uppercase.
- ///
- /// # Note
- ///
- /// This method will be deprecated in favor of the identically-named
- /// inherent methods on `u8` and `char`.
- /// For `[u8]` use `.iter().all(u8::is_ascii_uppercase)`.
- /// For `str` use `.bytes().all(u8::is_ascii_uppercase)`.
- #[unstable(feature = "ascii_ctype", issue = "39658")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- fn is_ascii_uppercase(&self) -> bool { unimplemented!(); }
-
- /// Checks if the value is an ASCII lowercase character:
- /// U+0061 'a' ... U+007A 'z'.
- /// For strings, true if all characters in the string are
- /// ASCII lowercase.
- ///
- /// # Note
- ///
- /// This method will be deprecated in favor of the identically-named
- /// inherent methods on `u8` and `char`.
- /// For `[u8]` use `.iter().all(u8::is_ascii_lowercase)`.
- /// For `str` use `.bytes().all(u8::is_ascii_lowercase)`.
- #[unstable(feature = "ascii_ctype", issue = "39658")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- fn is_ascii_lowercase(&self) -> bool { unimplemented!(); }
-
- /// Checks if the value is an ASCII alphanumeric character:
- /// U+0041 'A' ... U+005A 'Z', U+0061 'a' ... U+007A 'z', or
- /// U+0030 '0' ... U+0039 '9'.
- /// For strings, true if all characters in the string are
- /// ASCII alphanumeric.
- ///
- /// # Note
- ///
- /// This method will be deprecated in favor of the identically-named
- /// inherent methods on `u8` and `char`.
- /// For `[u8]` use `.iter().all(u8::is_ascii_alphanumeric)`.
- /// For `str` use `.bytes().all(u8::is_ascii_alphanumeric)`.
- #[unstable(feature = "ascii_ctype", issue = "39658")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); }
-
- /// Checks if the value is an ASCII decimal digit:
- /// U+0030 '0' ... U+0039 '9'.
- /// For strings, true if all characters in the string are
- /// ASCII digits.
- ///
- /// # Note
- ///
- /// This method will be deprecated in favor of the identically-named
- /// inherent methods on `u8` and `char`.
- /// For `[u8]` use `.iter().all(u8::is_ascii_digit)`.
- /// For `str` use `.bytes().all(u8::is_ascii_digit)`.
- #[unstable(feature = "ascii_ctype", issue = "39658")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- fn is_ascii_digit(&self) -> bool { unimplemented!(); }
-
- /// Checks if the value is an ASCII hexadecimal digit:
- /// U+0030 '0' ... U+0039 '9', U+0041 'A' ... U+0046 'F', or
- /// U+0061 'a' ... U+0066 'f'.
- /// For strings, true if all characters in the string are
- /// ASCII hex digits.
- ///
- /// # Note
- ///
- /// This method will be deprecated in favor of the identically-named
- /// inherent methods on `u8` and `char`.
- /// For `[u8]` use `.iter().all(u8::is_ascii_hexdigit)`.
- /// For `str` use `.bytes().all(u8::is_ascii_hexdigit)`.
- #[unstable(feature = "ascii_ctype", issue = "39658")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); }
-
- /// Checks if the value is an ASCII punctuation character:
- ///
- /// U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`
- /// U+003A ... U+0040 `: ; < = > ? @`
- /// U+005B ... U+0060 ``[ \\ ] ^ _ ` ``
- /// U+007B ... U+007E `{ | } ~`
- ///
- /// For strings, true if all characters in the string are
- /// ASCII punctuation.
- ///
- /// # Note
- ///
- /// This method will be deprecated in favor of the identically-named
- /// inherent methods on `u8` and `char`.
- /// For `[u8]` use `.iter().all(u8::is_ascii_punctuation)`.
- /// For `str` use `.bytes().all(u8::is_ascii_punctuation)`.
- #[unstable(feature = "ascii_ctype", issue = "39658")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- fn is_ascii_punctuation(&self) -> bool { unimplemented!(); }
-
- /// Checks if the value is an ASCII graphic character:
- /// U+0021 '!' ... U+007E '~'.
- /// For strings, true if all characters in the string are
- /// ASCII graphic characters.
- ///
- /// # Note
- ///
- /// This method will be deprecated in favor of the identically-named
- /// inherent methods on `u8` and `char`.
- /// For `[u8]` use `.iter().all(u8::is_ascii_graphic)`.
- /// For `str` use `.bytes().all(u8::is_ascii_graphic)`.
- #[unstable(feature = "ascii_ctype", issue = "39658")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- fn is_ascii_graphic(&self) -> bool { unimplemented!(); }
-
- /// Checks if the value is an ASCII whitespace character:
- /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED,
- /// U+000C FORM FEED, or U+000D CARRIAGE RETURN.
- /// For strings, true if all characters in the string are
- /// ASCII whitespace.
- ///
- /// Rust uses the WhatWG Infra Standard's [definition of ASCII
- /// whitespace][infra-aw]. There are several other definitions in
- /// wide use. For instance, [the POSIX locale][pct] includes
- /// U+000B VERTICAL TAB as well as all the above characters,
- /// but—from the very same specification—[the default rule for
- /// "field splitting" in the Bourne shell][bfs] considers *only*
- /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace.
- ///
- /// If you are writing a program that will process an existing
- /// file format, check what that format's definition of whitespace is
- /// before using this function.
- ///
- /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace
- /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
- /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
- ///
- /// # Note
- ///
- /// This method will be deprecated in favor of the identically-named
- /// inherent methods on `u8` and `char`.
- /// For `[u8]` use `.iter().all(u8::is_ascii_whitespace)`.
- /// For `str` use `.bytes().all(u8::is_ascii_whitespace)`.
- #[unstable(feature = "ascii_ctype", issue = "39658")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- fn is_ascii_whitespace(&self) -> bool { unimplemented!(); }
-
- /// Checks if the value is an ASCII control character:
- /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE.
- /// Note that most ASCII whitespace characters are control
- /// characters, but SPACE is not.
- ///
- /// # Note
- ///
- /// This method will be deprecated in favor of the identically-named
- /// inherent methods on `u8` and `char`.
- /// For `[u8]` use `.iter().all(u8::is_ascii_control)`.
- /// For `str` use `.bytes().all(u8::is_ascii_control)`.
- #[unstable(feature = "ascii_ctype", issue = "39658")]
- #[rustc_deprecated(since = "1.26.0", reason = "use inherent methods instead")]
- fn is_ascii_control(&self) -> bool { unimplemented!(); }
}
macro_rules! delegating_ascii_methods {
}
}
-macro_rules! delegating_ascii_ctype_methods {
- () => {
- #[inline]
- fn is_ascii_alphabetic(&self) -> bool { self.is_ascii_alphabetic() }
-
- #[inline]
- fn is_ascii_uppercase(&self) -> bool { self.is_ascii_uppercase() }
-
- #[inline]
- fn is_ascii_lowercase(&self) -> bool { self.is_ascii_lowercase() }
-
- #[inline]
- fn is_ascii_alphanumeric(&self) -> bool { self.is_ascii_alphanumeric() }
-
- #[inline]
- fn is_ascii_digit(&self) -> bool { self.is_ascii_digit() }
-
- #[inline]
- fn is_ascii_hexdigit(&self) -> bool { self.is_ascii_hexdigit() }
-
- #[inline]
- fn is_ascii_punctuation(&self) -> bool { self.is_ascii_punctuation() }
-
- #[inline]
- fn is_ascii_graphic(&self) -> bool { self.is_ascii_graphic() }
-
- #[inline]
- fn is_ascii_whitespace(&self) -> bool { self.is_ascii_whitespace() }
-
- #[inline]
- fn is_ascii_control(&self) -> bool { self.is_ascii_control() }
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
impl AsciiExt for u8 {
type Owned = u8;
delegating_ascii_methods!();
- delegating_ascii_ctype_methods!();
}
#[stable(feature = "rust1", since = "1.0.0")]
type Owned = char;
delegating_ascii_methods!();
- delegating_ascii_ctype_methods!();
}
#[stable(feature = "rust1", since = "1.0.0")]
type Owned = Vec<u8>;
delegating_ascii_methods!();
-
- #[inline]
- fn is_ascii_alphabetic(&self) -> bool {
- self.iter().all(|b| b.is_ascii_alphabetic())
- }
-
- #[inline]
- fn is_ascii_uppercase(&self) -> bool {
- self.iter().all(|b| b.is_ascii_uppercase())
- }
-
- #[inline]
- fn is_ascii_lowercase(&self) -> bool {
- self.iter().all(|b| b.is_ascii_lowercase())
- }
-
- #[inline]
- fn is_ascii_alphanumeric(&self) -> bool {
- self.iter().all(|b| b.is_ascii_alphanumeric())
- }
-
- #[inline]
- fn is_ascii_digit(&self) -> bool {
- self.iter().all(|b| b.is_ascii_digit())
- }
-
- #[inline]
- fn is_ascii_hexdigit(&self) -> bool {
- self.iter().all(|b| b.is_ascii_hexdigit())
- }
-
- #[inline]
- fn is_ascii_punctuation(&self) -> bool {
- self.iter().all(|b| b.is_ascii_punctuation())
- }
-
- #[inline]
- fn is_ascii_graphic(&self) -> bool {
- self.iter().all(|b| b.is_ascii_graphic())
- }
-
- #[inline]
- fn is_ascii_whitespace(&self) -> bool {
- self.iter().all(|b| b.is_ascii_whitespace())
- }
-
- #[inline]
- fn is_ascii_control(&self) -> bool {
- self.iter().all(|b| b.is_ascii_control())
- }
}
#[stable(feature = "rust1", since = "1.0.0")]
type Owned = String;
delegating_ascii_methods!();
-
- #[inline]
- fn is_ascii_alphabetic(&self) -> bool {
- self.bytes().all(|b| b.is_ascii_alphabetic())
- }
-
- #[inline]
- fn is_ascii_uppercase(&self) -> bool {
- self.bytes().all(|b| b.is_ascii_uppercase())
- }
-
- #[inline]
- fn is_ascii_lowercase(&self) -> bool {
- self.bytes().all(|b| b.is_ascii_lowercase())
- }
-
- #[inline]
- fn is_ascii_alphanumeric(&self) -> bool {
- self.bytes().all(|b| b.is_ascii_alphanumeric())
- }
-
- #[inline]
- fn is_ascii_digit(&self) -> bool {
- self.bytes().all(|b| b.is_ascii_digit())
- }
-
- #[inline]
- fn is_ascii_hexdigit(&self) -> bool {
- self.bytes().all(|b| b.is_ascii_hexdigit())
- }
-
- #[inline]
- fn is_ascii_punctuation(&self) -> bool {
- self.bytes().all(|b| b.is_ascii_punctuation())
- }
-
- #[inline]
- fn is_ascii_graphic(&self) -> bool {
- self.bytes().all(|b| b.is_ascii_graphic())
- }
-
- #[inline]
- fn is_ascii_whitespace(&self) -> bool {
- self.bytes().all(|b| b.is_ascii_whitespace())
- }
-
- #[inline]
- fn is_ascii_control(&self) -> bool {
- self.bytes().all(|b| b.is_ascii_control())
- }
}
#[stable(feature = "cstring_into", since = "1.7.0")]
impl From<CString> for Vec<u8> {
+ /// Converts a [`CString`] into a [`Vec`]`<u8>`.
+ ///
+ /// The conversion consumes the [`CString`], and removes the terminating NUL byte.
+ ///
+ /// [`Vec`]: ../vec/struct.Vec.html
+ /// [`CString`]: ../ffi/struct.CString.html
#[inline]
fn from(s: CString) -> Vec<u8> {
s.into_bytes()
#[stable(feature = "c_string_from_box", since = "1.18.0")]
impl From<Box<CStr>> for CString {
+ /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
+ ///
+ /// [`Box`]: ../boxed/struct.Box.html
+ /// [`CString`]: ../ffi/struct.CString.html
#[inline]
fn from(s: Box<CStr>) -> CString {
s.into_c_string()
#[stable(feature = "box_from_c_string", since = "1.20.0")]
impl From<CString> for Box<CStr> {
+ /// Converts a [`CString`] into a [`Box`]`<CStr>` without copying or allocating.
+ ///
+ /// [`CString`]: ../ffi/struct.CString.html
+ /// [`Box`]: ../boxed/struct.Box.html
#[inline]
fn from(s: CString) -> Box<CStr> {
s.into_boxed_c_str()
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<CString> for Arc<CStr> {
+ /// Converts a [`CString`] into a [`Arc`]`<CStr>` without copying or allocating.
+ ///
+ /// [`CString`]: ../ffi/struct.CString.html
+ /// [`Arc`]: ../sync/struct.Arc.html
#[inline]
fn from(s: CString) -> Arc<CStr> {
let arc: Arc<[u8]> = Arc::from(s.into_inner());
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<CString> for Rc<CStr> {
+ /// Converts a [`CString`] into a [`Rc`]`<CStr>` without copying or allocating.
+ ///
+ /// [`CString`]: ../ffi/struct.CString.html
+ /// [`Rc`]: ../rc/struct.Rc.html
#[inline]
fn from(s: CString) -> Rc<CStr> {
let rc: Rc<[u8]> = Rc::from(s.into_inner());
#[stable(feature = "rust1", since = "1.0.0")]
impl From<NulError> for io::Error {
+ /// Converts a [`NulError`] into a [`io::Error`].
+ ///
+ /// [`NulError`]: ../ffi/struct.NulError.html
+ /// [`io::Error`]: ../io/struct.Error.html
fn from(_: NulError) -> io::Error {
io::Error::new(io::ErrorKind::InvalidInput,
"data provided contains a nul byte")
#[stable(feature = "rust1", since = "1.0.0")]
impl From<String> for OsString {
+ /// Converts a [`String`] into a [`OsString`].
+ ///
+ /// The conversion copies the data, and includes an allocation on the heap.
+ ///
+ /// [`String`]: ../string/struct.String.html
+ /// [`OsString`]: struct.OsString.html
fn from(s: String) -> OsString {
OsString { inner: Buf::from_string(s) }
}
#[stable(feature = "os_string_from_box", since = "1.18.0")]
impl From<Box<OsStr>> for OsString {
+ /// Converts a `Box<OsStr>` into a `OsString` without copying or allocating.
+ ///
+ /// [`Box`]: ../boxed/struct.Box.html
+ /// [`OsString`]: ../ffi/struct.OsString.html
fn from(boxed: Box<OsStr>) -> OsString {
boxed.into_os_string()
}
#[stable(feature = "box_from_os_string", since = "1.20.0")]
impl From<OsString> for Box<OsStr> {
+ /// Converts a [`OsString`] into a [`Box`]`<OsStr>` without copying or allocating.
+ ///
+ /// [`Box`]: ../boxed/struct.Box.html
+ /// [`OsString`]: ../ffi/struct.OsString.html
fn from(s: OsString) -> Box<OsStr> {
s.into_boxed_os_str()
}
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<OsString> for Arc<OsStr> {
+ /// Converts a [`OsString`] into a [`Arc`]`<OsStr>` without copying or allocating.
+ ///
+ /// [`Arc`]: ../sync/struct.Arc.html
+ /// [`OsString`]: ../ffi/struct.OsString.html
#[inline]
fn from(s: OsString) -> Arc<OsStr> {
let arc = s.inner.into_arc();
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<OsString> for Rc<OsStr> {
+ /// Converts a [`OsString`] into a [`Rc`]`<OsStr>` without copying or allocating.
+ ///
+ /// [`Rc`]: ../rc/struct.Rc.html
+ /// [`OsString`]: ../ffi/struct.OsString.html
#[inline]
fn from(s: OsString) -> Rc<OsStr> {
let rc = s.inner.into_rc();
#[unstable(feature = "gen_future", issue = "50547")]
/// Polls a future in the current thread-local task context.
-pub fn poll_in_task_cx<F>(f: &mut PinMut<F>) -> Poll<F::Output>
+pub fn poll_in_task_cx<F>(f: PinMut<F>) -> Poll<F::Output>
where
F: Future
{
- get_task_cx(|cx| f.reborrow().poll(cx))
+ get_task_cx(|cx| f.poll(cx))
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
- /// Returns `true` if there are no bytes in the internal buffer.
- ///
- /// # Examples
- //
- /// ```no_run
- /// # #![feature(bufreader_is_empty)]
- /// use std::io::BufReader;
- /// use std::io::BufRead;
- /// use std::fs::File;
- ///
- /// fn main() -> std::io::Result<()> {
- /// let f1 = File::open("log.txt")?;
- /// let mut reader = BufReader::new(f1);
- /// assert!(reader.is_empty());
- ///
- /// if reader.fill_buf()?.len() > 0 {
- /// assert!(!reader.is_empty());
- /// }
- /// Ok(())
- /// }
- /// ```
- #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")]
- #[rustc_deprecated(since = "1.26.0", reason = "use .buffer().is_empty() instead")]
- pub fn is_empty(&self) -> bool {
- self.buffer().is_empty()
- }
-
/// Returns a reference to the internally buffered data.
///
/// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty.
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
- #[test]
- #[allow(deprecated)]
- fn read_char_buffered() {
- let buf = [195, 159];
- let reader = BufReader::with_capacity(1, &buf[..]);
- assert_eq!(reader.chars().next().unwrap().unwrap(), 'ß');
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_chars() {
- let buf = [195, 159, b'a'];
- let reader = BufReader::with_capacity(1, &buf[..]);
- let mut it = reader.chars();
- assert_eq!(it.next().unwrap().unwrap(), 'ß');
- assert_eq!(it.next().unwrap().unwrap(), 'a');
- assert!(it.next().is_none());
- }
-
#[test]
#[should_panic]
fn dont_panic_in_drop_on_panicked_flush() {
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
- #[test]
- #[allow(deprecated)]
- fn test_read_char() {
- let b = &b"Vi\xE1\xBB\x87t"[..];
- let mut c = Cursor::new(b).chars();
- assert_eq!(c.next().unwrap().unwrap(), 'V');
- assert_eq!(c.next().unwrap().unwrap(), 'i');
- assert_eq!(c.next().unwrap().unwrap(), 'ệ');
- assert_eq!(c.next().unwrap().unwrap(), 't');
- assert!(c.next().is_none());
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_read_bad_char() {
- let b = &b"\x80"[..];
- let mut c = Cursor::new(b).chars();
- assert!(c.next().unwrap().is_err());
- }
-
#[test]
fn seek_past_end() {
let buf = [0xff];
#![stable(feature = "rust1", since = "1.0.0")]
use cmp;
-use core::str as core_str;
-use error as std_error;
use fmt;
-use result;
use str;
use memchr;
use ptr;
// avoid paying to allocate and zero a huge chunk of memory if the reader only
// has 4 bytes while still making large reads if the reader does have a ton
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
-// time is 4,500 times (!) slower than this if the reader has a very small
-// amount of data to return.
+// time is 4,500 times (!) slower than a default reservation size of 32 if the
+// reader has a very small amount of data to return.
//
// Because we're extending the buffer with uninitialized data for trusted
// readers, we need to make sure to truncate that if any of this panics.
fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
+ read_to_end_with_reservation(r, buf, 32)
+}
+
+fn read_to_end_with_reservation<R: Read + ?Sized>(r: &mut R,
+ buf: &mut Vec<u8>,
+ reservation_size: usize) -> Result<usize>
+{
let start_len = buf.len();
let mut g = Guard { len: buf.len(), buf: buf };
let ret;
loop {
if g.len == g.buf.len() {
unsafe {
- g.buf.reserve(32);
+ g.buf.reserve(reservation_size);
let capacity = g.buf.capacity();
g.buf.set_len(capacity);
r.initializer().initialize(&mut g.buf[g.len..]);
Bytes { inner: self }
}
- /// Transforms this `Read` instance to an [`Iterator`] over [`char`]s.
- ///
- /// This adaptor will attempt to interpret this reader as a UTF-8 encoded
- /// sequence of characters. The returned iterator will return [`None`] once
- /// EOF is reached for this reader. Otherwise each element yielded will be a
- /// [`Result`]`<`[`char`]`, E>` where `E` may contain information about what I/O error
- /// occurred or where decoding failed.
- ///
- /// Currently this adaptor will discard intermediate data read, and should
- /// be avoided if this is not desired.
- ///
- /// # Examples
- ///
- /// [`File`]s implement `Read`:
- ///
- /// [`File`]: ../fs/struct.File.html
- /// [`Iterator`]: ../../std/iter/trait.Iterator.html
- /// [`Result`]: ../../std/result/enum.Result.html
- /// [`char`]: ../../std/primitive.char.html
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
- /// ```no_run
- /// #![feature(io)]
- /// use std::io;
- /// use std::io::prelude::*;
- /// use std::fs::File;
- ///
- /// fn main() -> io::Result<()> {
- /// let mut f = File::open("foo.txt")?;
- ///
- /// for c in f.chars() {
- /// println!("{}", c.unwrap());
- /// }
- /// Ok(())
- /// }
- /// ```
- #[unstable(feature = "io", reason = "the semantics of a partial read/write \
- of where errors happen is currently \
- unclear and may change",
- issue = "27802")]
- #[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
- #[allow(deprecated)]
- fn chars(self) -> Chars<Self> where Self: Sized {
- Chars { inner: self }
- }
-
/// Creates an adaptor which will chain this stream with another.
///
/// The returned `Read` instance will first read all bytes from this object
unsafe fn initializer(&self) -> Initializer {
self.inner.initializer()
}
+
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
+ let reservation_size = cmp::min(self.limit, 32) as usize;
+
+ read_to_end_with_reservation(self, buf, reservation_size)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/// An iterator over the `char`s of a reader.
-///
-/// This struct is generally created by calling [`chars`][chars] on a reader.
-/// Please see the documentation of `chars()` for more details.
-///
-/// [chars]: trait.Read.html#method.chars
-#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
- issue = "27802")]
-#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
-#[derive(Debug)]
-#[allow(deprecated)]
-pub struct Chars<R> {
- inner: R,
-}
-
-/// An enumeration of possible errors that can be generated from the `Chars`
-/// adapter.
-#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
- issue = "27802")]
-#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
-#[derive(Debug)]
-#[allow(deprecated)]
-pub enum CharsError {
- /// Variant representing that the underlying stream was read successfully
- /// but it did not contain valid utf8 data.
- NotUtf8,
-
- /// Variant representing that an I/O error occurred.
- Other(Error),
-}
-
-#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
- issue = "27802")]
-#[allow(deprecated)]
-impl<R: Read> Iterator for Chars<R> {
- type Item = result::Result<char, CharsError>;
-
- fn next(&mut self) -> Option<result::Result<char, CharsError>> {
- let first_byte = match read_one_byte(&mut self.inner)? {
- Ok(b) => b,
- Err(e) => return Some(Err(CharsError::Other(e))),
- };
- let width = core_str::utf8_char_width(first_byte);
- if width == 1 { return Some(Ok(first_byte as char)) }
- if width == 0 { return Some(Err(CharsError::NotUtf8)) }
- let mut buf = [first_byte, 0, 0, 0];
- {
- let mut start = 1;
- while start < width {
- match self.inner.read(&mut buf[start..width]) {
- Ok(0) => return Some(Err(CharsError::NotUtf8)),
- Ok(n) => start += n,
- Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
- Err(e) => return Some(Err(CharsError::Other(e))),
- }
- }
- }
- Some(match str::from_utf8(&buf[..width]).ok() {
- Some(s) => Ok(s.chars().next().unwrap()),
- None => Err(CharsError::NotUtf8),
- })
- }
-}
-
-#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
- issue = "27802")]
-#[allow(deprecated)]
-impl std_error::Error for CharsError {
- fn description(&self) -> &str {
- match *self {
- CharsError::NotUtf8 => "invalid utf8 encoding",
- CharsError::Other(ref e) => std_error::Error::description(e),
- }
- }
- fn cause(&self) -> Option<&dyn std_error::Error> {
- match *self {
- CharsError::NotUtf8 => None,
- CharsError::Other(ref e) => e.cause(),
- }
- }
-}
-
-#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
- issue = "27802")]
-#[allow(deprecated)]
-impl fmt::Display for CharsError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- CharsError::NotUtf8 => {
- "byte stream did not contain valid utf8".fmt(f)
- }
- CharsError::Other(ref e) => e.fmt(f),
- }
- }
-}
-
/// An iterator over the contents of an instance of `BufRead` split on a
/// particular byte.
///
macro_rules! println {
() => (print!("\n"));
($($arg:tt)*) => ({
- #[cfg(not(stage0))] {
- ($crate::io::_print(format_args_nl!($($arg)*)));
- }
- #[cfg(stage0)] {
- print!("{}\n", format_args!($($arg)*))
- }
+ $crate::io::_print(format_args_nl!($($arg)*));
})
}
macro_rules! eprintln {
() => (eprint!("\n"));
($($arg:tt)*) => ({
- #[cfg(all(not(stage0), not(stage1)))] {
- ($crate::io::_eprint(format_args_nl!($($arg)*)));
- }
- #[cfg(any(stage0, stage1))] {
- eprint!("{}\n", format_args!($($arg)*))
- }
+ $crate::io::_eprint(format_args_nl!($($arg)*));
})
}
macro_rules! await {
($e:expr) => { {
let mut pinned = $e;
- let mut pinned = unsafe { $crate::mem::PinMut::new_unchecked(&mut pinned) };
loop {
- match $crate::future::poll_in_task_cx(&mut pinned) {
- // FIXME(cramertj) prior to stabilizing await, we have to ensure that this
- // can't be used to create a generator on stable via `|| await!()`.
- $crate::task::Poll::Pending => yield,
- $crate::task::Poll::Ready(x) => break x,
+ if let $crate::task::Poll::Ready(x) =
+ $crate::future::poll_in_task_cx(unsafe {
+ $crate::mem::PinMut::new_unchecked(&mut pinned)
+ })
+ {
+ break x;
}
+ // FIXME(cramertj) prior to stabilizing await, we have to ensure that this
+ // can't be used to create a generator on stable via `|| await!()`.
+ yield
}
} }
}
--- /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.
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use libc;
+
+use fs::Metadata;
+use sys_common::AsInner;
+
+#[allow(deprecated)]
+use os::hermit::raw;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Gain a reference to the underlying `stat` structure which contains
+ /// the raw information returned by the OS.
+ ///
+ /// The contents of the returned [`stat`] are **not** consistent across
+ /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
+ /// cross-Unix abstractions contained within the raw stat.
+ ///
+ /// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// let stat = meta.as_raw_stat();
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ #[rustc_deprecated(since = "1.8.0",
+ reason = "deprecated in favor of the accessor \
+ methods of this trait")]
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat;
+
+ /// Returns the device ID on which this file resides.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_dev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ino());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ /// Returns the file type and mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mode());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ /// Returns the number of hard links to file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_nlink());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ /// Returns the user ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_uid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ /// Returns the group ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_gid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ /// Returns the device ID that this file represents. Only relevant for special file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_rdev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+ ///
+ /// The size of a symbolic link is the length of the pathname it contains,
+ /// without a terminating null byte.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_size());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ /// Returns the last access time.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ /// Returns the last access time, nano seconds part.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ /// Returns the last modification time.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ /// Returns the last modification time, nano seconds part.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ /// Returns the last status change time.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ /// Returns the last status change time, nano seconds part.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ /// Returns the "preferred" blocksize for efficient filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blksize());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, 512-byte units.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::linux::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blocks());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ #[allow(deprecated)]
+ fn as_raw_stat(&self) -> &raw::stat {
+ unsafe {
+ &*(self.as_inner().as_inner() as *const libc::stat64
+ as *const raw::stat)
+ }
+ }
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
--- /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.
+
+//! HermitCore-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
--- /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.
+
+//! HermitCore-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![rustc_deprecated(since = "1.8.0",
+ reason = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions")]
+#![allow(deprecated)]
+#![allow(missing_debug_implementations)]
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub use libc::pthread_t;
+
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use libc::{dev_t, mode_t, off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
#[cfg(target_os = "solaris")] pub mod solaris;
#[cfg(target_os = "emscripten")] pub mod emscripten;
#[cfg(target_os = "fuchsia")] pub mod fuchsia;
+ #[cfg(target_os = "hermit")] pub mod hermit;
#[cfg(any(target_os = "redox", unix))]
#[stable(feature = "rust1", since = "1.0.0")]
/// happens-before relation between the closure and code executing after the
/// return).
///
+ /// If the given closure recusively invokes `call_once` on the same `Once`
+ /// instance the exact behavior is not specified, allowed outcomes are
+ /// a panic or a deadlock.
+ ///
/// # Examples
///
/// ```
target_os = "emscripten",
target_os = "haiku",
target_os = "l4re",
- target_os = "fuchsia"))]
+ target_os = "fuchsia",
+ target_os = "hermit"))]
mod imp {
use os::unix::prelude::*;
use ptr;
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "l4re",
- target_os = "android"))]
+ target_os = "android",
+ target_os = "hermit"))]
pub unsafe fn init(&mut self) {}
#[cfg(not(any(target_os = "macos",
target_os = "ios",
target_os = "l4re",
- target_os = "android")))]
+ target_os = "android",
+ target_os = "hermit")))]
pub unsafe fn init(&mut self) {
use mem;
let mut attr: libc::pthread_condattr_t = mem::uninitialized();
// where we configure condition variable to use monotonic clock (instead of
// default system clock). This approach avoids all problems that result
// from changes made to the system time.
- #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))]
+ #[cfg(not(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "android",
+ target_os = "hermit")))]
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
use mem;
// This implementation is modeled after libcxx's condition_variable
// https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
// https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android", target_os = "hermit"))]
pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
use ptr;
use time::Instant;
pub const EXE_SUFFIX: &'static str = "";
pub const EXE_EXTENSION: &'static str = "";
}
+
+#[cfg(target_os = "hermit")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "hermit";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
// fallback implementation to use as well.
//
// Due to rust-lang/rust#18804, make sure this is not generic!
-#[cfg(any(target_os = "linux", target_os = "fuchsia"))]
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit"))]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
use libc;
use mem;
lstat(&self.path())
}
- #[cfg(any(target_os = "solaris", target_os = "haiku"))]
+ #[cfg(any(target_os = "solaris", target_os = "haiku", target_os = "hermit"))]
pub fn file_type(&self) -> io::Result<FileType> {
lstat(&self.path()).map(|m| m.file_type())
}
- #[cfg(not(any(target_os = "solaris", target_os = "haiku")))]
+ #[cfg(not(any(target_os = "solaris", target_os = "haiku", target_os = "hermit")))]
pub fn file_type(&self) -> io::Result<FileType> {
match self.entry.d_type {
libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
target_os = "solaris",
target_os = "haiku",
target_os = "l4re",
- target_os = "fuchsia"))]
+ target_os = "fuchsia",
+ target_os = "hermit"))]
pub fn ino(&self) -> u64 {
self.entry.d_ino as u64
}
target_os = "linux",
target_os = "emscripten",
target_os = "l4re",
- target_os = "haiku"))]
+ target_os = "haiku",
+ target_os = "hermit"))]
fn name_bytes(&self) -> &[u8] {
unsafe {
CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
#[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform;
#[cfg(all(not(dox), target_os = "fuchsia"))] pub use os::fuchsia as platform;
#[cfg(all(not(dox), target_os = "l4re"))] pub use os::linux as platform;
+#[cfg(all(not(dox), target_os = "hermit"))] pub use os::hermit as platform;
pub use self::rand::hashmap_random_keys;
pub use libc::strlen;
target_os = "netbsd",
target_os = "openbsd",
target_os = "android",
+ target_os = "hermit",
target_env = "newlib"),
link_name = "__errno")]
#[cfg_attr(target_os = "solaris", link_name = "___errno")]
}
}
-#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
+#[cfg(any(target_os = "fuchsia", target_os = "l4re", target_os = "hermit"))]
pub fn current_exe() -> io::Result<PathBuf> {
use io::ErrorKind;
Err(io::Error::new(ErrorKind::Other, "Not yet implemented!"))
target_os = "solaris",
target_os = "haiku",
target_os = "l4re",
- target_os = "emscripten"))]
+ target_os = "emscripten",
+ target_os = "hermit"))]
pub fn set_name(_name: &CStr) {
// Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.
}
}
}
- #[cfg(not(target_os = "dragonfly"))]
+ #[cfg(not(any(target_os = "dragonfly", target_os = "hermit")))]
pub type clock_t = libc::c_int;
- #[cfg(target_os = "dragonfly")]
+ #[cfg(any(target_os = "dragonfly", target_os = "hermit"))]
pub type clock_t = libc::c_ulong;
fn now(clock: clock_t) -> Timespec {
pub const FD_SETSIZE: usize = 64;
+pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000;
+
#[repr(C)]
#[cfg(not(target_pointer_width = "64"))]
pub struct WSADATA {
let stack_size = (stack + 0xfffe) & (!0xfffe);
let ret = c::CreateThread(ptr::null_mut(), stack_size,
thread_start, &*p as *const _ as *mut _,
- 0, ptr::null_mut());
+ c::STACK_SIZE_PARAM_IS_A_RESERVATION,
+ ptr::null_mut());
return if ret as usize == 0 {
Err(io::Error::last_os_error())
/// specifying a maximum time to block the thread for.
///
/// * The [`unpark`] method on a [`Thread`] atomically makes the token available
-/// if it wasn't already.
+/// if it wasn't already. Because the token is initially absent, [`unpark`]
+/// followed by [`park`] will result in the second call returning immediately.
///
/// In other words, each [`Thread`] acts a bit like a spinlock that can be
/// locked and unlocked using `park` and `unpark`.
/// // Let some time pass for the thread to be spawned.
/// thread::sleep(Duration::from_millis(10));
///
+/// // There is no race condition here, if `unpark`
+/// // happens first, `park` will return immediately.
/// println!("Unpark the thread");
/// parked_thread.thread().unpark();
///
+++ /dev/null
-[package]
-authors = ["The Rust Project Developers"]
-name = "std_unicode"
-version = "0.0.0"
-
-[lib]
-name = "std_unicode"
-path = "lib.rs"
-test = false
-bench = false
-
-[dependencies]
-core = { path = "../libcore" }
-compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! # The Unicode Library
-//!
-//! Unicode-intensive functions for `char` and `str` types.
-//!
-//! This crate provides a collection of Unicode-related functionality,
-//! including decompositions, conversions, etc., and provides traits
-//! implementing these functions for the `char` and `str` types.
-//!
-//! The functionality included here is only that which is necessary to
-//! provide for basic string-related manipulations. This crate does not
-//! (yet) aim to provide a full set of Unicode tables.
-
-#![unstable(feature = "unicode", issue = "27783")]
-#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
- html_root_url = "https://doc.rust-lang.org/nightly/",
- html_playground_url = "https://play.rust-lang.org/",
- issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
- test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
-#![no_std]
-
-#![feature(unicode_internals)]
-#![feature(staged_api)]
-#![rustc_deprecated(since = "1.27.0", reason = "moved into libcore")]
-
-pub use core::unicode::*;
use print::pprust;
use ptr::P;
use rustc_data_structures::indexed_vec;
+use rustc_data_structures::indexed_vec::Idx;
use symbol::{Symbol, keywords};
use tokenstream::{ThinTokenStream, TokenStream};
Inner,
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, PartialOrd, Ord, Copy)]
pub struct AttrId(pub usize);
+impl Idx for AttrId {
+ fn new(idx: usize) -> Self {
+ AttrId(idx)
+ }
+ fn index(self) -> usize {
+ self.0
+ }
+}
+
/// Meta-data associated with an item
/// Doc-comments are promoted to attributes that have is_sugared_doc = true
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub fn mark_used(attr: &Attribute) {
debug!("Marking {:?} as used.", attr);
- let AttrId(id) = attr.id;
GLOBALS.with(|globals| {
- let mut slot = globals.used_attrs.lock();
- let idx = (id / 64) as usize;
- let shift = id % 64;
- if slot.len() <= idx {
- slot.resize(idx + 1, 0);
- }
- slot[idx] |= 1 << shift;
+ globals.used_attrs.lock().insert(attr.id);
});
}
pub fn is_used(attr: &Attribute) -> bool {
- let AttrId(id) = attr.id;
GLOBALS.with(|globals| {
- let slot = globals.used_attrs.lock();
- let idx = (id / 64) as usize;
- let shift = id % 64;
- slot.get(idx).map(|bits| bits & (1 << shift) != 0)
- .unwrap_or(false)
+ globals.used_attrs.lock().contains(attr.id)
})
}
pub fn mark_known(attr: &Attribute) {
debug!("Marking {:?} as known.", attr);
- let AttrId(id) = attr.id;
GLOBALS.with(|globals| {
- let mut slot = globals.known_attrs.lock();
- let idx = (id / 64) as usize;
- let shift = id % 64;
- if slot.len() <= idx {
- slot.resize(idx + 1, 0);
- }
- slot[idx] |= 1 << shift;
+ globals.known_attrs.lock().insert(attr.id);
});
}
pub fn is_known(attr: &Attribute) -> bool {
- let AttrId(id) = attr.id;
GLOBALS.with(|globals| {
- let slot = globals.known_attrs.lock();
- let idx = (id / 64) as usize;
- let shift = id % 64;
- slot.get(idx).map(|bits| bits & (1 << shift) != 0)
- .unwrap_or(false)
+ globals.known_attrs.lock().contains(attr.id)
})
}
-const RUST_KNOWN_TOOL: &[&str] = &["clippy", "rustfmt"];
-const RUST_KNOWN_LINT_TOOL: &[&str] = &["clippy"];
-
-pub fn is_known_tool(attr: &Attribute) -> bool {
- let tool_name =
- attr.path.segments.iter().next().expect("empty path in attribute").ident.name;
- RUST_KNOWN_TOOL.contains(&tool_name.as_str().as_ref())
-}
-
pub fn is_known_lint_tool(m_item: Ident) -> bool {
- RUST_KNOWN_LINT_TOOL.contains(&m_item.as_str().as_ref())
+ ["clippy"].contains(&m_item.as_str().as_ref())
}
impl NestedMetaItem {
pub fn is_value_str(&self) -> bool {
self.value_str().is_some()
}
-
- pub fn is_scoped(&self) -> bool {
- self.path.segments.len() > 1
- }
}
impl MetaItem {
/// An enum representing the different kinds of syntax extensions.
pub enum SyntaxExtension {
+ /// A trivial "extension" that does nothing, only keeps the attribute and marks it as known.
+ NonMacroAttr,
+
/// A syntax extension that is attached to an item and creates new items
/// based upon it.
///
SyntaxExtension::IdentTT(..) |
SyntaxExtension::ProcMacro { .. } =>
MacroKind::Bang,
+ SyntaxExtension::NonMacroAttr |
SyntaxExtension::MultiDecorator(..) |
SyntaxExtension::MultiModifier(..) |
SyntaxExtension::AttrProcMacro(..) =>
SyntaxExtension::AttrProcMacro(.., edition) |
SyntaxExtension::ProcMacroDerive(.., edition) => edition,
// Unstable legacy stuff
+ SyntaxExtension::NonMacroAttr |
SyntaxExtension::IdentTT(..) |
SyntaxExtension::MultiDecorator(..) |
SyntaxExtension::MultiModifier(..) |
use config::{is_test_or_bench, StripUnconfigured};
use errors::{Applicability, FatalError};
use ext::base::*;
+use ext::build::AstBuilder;
use ext::derive::{add_derived_markers, collect_derives};
use ext::hygiene::{self, Mark, SyntaxContext};
use ext::placeholders::{placeholder, PlaceholderExpander};
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
-use std::mem;
+use std::{iter, mem};
use std::rc::Rc;
use std::path::PathBuf;
}
}
+ pub fn path_span(&self) -> Span {
+ match self.kind {
+ InvocationKind::Bang { ref mac, .. } => mac.node.path.span,
+ InvocationKind::Attr { attr: Some(ref attr), .. } => attr.path.span,
+ InvocationKind::Attr { attr: None, .. } => DUMMY_SP,
+ InvocationKind::Derive { ref path, .. } => path.span,
+ }
+ }
+
pub fn attr_id(&self) -> Option<ast::AttrId> {
match self.kind {
InvocationKind::Attr { attr: Some(ref attr), .. } => Some(attr.id),
cx: self.cx,
invocations: Vec::new(),
monotonic: self.monotonic,
+ tests_nameable: true,
};
(fragment.fold_with(&mut collector), collector.invocations)
};
});
match *ext {
+ NonMacroAttr => {
+ attr::mark_known(&attr);
+ let item = item.map_attrs(|mut attrs| { attrs.push(attr); attrs });
+ Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item)))
+ }
MultiModifier(ref mac) => {
let meta = attr.parse_meta(self.cx.parse_sess)
.map_err(|mut e| { e.emit(); }).ok()?;
}
}
- MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) => {
+ MultiDecorator(..) | MultiModifier(..) |
+ AttrProcMacro(..) | SyntaxExtension::NonMacroAttr => {
self.cx.span_err(path.span,
&format!("`{}` can only be used in attributes", path));
self.cx.trace_macros_diag();
cfg: StripUnconfigured<'a>,
invocations: Vec<Invocation>,
monotonic: bool,
+
+ /// Test functions need to be nameable. Tests inside functions or in other
+ /// unnameable locations need to be ignored. `tests_nameable` tracks whether
+ /// any test functions found in the current context would be nameable.
+ tests_nameable: bool,
}
impl<'a, 'b> InvocationCollector<'a, 'b> {
placeholder(fragment_kind, NodeId::placeholder_from_mark(mark))
}
+ /// Folds the item allowing tests to be expanded because they are still nameable.
+ /// This should probably only be called with module items
+ fn fold_nameable(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
+ fold::noop_fold_item(item, self)
+ }
+
+ /// Folds the item but doesn't allow tests to occur within it
+ fn fold_unnameable(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
+ let was_nameable = mem::replace(&mut self.tests_nameable, false);
+ let items = fold::noop_fold_item(item, self);
+ self.tests_nameable = was_nameable;
+ items
+ }
+
fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment {
self.collect(kind, InvocationKind::Bang { mac: mac, ident: None, span: span })
}
}
ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
if item.ident == keywords::Invalid.ident() {
- return noop_fold_item(item, self);
+ return self.fold_nameable(item);
}
let orig_directory_ownership = self.cx.current_expansion.directory_ownership;
let orig_module =
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
- let result = noop_fold_item(item, self);
+ let result = self.fold_nameable(item);
self.cx.current_expansion.module = orig_module;
self.cx.current_expansion.directory_ownership = orig_directory_ownership;
result
}
// Ensure that test functions are accessible from the test harness.
+ // #[test] fn foo() {}
+ // becomes:
+ // #[test] pub fn foo_gensym(){}
+ // #[allow(unused)]
+ // use foo_gensym as foo;
ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => {
- if item.attrs.iter().any(|attr| is_test_or_bench(attr)) {
+ if self.tests_nameable && item.attrs.iter().any(|attr| is_test_or_bench(attr)) {
+ let orig_ident = item.ident;
+ let orig_vis = item.vis.clone();
+
+ // Publicize the item under gensymed name to avoid pollution
item = item.map(|mut item| {
item.vis = respan(item.vis.span, ast::VisibilityKind::Public);
+ item.ident = item.ident.gensym();
item
});
+
+ // Use the gensymed name under the item's original visibility
+ let mut use_item = self.cx.item_use_simple_(
+ item.ident.span,
+ orig_vis,
+ Some(orig_ident),
+ self.cx.path(item.ident.span,
+ vec![keywords::SelfValue.ident(), item.ident]));
+
+ // #[allow(unused)] because the test function probably isn't being referenced
+ use_item = use_item.map(|mut ui| {
+ ui.attrs.push(
+ self.cx.attribute(DUMMY_SP, attr::mk_list_item(DUMMY_SP,
+ Ident::from_str("allow"), vec![
+ attr::mk_nested_word_item(Ident::from_str("unused"))
+ ]
+ ))
+ );
+
+ ui
+ });
+
+ SmallVector::many(
+ self.fold_unnameable(item).into_iter()
+ .chain(self.fold_unnameable(use_item)))
+ } else {
+ self.fold_unnameable(item)
}
- noop_fold_item(item, self)
}
- _ => noop_fold_item(item, self),
+ _ => self.fold_unnameable(item),
}
}
fn enable_allow_internal_unstable = allow_internal_unstable,
fn enable_custom_derive = custom_derive,
fn enable_format_args_nl = format_args_nl,
- fn use_extern_macros_enabled = use_extern_macros,
fn macros_in_extern_enabled = macros_in_extern,
fn proc_macro_mod = proc_macro_mod,
fn proc_macro_gen = proc_macro_gen,
fn proc_macro_expr = proc_macro_expr,
fn proc_macro_non_items = proc_macro_non_items,
}
+
+ pub fn use_extern_macros_enabled(&self) -> bool {
+ self.features.map_or(false, |features| features.use_extern_macros())
+ }
}
// A Marker adds the given mark to the syntax context.
{
$(f(stringify!($feature), self.$feature);)+
}
+
+ pub fn use_extern_macros(&self) -> bool {
+ // The `decl_macro` and `tool_attributes` features imply `use_extern_macros`.
+ self.use_extern_macros || self.decl_macro || self.tool_attributes
+ }
}
};
// Infer outlives requirements; RFC 2093
(active, infer_outlives_requirements, "1.26.0", Some(44493), None),
- // Infer outlives requirements; RFC 2093
+ // Infer static outlives requirements; RFC 2093
(active, infer_static_outlives_requirements, "1.26.0", Some(44493), None),
// Multiple patterns with `|` in `if let` and `while let`
BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
}
+pub fn is_builtin_attr_name(name: ast::Name) -> bool {
+ BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| name == builtin_name)
+}
+
pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) ||
attr.name().as_str().starts_with("rustc_")
// before the plugin attributes are registered
// so we skip this then
if !is_macro {
- if attr.is_scoped() {
- gate_feature!(self, tool_attributes, attr.span,
- &format!("scoped attribute `{}` is experimental", attr.path));
- if attr::is_known_tool(attr) {
- attr::mark_used(attr);
- } else {
- span_err!(
- self.parse_sess.span_diagnostic,
- attr.span,
- E0694,
- "an unknown tool name found in scoped attribute: `{}`.",
- attr.path
- );
- }
- } else {
- gate_feature!(self, custom_attribute, attr.span,
- &format!("The attribute `{}` is currently \
- unknown to the compiler and \
- may have meaning \
- added to it in the future",
- attr.path));
- }
+ let msg = format!("The attribute `{}` is currently unknown to the compiler and \
+ may have meaning added to it in the future", attr.path);
+ gate_feature!(self, custom_attribute, attr.span, &msg);
}
}
}
}
}
- if self.context.features.use_extern_macros && attr::is_known(attr) {
+ if self.context.features.use_extern_macros() && attr::is_known(attr) {
return
}
// the branching can be eliminated by modifying `set!()` to set these spans
// only for the features that need to be checked for mutual exclusion.
fn collect(&mut self, features: &Features, span: Span) {
- if features.use_extern_macros {
+ if features.use_extern_macros() {
// If self.use_extern_macros is None, set to Some(span)
self.use_extern_macros = self.use_extern_macros.or(Some(span));
}
extern crate serialize as rustc_serialize; // used by deriving
use rustc_data_structures::sync::Lock;
+use rustc_data_structures::bitvec::BitVector;
+use ast::AttrId;
// A variant of 'try!' that panics on an Err. This is used as a crutch on the
// way towards a non-panic!-prone parser. It should be used for fatal parsing
}
pub struct Globals {
- used_attrs: Lock<Vec<u64>>,
- known_attrs: Lock<Vec<u64>>,
+ used_attrs: Lock<BitVector<AttrId>>,
+ known_attrs: Lock<BitVector<AttrId>>,
syntax_pos_globals: syntax_pos::Globals,
}
impl Globals {
fn new() -> Globals {
Globals {
- used_attrs: Lock::new(Vec::new()),
- known_attrs: Lock::new(Vec::new()),
+ // We have no idea how many attributes their will be, so just
+ // initiate the vectors with 0 bits. We'll grow them as necessary.
+ used_attrs: Lock::new(BitVector::new()),
+ known_attrs: Lock::new(BitVector::new()),
syntax_pos_globals: syntax_pos::Globals::new(),
}
}
!ident_token.is_reserved_ident() ||
ident_token.is_path_segment_keyword() ||
[
+ keywords::Async.name(),
keywords::Do.name(),
keywords::Box.name(),
keywords::Break.name(),
#[derive(Clone, PartialEq, Debug)]
pub enum Substitution<'a> {
- Ordinal(u8),
- Name(&'a str),
- Escape,
+ Ordinal(u8, (usize, usize)),
+ Name(&'a str, (usize, usize)),
+ Escape((usize, usize)),
}
impl<'a> Substitution<'a> {
pub fn as_str(&self) -> String {
- match *self {
- Substitution::Ordinal(n) => format!("${}", n),
- Substitution::Name(n) => format!("${}", n),
- Substitution::Escape => "$$".into(),
+ match self {
+ Substitution::Ordinal(n, _) => format!("${}", n),
+ Substitution::Name(n, _) => format!("${}", n),
+ Substitution::Escape(_) => "$$".into(),
}
}
pub fn position(&self) -> Option<(usize, usize)> {
- match *self {
- _ => None,
+ match self {
+ Substitution::Ordinal(_, pos) |
+ Substitution::Name(_, pos) |
+ Substitution::Escape(pos) => Some(*pos),
+ }
+ }
+
+ pub fn set_position(&mut self, start: usize, end: usize) {
+ match self {
+ Substitution::Ordinal(_, ref mut pos) |
+ Substitution::Name(_, ref mut pos) |
+ Substitution::Escape(ref mut pos) => *pos = (start, end),
}
}
pub fn translate(&self) -> Option<String> {
match *self {
- Substitution::Ordinal(n) => Some(format!("{{{}}}", n)),
- Substitution::Name(n) => Some(format!("{{{}}}", n)),
- Substitution::Escape => None,
+ Substitution::Ordinal(n, _) => Some(format!("{{{}}}", n)),
+ Substitution::Name(n, _) => Some(format!("{{{}}}", n)),
+ Substitution::Escape(_) => None,
}
}
}
pub fn iter_subs(s: &str) -> Substitutions {
Substitutions {
s,
+ pos: 0,
}
}
/// Iterator over substitutions in a string.
pub struct Substitutions<'a> {
s: &'a str,
+ pos: usize,
}
impl<'a> Iterator for Substitutions<'a> {
type Item = Substitution<'a>;
fn next(&mut self) -> Option<Self::Item> {
match parse_next_substitution(self.s) {
- Some((sub, tail)) => {
+ Some((mut sub, tail)) => {
self.s = tail;
+ if let Some((start, end)) = sub.position() {
+ sub.set_position(start + self.pos, end + self.pos);
+ self.pos += end;
+ }
Some(sub)
},
None => None,
let at = {
let start = s.find('$')?;
match s[start+1..].chars().next()? {
- '$' => return Some((Substitution::Escape, &s[start+2..])),
+ '$' => return Some((Substitution::Escape((start, start+2)), &s[start+2..])),
c @ '0' ..= '9' => {
let n = (c as u8) - b'0';
- return Some((Substitution::Ordinal(n), &s[start+2..]));
+ return Some((Substitution::Ordinal(n, (start, start+2)), &s[start+2..]));
},
_ => {/* fall-through */},
}
- Cur::new_at_start(&s[start..])
+ Cur::new_at(&s[..], start)
};
let at = at.at_next_cp()?;
None
} else {
let end = at_next_cp_while(inner, is_ident_tail);
- Some((Substitution::Name(at.slice_between(end).unwrap()), end.slice_after()))
+ let slice = at.slice_between(end).unwrap();
+ let start = at.at - 1;
+ let end_pos = at.at + slice.len();
+ Some((Substitution::Name(slice, (start, end_pos)), end.slice_after()))
}
}
fn test_escape() {
assert_eq!(pns("has no escapes"), None);
assert_eq!(pns("has no escapes, either $"), None);
- assert_eq!(pns("*so* has a $$ escape"), Some((S::Escape, " escape")));
- assert_eq!(pns("$$ leading escape"), Some((S::Escape, " leading escape")));
- assert_eq!(pns("trailing escape $$"), Some((S::Escape, "")));
+ assert_eq!(pns("*so* has a $$ escape"), Some((S::Escape((11, 13)), " escape")));
+ assert_eq!(pns("$$ leading escape"), Some((S::Escape((0, 2)), " leading escape")));
+ assert_eq!(pns("trailing escape $$"), Some((S::Escape((16, 18)), "")));
}
#[test]
fn test_parse() {
macro_rules! assert_pns_eq_sub {
- ($in_:expr, $kind:ident($arg:expr)) => {
- assert_eq!(pns(concat!($in_, "!")), Some((S::$kind($arg.into()), "!")))
+ ($in_:expr, $kind:ident($arg:expr, $pos:expr)) => {
+ assert_eq!(pns(concat!($in_, "!")), Some((S::$kind($arg.into(), $pos), "!")))
};
}
- assert_pns_eq_sub!("$0", Ordinal(0));
- assert_pns_eq_sub!("$1", Ordinal(1));
- assert_pns_eq_sub!("$9", Ordinal(9));
- assert_pns_eq_sub!("$N", Name("N"));
- assert_pns_eq_sub!("$NAME", Name("NAME"));
+ assert_pns_eq_sub!("$0", Ordinal(0, (0, 2)));
+ assert_pns_eq_sub!("$1", Ordinal(1, (0, 2)));
+ assert_pns_eq_sub!("$9", Ordinal(9, (0, 2)));
+ assert_pns_eq_sub!("$N", Name("N", (0, 2)));
+ assert_pns_eq_sub!("$NAME", Name("NAME", (0, 5)));
}
#[test]
}
impl<'a> StrCursor<'a> {
- pub fn new_at_start(s: &'a str) -> StrCursor<'a> {
- StrCursor {
- s,
- at: 0,
- }
- }
-
pub fn new_at(s: &'a str, at: usize) -> StrCursor<'a> {
StrCursor {
s,
/// The kind of compiler desugaring.
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum CompilerDesugaringKind {
- DotFill,
QuestionMark,
Catch,
/// Desugaring of an `impl Trait` in return type position
pub fn name(self) -> Symbol {
Symbol::intern(match self {
CompilerDesugaringKind::Async => "async",
- CompilerDesugaringKind::DotFill => "...",
CompilerDesugaringKind::QuestionMark => "?",
CompilerDesugaringKind::Catch => "do catch",
CompilerDesugaringKind::ExistentialReturnType => "existential type",
-Subproject commit 03684905101f0b7e49dfe530e54dc1aeac6ef0fb
+Subproject commit e19f07f5a6e5546ab4f6ea951e3c6b8627edeaa7
#if LLVM_VERSION_GE(4, 0)
Expected<StringRef> NameOrErr = Child->getName();
if (!NameOrErr) {
- // rustc_llvm currently doesn't use this error string, but it might be
+ // rustc_codegen_llvm currently doesn't use this error string, but it might be
// useful in the future, and in the mean time this tells LLVM that the
// error was not ignored and that it shouldn't abort the process.
LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
#define SUBTARGET_MSP430
#endif
+#ifdef LLVM_COMPONENT_RISCV
+#define SUBTARGET_RISCV SUBTARGET(RISCV)
+#else
+#define SUBTARGET_RISCV
+#endif
+
#ifdef LLVM_COMPONENT_SPARC
#define SUBTARGET_SPARC SUBTARGET(Sparc)
#else
SUBTARGET_SYSTEMZ \
SUBTARGET_MSP430 \
SUBTARGET_SPARC \
- SUBTARGET_HEXAGON
+ SUBTARGET_HEXAGON \
+ SUBTARGET_RISCV \
#define SUBTARGET(x) \
namespace llvm { \
// and various online resources about ThinLTO to make heads or tails of all
// this.
-extern "C" bool
-LLVMRustWriteThinBitcodeToFile(LLVMPassManagerRef PMR,
- LLVMModuleRef M,
- const char *BcFile) {
- llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR);
- std::error_code EC;
- llvm::raw_fd_ostream bc(BcFile, EC, llvm::sys::fs::F_None);
- if (EC) {
- LLVMRustSetLastError(EC.message().c_str());
- return false;
- }
- PM->add(createWriteThinLTOBitcodePass(bc));
- PM->run(*unwrap(M));
- delete PM;
- return true;
-}
-
// This is a shared data structure which *must* be threadsafe to share
// read-only amongst threads. This also corresponds basically to the arguments
// of the `ProcessThinLTOModule` function in the LLVM source.
auto MOrErr = getLazyBitcodeModule(Memory, Context, true, true);
if (!MOrErr)
- return std::move(MOrErr);
+ return MOrErr;
// The rest of this closure is a workaround for
// https://bugs.llvm.org/show_bug.cgi?id=38184 where during ThinLTO imports
// shouldn't be a perf hit.
if (Error Err = (*MOrErr)->materializeMetadata()) {
Expected<std::unique_ptr<Module>> Ret(std::move(Err));
- return std::move(Ret);
+ return Ret;
}
auto *WasmCustomSections = (*MOrErr)->getNamedMetadata("wasm.custom_sections");
if (WasmCustomSections)
WasmCustomSections->eraseFromParent();
- return std::move(MOrErr);
+ return MOrErr;
};
FunctionImporter Importer(Data->Index, Loader);
Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
#else
-extern "C" bool
-LLVMRustWriteThinBitcodeToFile(LLVMPassManagerRef PMR,
- LLVMModuleRef M,
- const char *BcFile) {
- report_fatal_error("ThinLTO not available");
-}
-
struct LLVMRustThinLTOData {
};
DINodeArray(unwrapDI<MDTuple>(Subscripts))));
}
-extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateVectorType(LLVMRustDIBuilderRef Builder, uint64_t Size,
- uint32_t AlignInBits, LLVMMetadataRef Ty,
- LLVMMetadataRef Subscripts) {
- return wrap(
- Builder->createVectorType(Size, AlignInBits, unwrapDI<DIType>(Ty),
- DINodeArray(unwrapDI<MDTuple>(Subscripts))));
-}
-
extern "C" LLVMMetadataRef
LLVMRustDIBuilderGetOrCreateSubrange(LLVMRustDIBuilderRef Builder, int64_t Lo,
int64_t Count) {
OptimizationRemarkOther,
OptimizationFailure,
PGOProfile,
+ Linker,
};
static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisAliasing;
case DK_PGOProfile:
return LLVMRustDiagnosticKind::PGOProfile;
+ case DK_Linker:
+ return LLVMRustDiagnosticKind::Linker;
default:
return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark)
? LLVMRustDiagnosticKind::OptimizationRemarkOther
# If this file is modified, then llvm will be (optionally) cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2018-07-12
\ No newline at end of file
+2018-08-02
# source tarball for a stable release you'll likely see `1.x.0` for rustc and
# `0.x.0` for Cargo where they were released on `date`.
-date: 2018-07-27
+date: 2018-08-01
rustc: beta
cargo: beta
--- /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.
+
+// no-system-llvm
+// compile-flags: -O -C panic=abort
+#![crate_type = "lib"]
+
+fn search<T: Ord + Eq>(arr: &mut [T], a: &T) -> Result<usize, ()> {
+ match arr.iter().position(|x| x == a) {
+ Some(p) => {
+ Ok(p)
+ },
+ None => Err(()),
+ }
+}
+
+// CHECK-LABEL: @position_no_bounds_check
+#[no_mangle]
+pub fn position_no_bounds_check(y: &mut [u32], x: &u32, z: &u32) -> bool {
+ // This contains "call assume" so we cannot just rule out all calls
+ // CHECK-NOT: panic_bounds_check
+ if let Ok(p) = search(y, x) {
+ y[p] == *z
+ } else {
+ false
+ }
+}
+
+// just to make sure that panicking really emits "panic_bounds_check" somewhere in the IR
+// CHECK-LABEL: @test_check
+#[no_mangle]
+pub fn test_check(y: &[i32]) -> i32 {
+ // CHECK: panic_bounds_check
+ y[12]
+}
// Checks that we correctly codegen extern "C" functions returning structs.
// See issue #52638.
+// only-sparc64
// compile-flags: -O --target=sparc64-unknown-linux-gnu --crate-type=rlib
#![feature(no_core, lang_items)]
#![no_core]
--- /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.
+
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @vec_clear
+#[no_mangle]
+pub fn vec_clear(x: &mut Vec<u32>) {
+ // CHECK-NOT: load
+ // CHECK-NOT: icmp
+ x.clear()
+}
--- /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.
+
+#![crate_type = "lib"]
+#![unstable(feature = "issue_52489_unstable", issue = "0")]
+#![feature(staged_api)]
--- /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 = "rlib"]
+
+#[no_mangle]
+pub extern fn foo() {}
--- /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 = "rlib"]
+
+#[no_mangle]
+pub extern fn foo() {}
enum Bar {
Boo = [unsafe { Foo { b: () }.a }; 4][3],
- //~^ ERROR constant evaluation of enum discriminant resulted in non-integer
+ //~^ ERROR could not evaluate enum discriminant
}
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.
-
-fn main() {
- #[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
- let x =
- 3;
-}
--- /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.
+
+// edition:2018
+// aux-build:issue-52489.rs
+
+use issue_52489;
+//~^ ERROR use of unstable library feature 'issue_52489_unstable'
+
+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.
+
+// aux-build:lto-duplicate-symbols1.rs
+// aux-build:lto-duplicate-symbols2.rs
+// error-pattern:Linking globals named 'foo': symbol multiply defined!
+// compile-flags: -C lto
+// no-prefer-dynamic
+
+extern crate lto_duplicate_symbols1;
+extern crate lto_duplicate_symbols2;
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(tool_attributes)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
-#![foo::bar] //~ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
-
-#[foo::bar] //~ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
+#[foo::bar] //~ ERROR failed to resolve. Use of undeclared type or module `foo`
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.
-
-// Make sure that 'custom_attributes' feature does not allow scoped attributes.
-
-#![feature(custom_attributes)]
-
-#[foo::bar]
-//~^ ERROR scoped attribute `foo::bar` is experimental (see issue #44690) [E0658]
-//~^^ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
-fn main() {}
#![deny(intra_doc_link_resolution_failure)]
/// [intradoc::failure]
-fn main() {
+pub fn main() {
println!("Hello, world!");
}
let crate_name = ongoing_codegen.downcast::<Symbol>()
.expect("in join_codegen_and_link: ongoing_codegen is not a Symbol");
for &crate_type in sess.opts.crate_types.iter() {
- if crate_type != CrateType::CrateTypeRlib {
+ if crate_type != CrateType::Rlib {
sess.fatal(&format!("Crate type is {:?}", crate_type));
}
let output_name =
extern crate syntax;
use rustc::session::{build_session, Session};
-use rustc::session::config::{basic_options, Input, Options,
+use rustc::session::config::{Input, Options,
OutputType, OutputTypes};
use rustc_driver::driver::{self, compile_input, CompileController};
use rustc_metadata::cstore::CStore;
fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
syntax::with_globals(|| {
- let mut opts = basic_options();
+ let mut opts = Options::default();
opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
opts.maybe_sysroot = Some(sysroot);
if let Ok(linker) = std::env::var("RUSTC_LINKER") {
extern crate rustc_codegen_utils;
extern crate syntax;
extern crate rustc_errors as errors;
+extern crate rustc_metadata;
-use rustc::middle::cstore::CrateStore;
use rustc::session::Session;
use rustc::session::config::{self, Input};
use rustc_driver::{driver, CompilerCalls, Compilation};
use rustc_codegen_utils::codegen_backend::CodegenBackend;
+use rustc_metadata::cstore::CStore;
use syntax::ast;
use std::path::PathBuf;
_: &CodegenBackend,
_: &getopts::Matches,
_: &Session,
- _: &CrateStore,
+ _: &CStore,
_: &Input,
_: &Option<PathBuf>,
_: &Option<PathBuf>)
// aux-build:issue-42708.rs
// ignore-stage1
-#![feature(decl_macro, use_extern_macros, proc_macro_path_invoc)]
+#![feature(decl_macro, proc_macro_path_invoc)]
#![allow(unused)]
extern crate issue_42708;
// aux-build:issue-50061.rs
// ignore-stage1
-#![feature(use_extern_macros, proc_macro_path_invoc, decl_macro)]
+#![feature(proc_macro_path_invoc, decl_macro)]
extern crate issue_50061;
--- /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(use_extern_macros)]
+#![allow(duplicate_macro_exports)]
+
+#[macro_export]
+macro_rules! foo_modern { ($i:ident) => {} }
+
+#[macro_export]
+macro_rules! foo_modern { () => {} }
#[cfg(not(target_arch = "asmjs"))]
{
const BE_U128: u128 = 999999u128.to_be();
- const LE_I128: i128 = -999999i128.to_le();
+ const LE_I128: i128 = (-999999i128).to_le();
assert_eq!(BE_U128, b(999999u128).to_be());
assert_eq!(LE_I128, b(-999999i128).to_le());
}
--- /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(generators)]
+
+fn main() {
+ static || {
+ loop {
+ // Test that `opt` is not live across the yield, even when borrowed in a loop
+ // See https://github.com/rust-lang/rust/issues/52792
+ let opt = {
+ yield;
+ true
+ };
+ &opt;
+ }
+ };
+}
// except according to those terms.
// aux-build:issue_38715.rs
+// aux-build:issue_38715-modern.rs
// Test that `#[macro_export] macro_rules!` shadow earlier `#[macro_export] macro_rules!`
#[macro_use]
extern crate issue_38715;
+#[macro_use]
+extern crate issue_38715_modern;
fn main() {
foo!();
+ foo_modern!();
}
--- /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.
+
+// This test checks for namespace pollution by private tests.
+// Tests used to marked as public causing name conflicts with normal
+// functions only in test builds.
+
+// compile-flags: --test
+
+mod a {
+ pub fn foo() -> bool {
+ true
+ }
+}
+
+mod b {
+ #[test]
+ fn foo() {
+ local_name(); // ensure the local name still works
+ }
+
+ #[test]
+ fn local_name() {}
+}
+
+use a::*;
+use b::*;
+
+pub fn conflict() {
+ let _: bool = foo();
+}
3 | no
| ^^ not found in this scope
-thread '$DIR/failed-doctest-output.rs - OtherStruct (line 26)' panicked at 'couldn't compile the test', librustdoc/test.rs:332:13
+thread '$DIR/failed-doctest-output.rs - OtherStruct (line 26)' panicked at 'couldn't compile the test', librustdoc/test.rs:333:13
note: Run with `RUST_BACKTRACE=1` for a backtrace.
---- $DIR/failed-doctest-output.rs - SomeStruct (line 20) stdout ----
thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1
note: Run with `RUST_BACKTRACE=1` for a backtrace.
-', librustdoc/test.rs:367:17
+', librustdoc/test.rs:368:17
failures:
--- /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.
+
+#![deny(intra_doc_link_resolution_failure)]
+
+pub type TypeAlias = usize;
+
+/// [broken cross-reference](TypeAlias::hoge) //~ ERROR
+pub fn some_public_item() {}
--- /dev/null
+error: `[TypeAlias::hoge]` cannot be resolved, ignoring it...
+ --> $DIR/intra-doc-alias-ice.rs:15:30
+ |
+15 | /// [broken cross-reference](TypeAlias::hoge) //~ ERROR
+ | ^^^^^^^^^^^^^^^ cannot be resolved, ignoring
+ |
+note: lint level defined here
+ --> $DIR/intra-doc-alias-ice.rs:11:9
+ |
+11 | #![deny(intra_doc_link_resolution_failure)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
+
--- /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.
+
+#![crate_name="inner"]
+
+//! ooh, i'm a rebel just for [kicks]
// @has foo/struct.Foo.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
pub struct Foo;
+// @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString'
impl fmt::Display for Foo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
--- /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:intra-link-extern-crate.rs
+
+// When loading `extern crate` statements, we would pull in their docs at the same time, even
+// though they would never actually get displayed. This tripped intra-doc-link resolution failures,
+// for items that aren't under our control, and not actually getting documented!
+
+#![deny(intra_doc_link_resolution_failure)]
+
+extern crate inner;
--- /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.
+
+// Rustdoc would previously report resolution failures on items that weren't in the public docs.
+// These failures were legitimate, but not truly relevant - the docs in question couldn't be
+// checked for accuracy anyway.
+
+#![deny(intra_doc_link_resolution_failure)]
+
+/// ooh, i'm a [rebel] just for kicks
+struct SomeStruct;
--- /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.
+
+#![crate_name = "foo"]
+
+// we need to reexport something from libstd so that `all_trait_implementations` is called.
+pub use std::string::String;
+
+include!("primitive/primitive-generic-impl.rs");
+
+// @has foo/primitive.i32.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
--- /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.
+
+#[doc(primitive = "i32")]
+/// Some useless docs, wouhou!
+mod i32 {}
--- /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(plugin_registrar)]
+#![feature(box_syntax, rustc_private)]
+#![feature(macro_vis_matcher)]
+#![feature(macro_at_most_once_rep)]
+
+extern crate syntax;
+
+// Load rustc as a plugin to get macros
+#[macro_use]
+extern crate rustc;
+extern crate rustc_plugin;
+
+use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
+ LintArray};
+use rustc_plugin::Registry;
+use syntax::ast;
+declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff");
+
+struct Pass;
+
+impl LintPass for Pass {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(TEST_LINT)
+ }
+}
+
+impl EarlyLintPass for Pass {
+ fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
+ if it.ident.name == "lintme" {
+ cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
+ }
+ }
+}
+
+#[plugin_registrar]
+pub fn plugin_registrar(reg: &mut Registry) {
+ reg.register_early_lint_pass(box Pass);
+}
--- /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.
+
+// run-pass
+// aux-build:lint_tool_test.rs
+// ignore-stage1
+#![feature(plugin)]
+#![feature(tool_lints)]
+#![plugin(lint_tool_test)]
+#![allow(dead_code)]
+
+fn lintme() { } //~ WARNING item is named 'lintme'
+
+#[allow(clippy::test_lint)]
+pub fn main() {
+ fn lintme() { }
+}
--- /dev/null
+warning: item is named 'lintme'
+ --> $DIR/lint_tool_test.rs:19:1
+ |
+LL | fn lintme() { } //~ WARNING item is named 'lintme'
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: #[warn(clippy::test_lint)] on by default
+
// aux-build:parent-source-spans.rs
// ignore-stage1
-#![feature(use_extern_macros, decl_macro, proc_macro_non_items)]
+#![feature(decl_macro, proc_macro_non_items)]
extern crate parent_source_spans;
--- /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::*;
+
+#[proc_macro_attribute]
+pub fn foo(_attr: TokenStream, _f: TokenStream) -> TokenStream {
+ "pub fn foo() -> ::Foo { ::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:suggestions-not-always-applicable.rs
+// compile-flags: --edition 2015
+// run-rustfix
+// rustfix-only-machine-applicable
+// compile-pass
+
+#![feature(rust_2018_preview)]
+#![warn(rust_2018_compatibility)]
+
+extern crate suggestions_not_always_applicable as foo;
+
+pub struct Foo;
+
+mod test {
+ use crate::foo::foo;
+
+ #[foo] //~ WARN: absolute paths must start with
+ //~| WARN: previously accepted
+ //~| WARN: absolute paths
+ //~| WARN: previously accepted
+ fn main() {
+ }
+}
+
+fn main() {
+ test::foo();
+}
--- /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:suggestions-not-always-applicable.rs
+// compile-flags: --edition 2015
+// run-rustfix
+// rustfix-only-machine-applicable
+// compile-pass
+
+#![feature(rust_2018_preview)]
+#![warn(rust_2018_compatibility)]
+
+extern crate suggestions_not_always_applicable as foo;
+
+pub struct Foo;
+
+mod test {
+ use crate::foo::foo;
+
+ #[foo] //~ WARN: absolute paths must start with
+ //~| WARN: previously accepted
+ //~| WARN: absolute paths
+ //~| WARN: previously accepted
+ fn main() {
+ }
+}
+
+fn main() {
+ test::foo();
+}
--- /dev/null
+warning: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+ --> $DIR/suggestions-not-always-applicable.rs:27:5
+ |
+LL | #[foo] //~ WARN: absolute paths must start with
+ | ^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/suggestions-not-always-applicable.rs:18:9
+ |
+LL | #![warn(rust_2018_compatibility)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ = note: #[warn(absolute_paths_not_starting_with_crate)] implied by #[warn(rust_2018_compatibility)]
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue TBD
+
+warning: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+ --> $DIR/suggestions-not-always-applicable.rs:27:5
+ |
+LL | #[foo] //~ WARN: absolute paths must start with
+ | ^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
+ = note: for more information, see issue TBD
+
error[E0384]: cannot assign twice to immutable variable `x`
- --> $DIR/asm-out-assign-imm.rs:33:9
+ --> $DIR/asm-out-assign-imm.rs:34:9
|
LL | let x: isize;
| - consider changing this to `mut x`
// ignore-sparc
// ignore-sparc64
// ignore-mips
+// ignore-mips64
#![feature(asm)]
error[E0384]: cannot assign twice to immutable variable `x`
- --> $DIR/asm-out-assign-imm.rs:33:9
+ --> $DIR/asm-out-assign-imm.rs:34:9
|
LL | x = 1;
| ----- first assignment to `x`
--- /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.
+
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro)]
+
+macro_rules! match_expr {
+ ($x:expr) => {}
+}
+
+fn main() {
+ match_expr!(async {});
+ match_expr!(async || {});
+}
macro_rules! mac {
($ident:ident) => { let $ident = 42; }
}
+
+#[macro_export]
+macro_rules! inline {
+ () => ()
+}
--> $DIR/borrowck-closures-two-mut.rs:24:24
|
LL | let c1 = to_fn_mut(|| x = 4);
- | -- - previous borrow occurs due to use of `x` in closure
+ | -- - first borrow occurs due to use of `x` in closure
| |
| first mutable borrow occurs here
LL | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once
- | ^^ - borrow occurs due to use of `x` in closure
+ | ^^ - second borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
LL | //~| ERROR cannot borrow `x` as mutable more than once
--> $DIR/borrowck-closures-two-mut.rs:36:24
|
LL | let c1 = to_fn_mut(|| set(&mut x));
- | -- - previous borrow occurs due to use of `x` in closure
+ | -- - first borrow occurs due to use of `x` in closure
| |
| first mutable borrow occurs here
LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
- | ^^ - borrow occurs due to use of `x` in closure
+ | ^^ - second borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
LL | //~| ERROR cannot borrow `x` as mutable more than once
--> $DIR/borrowck-closures-two-mut.rs:44:24
|
LL | let c1 = to_fn_mut(|| x = 5);
- | -- - previous borrow occurs due to use of `x` in closure
+ | -- - first borrow occurs due to use of `x` in closure
| |
| first mutable borrow occurs here
LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
- | ^^ - borrow occurs due to use of `x` in closure
+ | ^^ - second borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
LL | //~| ERROR cannot borrow `x` as mutable more than once
--> $DIR/borrowck-closures-two-mut.rs:52:24
|
LL | let c1 = to_fn_mut(|| x = 5);
- | -- - previous borrow occurs due to use of `x` in closure
+ | -- - first borrow occurs due to use of `x` in closure
| |
| first mutable borrow occurs here
LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
- | ^^ - borrow occurs due to use of `x` in closure
+ | ^^ - second borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
...
--> $DIR/borrowck-closures-two-mut.rs:65:24
|
LL | let c1 = to_fn_mut(|| set(&mut *x.f));
- | -- - previous borrow occurs due to use of `x` in closure
+ | -- - first borrow occurs due to use of `x` in closure
| |
| first mutable borrow occurs here
LL | let c2 = to_fn_mut(|| set(&mut *x.f));
- | ^^ - borrow occurs due to use of `x` in closure
+ | ^^ - second borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
...
error[E0597]: `books` does not live long enough
- --> $DIR/borrowck-escaping-closure-error-1.rs:23:11
+ --> $DIR/borrowck-escaping-closure-error-1.rs:23:14
|
LL | spawn(|| books.push(4));
- | ^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | -- ^^^^^ borrowed value does not live long enough
+ | |
+ | value captured here
LL | //~^ ERROR E0373
LL | }
| - `books` dropped here while still borrowed
error[E0597]: `books` does not live long enough
- --> $DIR/borrowck-escaping-closure-error-2.rs:21:14
+ --> $DIR/borrowck-escaping-closure-error-2.rs:21:17
|
LL | Box::new(|| books.push(4))
- | ^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | -- ^^^^^ borrowed value does not live long enough
+ | |
+ | value captured here
LL | //~^ ERROR E0373
LL | }
| - `books` dropped here while still borrowed
|
LL | match (S {f: "foo".to_string(), g: "bar".to_string()}) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
+...
+LL | f: _s,
+ | -- data moved here
+LL | g: _t
+ | -- ... and here
help: to prevent move, use ref or ref mut
|
LL | f: ref _s,
- | ^^^^^^
-help: to prevent move, use ref or ref mut
- |
LL | g: ref _t
- | ^^^^^^
+ |
error[E0507]: cannot move out of borrowed content
--> $DIR/borrowck-move-error-with-note.rs:57:11
|
LL | match tail {
| ^^^^ cannot move out of here
+LL | &[Foo { string: a },
+ | - data moved here
+...
+LL | Foo { string: b }] => {
+ | - ... and here
help: to prevent move, use ref or ref mut
|
LL | &[Foo { string: ref a },
- | ^^^^^
-help: to prevent move, use ref or ref mut
- |
+LL | //~^ ERROR cannot move out of type `[Foo]`
+LL | //~| cannot move out
+LL | //~| to prevent move
LL | Foo { string: ref b }] => {
- | ^^^^^
+ |
error: aborting due to previous error
LL | match vec {
| ^^^ cannot move out of here
LL | &mut [_a, //~ ERROR cannot move out
- | -- help: to prevent move, use ref or ref mut: `ref _a`
+ | --
+ | |
+ | data moved here
+ | help: to prevent move, use ref or ref mut: `ref _a`
error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:57:13
| ^^^ cannot move out of here
...
LL | _b] => {}
- | -- help: to prevent move, use ref or ref mut: `ref _b`
+ | --
+ | |
+ | data moved here
+ | help: to prevent move, use ref or ref mut: `ref _b`
error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:70:13
|
LL | match vec {
| ^^^ cannot move out of here
+LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out
+ | -- -- -- ... and here
+ | | |
+ | | ... and here
+ | data moved here
help: to prevent move, use ref or ref mut
|
-LL | &mut [ref _a, _b, _c] => {} //~ ERROR cannot move out
- | ^^^^^^
-help: to prevent move, use ref or ref mut
- |
-LL | &mut [_a, ref _b, _c] => {} //~ ERROR cannot move out
- | ^^^^^^
-help: to prevent move, use ref or ref mut
- |
-LL | &mut [_a, _b, ref _c] => {} //~ ERROR cannot move out
- | ^^^^^^
+LL | &mut [ref _a, ref _b, ref _c] => {} //~ ERROR cannot move out
+ | ^^^^^^ ^^^^^^ ^^^^^^
error[E0508]: cannot move out of type `[std::boxed::Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:82:13
= note: move occurs because the value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `maybe` (Mir)
- --> $DIR/issue-41962.rs:17:30
+ --> $DIR/issue-41962.rs:17:16
|
LL | if let Some(thing) = maybe {
- | ----- ^^^^^ value used here after move
- | |
- | value moved here
+ | ^^^^^-----^
+ | | |
+ | | value moved here
+ | value used here after move
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
-error[E0382]: borrow of moved value: `maybe` (Mir)
- --> $DIR/issue-41962.rs:17:30
+error[E0382]: use of moved value (Mir)
+ --> $DIR/issue-41962.rs:17:21
|
LL | if let Some(thing) = maybe {
- | ----- ^^^^^ value borrowed here after move
- | |
- | value moved here
+ | ^^^^^ value moved here in previous iteration of loop
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `maybe` (Mir)
- --> $DIR/issue-41962.rs:17:16
+ --> $DIR/issue-41962.rs:17:30
|
LL | if let Some(thing) = maybe {
- | ^^^^^-----^
- | | |
- | | value moved here
- | value used here after move
+ | ----- ^^^^^ value used here after move
+ | |
+ | value moved here
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
-error[E0382]: use of moved value (Mir)
- --> $DIR/issue-41962.rs:17:21
+error[E0382]: borrow of moved value: `maybe` (Mir)
+ --> $DIR/issue-41962.rs:17:30
|
LL | if let Some(thing) = maybe {
- | ^^^^^ value moved here in previous iteration of loop
+ | ----- ^^^^^ value borrowed here after move
+ | |
+ | value moved here
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
LL | let opt = a.iter().enumerate().find(|(_, &s)| {
| ^^^^^-^
| | |
+ | | data moved here
| | help: to prevent move, use ref or ref mut: `ref s`
| cannot move out of borrowed content
--- /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.
+
+// This is a regression test for #52967, where we discovered that in
+// the initial deployment of NLL for the 2018 edition, I forgot to
+// turn on two-phase-borrows in addition to `-Z borrowck=migrate`.
+
+// revisions: ast zflags edition
+//[zflags]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+//[edition]compile-flags: --edition 2018
+
+// run-pass
+
+fn the_bug() {
+ let mut stuff = ("left", "right");
+ match stuff {
+ (ref mut left, _) if *left == "left" => { *left = "new left"; }
+ _ => {}
+ }
+ assert_eq!(stuff, ("new left", "right"));
+}
+
+fn main() {
+ the_bug();
+}
| ^^^^^^^^^^^^^^^ second mutable borrow occurs here
LL | inner_second.use_mut();
LL | inner_first.use_mut();
- | ----------- borrow later used here
+ | ----------- borrow used here in later iteration of loop
error: aborting due to 2 previous errors
error[E0597]: borrowed value does not live long enough
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:21
|
-LL | fn gimme_static_mut_let() -> &'static mut u32 {
- | _______________________________________________-
-LL | | let ref mut x = 1234543; //~ ERROR
- | | ^^^^^^^ temporary value does not live long enough
-LL | | x
-LL | | }
- | | -
- | | |
- | |_temporary value only lives until here
- | borrow later used here
+LL | let ref mut x = 1234543; //~ ERROR
+ | ^^^^^^^ temporary value does not live long enough
+LL | x
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:20:25
|
-LL | fn gimme_static_mut_let_nested() -> &'static mut u32 {
- | ______________________________________________________-
-LL | | let (ref mut x, ) = (1234543, ); //~ ERROR
- | | ^^^^^^^^^^^ temporary value does not live long enough
-LL | | x
-LL | | }
- | | -
- | | |
- | |_temporary value only lives until here
- | borrow later used here
+LL | let (ref mut x, ) = (1234543, ); //~ ERROR
+ | ^^^^^^^^^^^ temporary value does not live long enough
+LL | x
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
error[E0597]: borrowed value does not live long enough
--> $DIR/promote-ref-mut-in-let-issue-46557.rs:25:11
error[E0499]: cannot borrow `foo` as mutable more than once at a time
- --> $DIR/two-phase-multi-mut.rs:23:16
+ --> $DIR/two-phase-multi-mut.rs:23:5
|
LL | foo.method(&mut foo);
- | -----------^^^^^^^^-
+ | ^^^^^^^^^^^--------^
| | |
- | | second mutable borrow occurs here
- | first mutable borrow occurs here
+ | | first mutable borrow occurs here
+ | second mutable borrow occurs here
| borrow later used here
error[E0499]: cannot borrow `foo` as mutable more than once at a time
- --> $DIR/two-phase-multi-mut.rs:23:5
+ --> $DIR/two-phase-multi-mut.rs:23:16
|
LL | foo.method(&mut foo);
- | ^^^^^^^^^^^--------^
+ | -----------^^^^^^^^-
| | |
- | | first mutable borrow occurs here
- | second mutable borrow occurs here
+ | | second mutable borrow occurs here
+ | first mutable borrow occurs here
| borrow later used here
error: aborting due to 2 previous errors
LL | match (S {f:"foo".to_string()}) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
LL | S {f:_s} => {} //~ ERROR cannot move out
- | -- help: to prevent move, use ref or ref mut: `ref _s`
+ | --
+ | |
+ | data moved here
+ | help: to prevent move, use ref or ref mut: `ref _s`
error: aborting due to previous error
--- /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.
+
+// compile-pass
+
+const PARSE_BOOL: Option<&'static str> = None;
+static FOO: (Option<&str>, u32) = (PARSE_BOOL, 42);
+
+fn main() {}
}
const fn read_field3() -> Field3 {
- const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR exhibits undefined behavior
+ const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR cannot be used
FIELD3
}
-error[E0080]: this constant likely exhibits undefined behavior
+error: this constant cannot be used
--> $DIR/union-const-eval-field.rs:37:5
|
-LL | const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR exhibits undefined behavior
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined bytes
+LL | const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR cannot be used
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
|
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+ = note: #[deny(const_err)] on by default
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0080`.
const UNION: DummyUnion = DummyUnion { field1: 1065353216 };
-const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR this constant likely exhibits undefined
+const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR this constant cannot be used
-const FIELD_PATH: Struct = Struct { //~ ERROR this constant likely exhibits undefined behavior
+const FIELD_PATH: Struct = Struct { //~ ERROR this constant cannot be used
a: 42,
b: unsafe { UNION.field3 },
};
-error[E0080]: this constant likely exhibits undefined behavior
+error: this constant cannot be used
--> $DIR/union-ice.rs:23:1
|
-LL | const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR this constant likely exhibits undefined
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined bytes
+LL | const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR this constant cannot be used
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempted to read undefined bytes
|
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+ = note: #[deny(const_err)] on by default
-error[E0080]: this constant likely exhibits undefined behavior
+error: this constant cannot be used
--> $DIR/union-ice.rs:25:1
|
-LL | / const FIELD_PATH: Struct = Struct { //~ ERROR this constant likely exhibits undefined behavior
+LL | / const FIELD_PATH: Struct = Struct { //~ ERROR this constant cannot be used
LL | | a: 42,
LL | | b: unsafe { UNION.field3 },
LL | | };
- | |__^ type validation failed: encountered undefined bytes at .b
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+ | |__^ attempted to read undefined bytes
error[E0080]: this constant likely exhibits undefined behavior
--> $DIR/union-ice.rs:35:1
--> $DIR/issue-39544.rs:26:17
|
LL | fn foo<'z>(&'z self) {
- | -------- help: consider changing this to be a mutable reference: `&mut self`
+ | -------- help: consider changing this to be a mutable reference: `&'z mut self`
LL | let _ = &mut self.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
--> $DIR/issue-39544.rs:35:17
|
LL | fn foo2<'a>(&'a self, other: &Z) {
- | -------- help: consider changing this to be a mutable reference: `&mut self`
+ | -------- help: consider changing this to be a mutable reference: `&'a mut self`
LL | let _ = &mut self.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
--> $DIR/issue-39544.rs:40:17
|
LL | fn foo3<'a>(self: &'a Self, other: &Z) {
- | -------- help: consider changing this to be a mutable reference: `&mut Z`
+ | -------- help: consider changing this to be a mutable reference: `&'a mut Self`
LL | let _ = &mut self.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
pub use std::panic;
#[macro_export]
-macro_rules! panic { () => {} } //~ ERROR a macro named `panic` has already been exported
+macro_rules! panic { () => {} } //~ ERROR the name `panic` is defined multiple times
fn main() {}
-error: a macro named `panic` has already been exported
+error[E0255]: the name `panic` is defined multiple times
--> $DIR/duplicate-check-macro-exports.rs:16:1
|
-LL | macro_rules! panic { () => {} } //~ ERROR a macro named `panic` has already been exported
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `panic` already exported
+LL | pub use std::panic;
+ | ---------- previous import of the macro `panic` here
+...
+LL | macro_rules! panic { () => {} } //~ ERROR the name `panic` is defined multiple times
+ | ^^^^^^^^^^^^^^^^^^ `panic` redefined here
|
-note: previous macro export here
- --> $DIR/duplicate-check-macro-exports.rs:13:9
+ = note: `panic` must be defined only once in the macro namespace of this module
+help: You can use `as` to change the binding name of the import
|
-LL | pub use std::panic;
- | ^^^^^^^^^^
+LL | pub use std::panic as other_panic;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0255`.
error[E0505]: cannot move out of `fancy_num` because it is borrowed
--> $DIR/E0504.rs:19:13
|
-LL | let fancy_ref = &fancy_num;
- | ---------- borrow of `fancy_num` occurs here
+LL | let fancy_ref = &fancy_num;
+ | ---------- borrow of `fancy_num` occurs here
LL |
-LL | let x = move || {
- | _____________^
-LL | | println!("child function: {}", fancy_num.num); //~ ERROR E0504
-LL | | };
- | |_____^ move out of `fancy_num` occurs here
+LL | let x = move || {
+ | ^^^^^^^ move out of `fancy_num` occurs here
+LL | println!("child function: {}", fancy_num.num); //~ ERROR E0504
+ | --------- move occurs due to use in closure
...
-LL | println!("main function: {}", fancy_ref.num);
- | ------------- borrow later used here
+LL | println!("main function: {}", fancy_ref.num);
+ | ------------- borrow later used here
error: aborting due to previous error
-error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
--> $DIR/feature-gate-macros_in_extern.rs:29:5
|
LL | returns_isize!(rust_get_test_int);
|
= help: add #![feature(macros_in_extern)] to the crate attributes to enable
-error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
--> $DIR/feature-gate-macros_in_extern.rs:31:5
|
LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
|
= help: add #![feature(macros_in_extern)] to the crate attributes to enable
-error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
--> $DIR/feature-gate-macros_in_extern.rs:33:5
|
LL | emits_nothing!();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(use_extern_macros)]
+
fn main() {
- #[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
+ #[rustfmt::skip] //~ ERROR tool attributes are unstable
let x = 3
;
}
-error[E0658]: scoped attribute `rustfmt::skip` is experimental (see issue #44690)
- --> $DIR/feature-gate-tool_attributes.rs:12:5
+error[E0658]: tool attributes are unstable (see issue #44690)
+ --> $DIR/feature-gate-tool_attributes.rs:14:5
|
-LL | #[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
+LL | #[rustfmt::skip] //~ ERROR tool attributes are unstable
| ^^^^^^^^^^^^^^^^
|
= help: add #![feature(tool_attributes)] to the crate attributes to enable
| |
| `*cell` dropped here while still borrowed
| borrow later used here, when `gen` is dropped
- |
- = note: values in a scope are dropped in the opposite order they are defined
error[E0597]: `ref_` does not live long enough
--> $DIR/dropck.rs:22:11
error[E0382]: use of moved value: `foo.x`
- --> $DIR/fields-move.rs:38:42
+ --> $DIR/fields-move.rs:28:9
|
LL | $foo.x
| ------ value moved here
...
+LL | $foo.x //~ ERROR use of moved value: `foo.x`
+ | ^^^^^^ value used here after move
+...
LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
- | ^^^^^ value used here after move
+ | ----- value moved here
+LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
+ | ----------------- in this macro invocation
|
= note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `foo.x`
- --> $DIR/fields-move.rs:28:9
+ --> $DIR/fields-move.rs:38:42
|
LL | $foo.x
| ------ value moved here
...
-LL | $foo.x //~ ERROR use of moved value: `foo.x`
- | ^^^^^^ value used here after move
-...
LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
- | ----- value moved here
-LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
- | ----------------- in this macro invocation
+ | ^^^^^ value used here after move
|
= note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait
error: unsatisfied lifetime constraints
--> $DIR/static-return-lifetime-infered.rs:21:9
|
+LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
+ | -- lifetime `'a` defined here
LL | self.x.iter().map(|a| a.0)
| ^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
--- /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(decl_macro)]
+
+macro_rules! define_exported { () => {
+ #[macro_export]
+ macro_rules! exported {
+ () => ()
+ }
+}}
+macro_rules! define_panic { () => {
+ #[macro_export]
+ macro_rules! panic {
+ () => ()
+ }
+}}
+macro_rules! define_include { () => {
+ #[macro_export]
+ macro_rules! include {
+ () => ()
+ }
+}}
+
+use inner1::*;
+
+mod inner1 {
+ pub macro exported() {}
+}
+
+exported!(); //~ ERROR `exported` is ambiguous
+
+mod inner2 {
+ define_exported!();
+}
+
+fn main() {
+ panic!(); //~ ERROR `panic` is ambiguous
+ //~^ ERROR `panic` is ambiguous
+}
+
+mod inner3 {
+ define_panic!();
+}
+
+mod inner4 {
+ define_include!();
+}
+
+include!(); //~ ERROR `include` is ambiguous
--- /dev/null
+error[E0659]: `exported` is ambiguous
+ --> $DIR/local-modularized-tricky-fail-1.rs:38:1
+ |
+LL | exported!(); //~ ERROR `exported` is ambiguous
+ | ^^^^^^^^
+ |
+note: `exported` could refer to the name defined here
+ --> $DIR/local-modularized-tricky-fail-1.rs:15:5
+ |
+LL | / macro_rules! exported {
+LL | | () => ()
+LL | | }
+ | |_____^
+...
+LL | define_exported!();
+ | ------------------- in this macro invocation
+note: `exported` could also refer to the name imported here
+ --> $DIR/local-modularized-tricky-fail-1.rs:32:5
+ |
+LL | use inner1::*;
+ | ^^^^^^^^^
+ = note: macro-expanded macros do not shadow
+
+error[E0659]: `include` is ambiguous
+ --> $DIR/local-modularized-tricky-fail-1.rs:57:1
+ |
+LL | include!(); //~ ERROR `include` is ambiguous
+ | ^^^^^^^
+ |
+note: `include` could refer to the name defined here
+ --> $DIR/local-modularized-tricky-fail-1.rs:27:5
+ |
+LL | / macro_rules! include {
+LL | | () => ()
+LL | | }
+ | |_____^
+...
+LL | define_include!();
+ | ------------------ in this macro invocation
+ = note: `include` is also a builtin macro
+ = note: macro-expanded macros do not shadow
+
+error[E0659]: `panic` is ambiguous
+ --> $DIR/local-modularized-tricky-fail-1.rs:45:5
+ |
+LL | panic!(); //~ ERROR `panic` is ambiguous
+ | ^^^^^
+ |
+note: `panic` could refer to the name defined here
+ --> $DIR/local-modularized-tricky-fail-1.rs:21:5
+ |
+LL | / macro_rules! panic {
+LL | | () => ()
+LL | | }
+ | |_____^
+...
+LL | define_panic!();
+ | ---------------- in this macro invocation
+ = note: `panic` is also a builtin macro
+ = note: macro-expanded macros do not shadow
+
+error[E0659]: `panic` is ambiguous
+ --> $DIR/local-modularized-tricky-fail-1.rs:45:5
+ |
+LL | panic!(); //~ ERROR `panic` is ambiguous
+ | ^^^^^^^^^
+ |
+note: `panic` could refer to the name defined here
+ --> $DIR/local-modularized-tricky-fail-1.rs:21:5
+ |
+LL | / macro_rules! panic {
+LL | | () => ()
+LL | | }
+ | |_____^
+...
+LL | define_panic!();
+ | ---------------- in this macro invocation
+ = note: `panic` is also a builtin macro
+ = note: macro-expanded macros do not shadow
+ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
--- /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.
+
+// `#[macro_export] macro_rules` that doen't originate from macro expansions can be placed
+// into the root module soon enough to act as usual items and shadow globs and preludes.
+
+#![feature(decl_macro)]
+
+// `macro_export` shadows globs
+use inner1::*;
+
+mod inner1 {
+ pub macro exported() {}
+}
+
+exported!();
+
+mod deep {
+ fn deep() {
+ type Deeper = [u8; {
+ #[macro_export]
+ macro_rules! exported {
+ () => ( struct Б; ) //~ ERROR non-ascii idents are not fully supported
+ }
+
+ 0
+ }];
+ }
+}
+
+// `macro_export` shadows std prelude
+fn main() {
+ panic!();
+}
+
+mod inner3 {
+ #[macro_export]
+ macro_rules! panic {
+ () => ( struct Г; ) //~ ERROR non-ascii idents are not fully supported
+ }
+}
+
+// `macro_export` shadows builtin macros
+include!();
+
+mod inner4 {
+ #[macro_export]
+ macro_rules! include {
+ () => ( struct Д; ) //~ ERROR non-ascii idents are not fully supported
+ }
+}
--- /dev/null
+error[E0658]: non-ascii idents are not fully supported. (see issue #28979)
+ --> $DIR/local-modularized-tricky-fail-2.rs:30:32
+ |
+LL | exported!();
+ | ------------ in this macro invocation
+...
+LL | () => ( struct Б; ) //~ ERROR non-ascii idents are not fully supported
+ | ^
+ |
+ = help: add #![feature(non_ascii_idents)] to the crate attributes to enable
+
+error[E0658]: non-ascii idents are not fully supported. (see issue #28979)
+ --> $DIR/local-modularized-tricky-fail-2.rs:46:24
+ |
+LL | panic!();
+ | --------- in this macro invocation
+...
+LL | () => ( struct Г; ) //~ ERROR non-ascii idents are not fully supported
+ | ^
+ |
+ = help: add #![feature(non_ascii_idents)] to the crate attributes to enable
+
+error[E0658]: non-ascii idents are not fully supported. (see issue #28979)
+ --> $DIR/local-modularized-tricky-fail-2.rs:56:24
+ |
+LL | include!();
+ | ----------- in this macro invocation
+...
+LL | () => ( struct Д; ) //~ ERROR non-ascii idents are not fully supported
+ | ^
+ |
+ = help: add #![feature(non_ascii_idents)] to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
--- /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.
+
+// compile-pass
+
+#![feature(use_extern_macros)]
+
+macro_rules! define_exported { () => {
+ #[macro_export]
+ macro_rules! exported {
+ () => ()
+ }
+}}
+
+mod inner1 {
+ use super::*;
+ exported!();
+}
+
+mod inner2 {
+ define_exported!();
+}
+
+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.
+
+// compile-pass
+
+#![feature(use_extern_macros)]
+
+#[macro_export(local_inner_macros)]
+macro_rules! dollar_crate_exported {
+ (1) => { $crate::exported!(); };
+ (2) => { exported!(); };
+}
+
+// Before `exported` is defined
+exported!();
+
+mod inner {
+
+ ::exported!();
+ crate::exported!();
+ dollar_crate_exported!(1);
+ dollar_crate_exported!(2);
+
+ mod inner_inner {
+ #[macro_export]
+ macro_rules! exported {
+ () => ()
+ }
+ }
+
+ // After `exported` is defined
+ ::exported!();
+ crate::exported!();
+ dollar_crate_exported!(1);
+ dollar_crate_exported!(2);
+}
+
+exported!();
+
+fn main() {}
error: unsatisfied lifetime constraints
--> $DIR/issue-10291.rs:12:5
|
+LL | fn test<'x>(x: &'x isize) {
+ | -- lifetime `'x` defined here
LL | drop::<Box<for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static`
| ----------- mutable borrow occurs here
LL | println!("access {}", foo.x);
LL | ptr = box Foo { x: ptr.x + 1 };
- | --- previous borrow occurs due to use of `ptr` in closure
+ | --- first borrow occurs due to use of `ptr` in closure
...
LL | test(&*ptr);
| -----^^^^^-
// except according to those terms.
fn main() {
- print!(test!());
+ print!(testo!());
//~^ ERROR: format argument must be a string literal
}
error: format argument must be a string literal
--> $DIR/issue-11692-1.rs:12:12
|
-LL | print!(test!());
- | ^^^^^^^
+LL | print!(testo!());
+ | ^^^^^^^^
help: you might be missing a string literal to format with
|
-LL | print!("{}", test!());
+LL | print!("{}", testo!());
| ^^^^^
error: aborting due to previous error
fn main() {
concat!(test!());
- //~^ ERROR cannot find macro `test!` in this scope
+ //~^ ERROR expected a macro, found non-macro attribute
}
-error: cannot find macro `test!` in this scope
+error: expected a macro, found non-macro attribute
--> $DIR/issue-11692-2.rs:12:13
|
LL | concat!(test!());
--> $DIR/issue-11873.rs:14:14
|
LL | let mut f = || v.push(2);
- | ------------ borrow of `v` occurs here
+ | -- - borrow occurs due to use in closure
+ | |
+ | borrow of `v` occurs here
LL | let _w = v; //~ ERROR: cannot move out of `v`
| ^ move out of `v` occurs here
LL |
|
LL | match (l1, l2) {
| ^^^^^^^^ cannot move out of here
+LL | (&[], &[]) => println!("both empty"),
+LL | (&[], &[hd, ..]) | (&[hd, ..], &[])
+ | -- data moved here
+...
+LL | (&[hd1, ..], &[hd2, ..])
+ | --- ... and here
help: to prevent move, use ref or ref mut
|
LL | (&[], &[ref hd, ..]) | (&[hd, ..], &[])
- | ^^^^^^
-help: to prevent move, use ref or ref mut
- |
+LL | => println!("one empty"),
+LL | //~^^ ERROR: cannot move out of type `[T]`, a non-copy slice
+LL | //~^^^ ERROR: cannot move out of type `[T]`, a non-copy slice
LL | (&[hd1, ..], &[ref hd2, ..])
- | ^^^^^^^
+ |
error[E0508]: cannot move out of type `[T]`, a non-copy slice
--> $DIR/issue-12567.rs:14:11
|
LL | match (l1, l2) {
| ^^^^^^^^ cannot move out of here
+LL | (&[], &[]) => println!("both empty"),
+LL | (&[], &[hd, ..]) | (&[hd, ..], &[])
+ | -- data moved here
+...
+LL | (&[hd1, ..], &[hd2, ..])
+ | --- ... and here
help: to prevent move, use ref or ref mut
|
LL | (&[], &[ref hd, ..]) | (&[hd, ..], &[])
- | ^^^^^^
-help: to prevent move, use ref or ref mut
- |
+LL | => println!("one empty"),
+LL | //~^^ ERROR: cannot move out of type `[T]`, a non-copy slice
+LL | //~^^^ ERROR: cannot move out of type `[T]`, a non-copy slice
LL | (&[ref hd1, ..], &[hd2, ..])
- | ^^^^^^^
+ |
error: aborting due to 2 previous errors
--> $DIR/issue-18783.rs:17:21
|
LL | c.push(Box::new(|| y = 0));
- | -- - previous borrow occurs due to use of `y` in closure
+ | -- - first borrow occurs due to use of `y` in closure
| |
| first mutable borrow occurs here
LL | c.push(Box::new(|| y = 0));
- | ^^ - borrow occurs due to use of `y` in closure
+ | ^^ - second borrow occurs due to use of `y` in closure
| |
| second mutable borrow occurs here
LL | //~^ ERROR cannot borrow `y` as mutable more than once at a time
--> $DIR/issue-18783.rs:26:29
|
LL | Push::push(&c, Box::new(|| y = 0));
- | -- - previous borrow occurs due to use of `y` in closure
+ | -- - first borrow occurs due to use of `y` in closure
| |
| first mutable borrow occurs here
LL | Push::push(&c, Box::new(|| y = 0));
- | ^^ - borrow occurs due to use of `y` in closure
+ | ^^ - second borrow occurs due to use of `y` in closure
| |
| second mutable borrow occurs here
LL | //~^ ERROR cannot borrow `y` as mutable more than once at a time
--> $DIR/issue-24357.rs:16:12
|
LL | let f = move || { let y = x; };
- | ---------------------- value moved here
+ | ------- - variable moved due to use in closure
+ | |
+ | value moved into closure here
LL | //~^ NOTE value moved (into closure) here
LL | let z = x;
| ^ value used here after move
error[E0505]: cannot move out of `b` because it is borrowed
- --> $DIR/issue-27282-move-match-input-into-guard.rs:26:16
+ --> $DIR/issue-27282-move-match-input-into-guard.rs:26:17
|
LL | match b {
| - borrow of `b` occurs here
LL | &mut false => {},
LL | _ if { (|| { let bar = b; *bar = false; })();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move out of `b` occurs here
+ | ^^ - move occurs due to use in closure
+ | |
+ | move out of `b` occurs here
...
LL | &mut true => { println!("You might think we should get here"); },
| --------- borrow later used here
--> $DIR/issue-27282-move-match-input-into-guard.rs:29:14
|
LL | _ if { (|| { let bar = b; *bar = false; })();
- | ----------------------------------- value moved here
+ | -- - variable moved due to use in closure
+ | |
+ | value moved into closure here
...
LL | &mut true => { println!("You might think we should get here"); },
| ^^^^ value used here after move
| - borrow occurs here
...
LL | (|| { *x = None; drop(force_fn_once); })();
- | ^^ - borrow occurs due to use of `x` in closure
+ | ^^ - second borrow occurs due to use of `x` in closure
| |
| closure construction occurs here
...
| - borrow occurs here
...
LL | (|| { *x = None; drop(force_fn_once); })();
- | ^^ - borrow occurs due to use of `x` in closure
+ | ^^ - second borrow occurs due to use of `x` in closure
| |
| closure construction occurs here
...
-error[E0597]: borrowed value does not live long enough
- --> $DIR/issue-27592.rs:26:33
- |
-LL | write(|| format_args!("{}", String::from("Hello world")));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here
- | |
- | temporary value does not live long enough
-
error[E0597]: borrowed value does not live long enough
--> $DIR/issue-27592.rs:26:27
|
| |
| temporary value does not live long enough
+error[E0597]: borrowed value does not live long enough
+ --> $DIR/issue-27592.rs:26:33
+ |
+LL | write(|| format_args!("{}", String::from("Hello world")));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here
+ | |
+ | temporary value does not live long enough
+
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0597`.
| ^^ cannot move out of captured variable in an `FnMut` closure
error[E0597]: `v` does not live long enough
- --> $DIR/issue-4335.rs:16:17
+ --> $DIR/issue-4335.rs:16:21
|
LL | id(Box::new(|| *v))
- | ^^^^^ borrowed value does not live long enough
+ | -- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `v` dropped here while still borrowed
--- /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.
+
+// rust-lang/rust#45696: This test is checking that we can return
+// mutable borrows owned by boxes even when the boxes are dropped.
+//
+// We will explicitly test AST-borrowck, NLL, and migration modes;
+// thus we will also skip the automated compare-mode=nll.
+
+// revisions: ast nll migrate
+// ignore-compare-mode-nll
+
+#![cfg_attr(nll, feature(nll))]
+//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+
+// run-pass
+
+// This function shows quite directly what is going on: We have a
+// reborrow of contents within the box.
+fn return_borrow_from_dropped_box_1(x: Box<&mut u32>) -> &mut u32 { &mut **x }
+
+// This function is the way you'll probably see this in practice (the
+// reborrow is now implicit).
+fn return_borrow_from_dropped_box_2(x: Box<&mut u32>) -> &mut u32 { *x }
+
+// For the remaining tests we just add some fields or other
+// indirection to ensure that the compiler isn't just special-casing
+// the above `Box<&mut T>` as the only type that would work.
+
+// Here we add a tuple of indirection between the box and the
+// reference.
+type BoxedTup<'a, 'b> = Box<(&'a mut u32, &'b mut u32)>;
+
+fn return_borrow_of_field_from_dropped_box_1<'a>(x: BoxedTup<'a, '_>) -> &'a mut u32 {
+ &mut *x.0
+}
+
+fn return_borrow_of_field_from_dropped_box_2<'a>(x: BoxedTup<'a, '_>) -> &'a mut u32 {
+ x.0
+}
+
+fn return_borrow_from_dropped_tupled_box_1<'a>(x: (BoxedTup<'a, '_>, &mut u32)) -> &'a mut u32 {
+ &mut *(x.0).0
+}
+
+fn return_borrow_from_dropped_tupled_box_2<'a>(x: (BoxedTup<'a, '_>, &mut u32)) -> &'a mut u32 {
+ (x.0).0
+}
+
+fn basic_tests() {
+ let mut x = 2;
+ let mut y = 3;
+ let mut z = 4;
+ *return_borrow_from_dropped_box_1(Box::new(&mut x)) += 10;
+ assert_eq!((x, y, z), (12, 3, 4));
+ *return_borrow_from_dropped_box_2(Box::new(&mut x)) += 10;
+ assert_eq!((x, y, z), (22, 3, 4));
+ *return_borrow_of_field_from_dropped_box_1(Box::new((&mut x, &mut y))) += 10;
+ assert_eq!((x, y, z), (32, 3, 4));
+ *return_borrow_of_field_from_dropped_box_2(Box::new((&mut x, &mut y))) += 10;
+ assert_eq!((x, y, z), (42, 3, 4));
+ *return_borrow_from_dropped_tupled_box_1((Box::new((&mut x, &mut y)), &mut z)) += 10;
+ assert_eq!((x, y, z), (52, 3, 4));
+ *return_borrow_from_dropped_tupled_box_2((Box::new((&mut x, &mut y)), &mut z)) += 10;
+ assert_eq!((x, y, z), (62, 3, 4));
+}
+
+// These scribbling tests have been transcribed from
+// issue-45696-scribble-on-boxed-borrow.rs
+//
+// In the context of that file, these tests are meant to show cases
+// that should be *accepted* by the compiler, so here we are actually
+// checking that the code we get when they are compiled matches our
+// expectations.
+
+struct Scribble<'a>(&'a mut u32);
+
+impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } }
+
+// this is okay, in both AST-borrowck and NLL: The `Scribble` here *has*
+// to strictly outlive `'a`
+fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 {
+ &mut *s.0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 {
+ &mut *(*s).0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_boxed_borrowed_scribble<'a>(s: Box<Box<&'a mut Scribble>>) -> &'a mut u32 {
+ &mut *(**s).0
+}
+
+fn scribbling_tests() {
+ let mut x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *borrowed_scribble(&mut long_lived) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+ x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+ x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+}
+
+fn main() {
+ basic_tests();
+ scribbling_tests();
+}
--- /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.
+
+// rust-lang/rust#45696: This test checks the compiler won't infinite
+// loop when you declare a variable of type `struct A(Box<A>, ...);`
+// (which is impossible to construct but *is* possible to declare; see
+// also issues #4287, #44933, and #52852).
+//
+// We will explicitly test AST-borrowck, NLL, and migration modes;
+// thus we will also skip the automated compare-mode=nll.
+
+// revisions: ast nll migrate
+// ignore-compare-mode-nll
+
+#![cfg_attr(nll, feature(nll))]
+//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+
+// run-pass
+
+// This test has structs and functions that are by definiton unusable
+// all over the place, so just go ahead and allow dead_code
+#![allow(dead_code)]
+
+// direct regular recursion with indirect ownership via box
+struct C { field: Box<C> }
+
+// direct non-regular recursion with indirect ownership via box
+struct D { field: Box<(D, D)> }
+
+// indirect regular recursion with indirect ownership via box.
+struct E { field: F }
+struct F { field: Box<E> }
+
+// indirect non-regular recursion with indirect ownership via box.
+struct G { field: (H, H) }
+struct H { field: Box<G> }
+
+// These enums are cases that are not currently hit by the
+// `visit_terminator_drop` recursion down a type's structural
+// definition.
+//
+// But it seems prudent to include them in this test as variants on
+// the above, in that they are similarly non-constructable data types
+// with destructors that would diverge.
+enum I { One(Box<I>) }
+enum J { One(Box<J>), Two(Box<J>) }
+
+fn impossible_to_call_c(_c: C) { }
+fn impossible_to_call_d(_d: D) { }
+fn impossible_to_call_e(_e: E) { }
+fn impossible_to_call_f(_f: F) { }
+fn impossible_to_call_g(_g: G) { }
+fn impossible_to_call_h(_h: H) { }
+fn impossible_to_call_i(_i: I) { }
+fn impossible_to_call_j(_j: J) { }
+
+fn main() {
+
+}
--- /dev/null
+error: compilation successful
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:89:1
+ |
+LL | / fn main() { //[ast]~ ERROR compilation successful
+LL | | //[migrate]~^ ERROR compilation successful
+LL | | let mut x = 1;
+LL | | {
+... |
+LL | | *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10;
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+warning[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:63:5
+ |
+LL | &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 62:14...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:14
+ |
+LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 {
+ | ^^
+ = warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
+ It represents potential unsoundness in your code.
+ This warning will become a hard error in the future.
+
+warning[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5
+ |
+LL | &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20
+ |
+LL | fn boxed_scribbled<'a>(s: Box<Scribble<'a>>) -> &'a mut u32 {
+ | ^^
+ = warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
+ It represents potential unsoundness in your code.
+ This warning will become a hard error in the future.
+
+warning[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:83:5
+ |
+LL | &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26
+ |
+LL | fn boxed_boxed_scribbled<'a>(s: Box<Box<Scribble<'a>>>) -> &'a mut u32 {
+ | ^^
+ = warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
+ It represents potential unsoundness in your code.
+ This warning will become a hard error in the future.
+
+error: compilation successful
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:89:1
+ |
+LL | / fn main() { //[ast]~ ERROR compilation successful
+LL | | //[migrate]~^ ERROR compilation successful
+LL | | let mut x = 1;
+LL | | {
+... |
+LL | | *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10;
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+error[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:63:5
+ |
+LL | &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 62:14...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:14
+ |
+LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 {
+ | ^^
+
+error[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5
+ |
+LL | &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20
+ |
+LL | fn boxed_scribbled<'a>(s: Box<Scribble<'a>>) -> &'a mut u32 {
+ | ^^
+
+error[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:83:5
+ |
+LL | &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26
+ |
+LL | fn boxed_boxed_scribbled<'a>(s: Box<Box<Scribble<'a>>>) -> &'a mut u32 {
+ | ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /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.
+
+// rust-lang/rust#45696: This test is checking that we *cannot* return
+// mutable borrows that would be scribbled over by destructors before
+// the return occurs.
+//
+// We will explicitly test AST-borrowck, NLL, and migration modes;
+// thus we will also skip the automated compare-mode=nll.
+
+// revisions: ast nll migrate
+// ignore-compare-mode-nll
+
+// This test is going to pass in the ast and migrate revisions,
+// because the AST-borrowck accepted this code in the past (see notes
+// below). So we use `#[rustc_error]` to keep the outcome as an error
+// in all scenarios, and rely on the stderr files to show what the
+// actual behavior is. (See rust-lang/rust#49855.)
+#![feature(rustc_attrs)]
+
+#![cfg_attr(nll, feature(nll))]
+//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+
+struct Scribble<'a>(&'a mut u32);
+
+impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } }
+
+// this is okay, in both AST-borrowck and NLL: The `Scribble` here *has*
+// to strictly outlive `'a`
+fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 {
+ &mut *s.0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 {
+ &mut *(*s).0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_boxed_borrowed_scribble<'a>(s: Box<Box<&'a mut Scribble>>) -> &'a mut u32 {
+ &mut *(**s).0
+}
+
+// this is not okay: in between the time that we take the mutable
+// borrow and the caller receives it as a return value, the drop of
+// `s` will scribble on it, violating our aliasing guarantees.
+//
+// * (Maybe in the future the two-phase borrows system will be
+// extended to support this case. But for now, it is an error in
+// NLL, even with two-phase borrows.)
+//
+// In any case, the AST-borrowck was not smart enough to know that
+// this should be an error. (Which is perhaps the essence of why
+// rust-lang/rust#45696 arose in the first place.)
+fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 {
+ &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ //[migrate]~^ WARNING `*s.0` does not live long enough [E0597]
+ //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility
+}
+
+// This, by analogy to previous case, is *also* not okay.
+//
+// (But again, AST-borrowck was not smart enogh to know that this
+// should be an error.)
+fn boxed_scribbled<'a>(s: Box<Scribble<'a>>) -> &'a mut u32 {
+ &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ //[migrate]~^ WARNING `*s.0` does not live long enough [E0597]
+ //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility
+}
+
+// This, by analogy to previous case, is *also* not okay.
+//
+// (But again, AST-borrowck was not smart enogh to know that this
+// should be an error.)
+fn boxed_boxed_scribbled<'a>(s: Box<Box<Scribble<'a>>>) -> &'a mut u32 {
+ &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ //[migrate]~^ WARNING `*s.0` does not live long enough [E0597]
+ //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility
+}
+
+#[rustc_error]
+fn main() { //[ast]~ ERROR compilation successful
+ //[migrate]~^ ERROR compilation successful
+ let mut x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *borrowed_scribble(&mut long_lived) += 10;
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10;
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10;
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ *scribbled(Scribble(&mut x)) += 10;
+ *boxed_scribbled(Box::new(Scribble(&mut x))) += 10;
+ *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10;
+}
--- /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.
+
+
+// compile-pass
+
+#![feature(nll)]
+
+fn fibs(n: u32) -> impl Iterator<Item=u128> {
+ (0 .. n)
+ .scan((0, 1), |st, _| {
+ *st = (st.1, st.0 + st.1);
+ Some(*st)
+ })
+ .map(&|(f, _)| f)
+}
+
+fn main() {
+ println!("{:?}", fibs(10).collect::<Vec<_>>());
+}
--- /dev/null
+error: unsatisfied lifetime constraints
+ --> $DIR/issue-49824.rs:22:9
+ |
+LL | || {
+ | _____-
+ | |_____|
+ | ||
+LL | || || {
+ | ||_________^
+LL | ||| let _y = &mut x;
+LL | ||| }
+ | |||_________^ requires that `'1` must outlive `'2`
+LL | || };
+ | || -
+ | ||_____|
+ | |______lifetime `'1` represents the closure body
+ | lifetime `'2` appears in return type
+
+error: aborting due to previous error
+
--- /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(rustc_attrs)]
+
+// This test checks that a failure occurs with NLL but does not fail with the
+// legacy AST output. Check issue-49824.nll.stderr for expected compilation error
+// output under NLL and #49824 for more information.
+
+#[rustc_error]
+fn main() {
+ //~^ compilation successful
+ let mut x = 0;
+ || {
+ || {
+ let _y = &mut x;
+ }
+ };
+}
--- /dev/null
+error: compilation successful
+ --> $DIR/issue-49824.rs:18:1
+ |
+LL | / fn main() {
+LL | | //~^ compilation successful
+LL | | let mut x = 0;
+LL | | || {
+... |
+LL | | };
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
// compile-pass
-#![feature(use_extern_macros, decl_macro)]
+#![feature(decl_macro)]
mod type_ns {
pub type A = u8;
| ^^^^ borrowed value does not live long enough
LL | //~^ ERROR `line` does not live long enough
LL | println!("accumulator before add_assign {:?}", acc.map);
- | ------- borrow later used here
+ | ------- borrow used here in later iteration of loop
...
LL | }
| - `line` dropped here while still borrowed
error: unsatisfied lifetime constraints
--> $DIR/issue-52213.rs:13:11
|
+LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | match (&t,) { //~ ERROR cannot infer an appropriate lifetime
LL | ((u,),) => u,
| ^ requires that `'a` must outlive `'b`
--> $DIR/issue-6801.rs:29:13
|
LL | let sq = || { *x * *x };
- | -------------- borrow of `x` occurs here
+ | -- - borrow occurs due to use in closure
+ | |
+ | borrow of `x` occurs here
LL |
LL | twice(x); //~ ERROR: cannot move out of
| ^ move out of `x` occurs here
],
"label": null,
"suggested_replacement": "1 / (2 + 3)",
- "suggestion_applicability": "Unspecified",
+ "suggestion_applicability": "MachineApplicable",
"expansion": null
}
],
--- /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(use_extern_macros, extern_prelude)]
+
+mod m {
+ fn check() {
+ Vec::clone!(); //~ ERROR failed to resolve. Not a module `Vec`
+ u8::clone!(); //~ ERROR failed to resolve. Not a module `u8`
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0433]: failed to resolve. Not a module `Vec`
+ --> $DIR/macro-path-prelude-fail-1.rs:15:9
+ |
+LL | Vec::clone!(); //~ ERROR failed to resolve. Not a module `Vec`
+ | ^^^ Not a module `Vec`
+
+error[E0433]: failed to resolve. Not a module `u8`
+ --> $DIR/macro-path-prelude-fail-1.rs:16:9
+ |
+LL | u8::clone!(); //~ ERROR failed to resolve. Not a module `u8`
+ | ^^ Not a module `u8`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
--- /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(use_extern_macros)]
+
+mod m {
+ fn check() {
+ Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
+ }
+}
+
+fn main() {}
--- /dev/null
+error: fail to resolve non-ident macro path
+ --> $DIR/macro-path-prelude-fail-2.rs:15:9
+ |
+LL | Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /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(use_extern_macros)]
+
+#[derive(inline)] //~ ERROR expected a macro, found non-macro attribute
+struct S;
+
+fn main() {
+ inline!(); //~ ERROR expected a macro, found non-macro attribute
+}
--- /dev/null
+error: expected a macro, found non-macro attribute
+ --> $DIR/macro-path-prelude-fail-3.rs:13:10
+ |
+LL | #[derive(inline)] //~ ERROR expected a macro, found non-macro attribute
+ | ^^^^^^
+
+error: expected a macro, found non-macro attribute
+ --> $DIR/macro-path-prelude-fail-3.rs:17:5
+ |
+LL | inline!(); //~ ERROR expected a macro, found non-macro attribute
+ | ^^^^^^
+
+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.
+
+// compile-pass
+
+#![feature(use_extern_macros, extern_prelude)]
+
+mod m {
+ fn check() {
+ std::panic!(); // OK
+ }
+}
+
+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.
+
+// aux-build:macro-in-other-crate.rs
+
+#![feature(decl_macro, extern_prelude)]
+
+macro_rules! add_macro_expanded_things_to_macro_prelude {() => {
+ #[macro_use]
+ extern crate macro_in_other_crate;
+}}
+
+add_macro_expanded_things_to_macro_prelude!();
+
+mod m1 {
+ fn check() {
+ inline!(); //~ ERROR `inline` is ambiguous
+ }
+}
+
+mod m2 {
+ pub mod std {
+ pub macro panic() {}
+ }
+}
+
+mod m3 {
+ use m2::*; // glob-import user-defined `std`
+ fn check() {
+ std::panic!(); //~ ERROR `std` is ambiguous
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0659]: `inline` is ambiguous
+ --> $DIR/macro-path-prelude-shadowing.rs:24:9
+ |
+LL | inline!(); //~ ERROR `inline` is ambiguous
+ | ^^^^^^
+ |
+note: `inline` could refer to the name imported here
+ --> $DIR/macro-path-prelude-shadowing.rs:16:5
+ |
+LL | #[macro_use]
+ | ^^^^^^^^^^^^
+...
+LL | add_macro_expanded_things_to_macro_prelude!();
+ | ---------------------------------------------- in this macro invocation
+note: `inline` could also refer to the name defined here
+ --> $DIR/macro-path-prelude-shadowing.rs:24:9
+ |
+LL | inline!(); //~ ERROR `inline` is ambiguous
+ | ^^^^^^
+ = note: macro-expanded macro imports do not shadow
+
+error[E0659]: `std` is ambiguous
+ --> $DIR/macro-path-prelude-shadowing.rs:37:9
+ |
+LL | std::panic!(); //~ ERROR `std` is ambiguous
+ | ^^^^^^^^^^
+ |
+note: `std` could refer to the name imported here
+ --> $DIR/macro-path-prelude-shadowing.rs:35:9
+ |
+LL | use m2::*; // glob-import user-defined `std`
+ | ^^^^^
+note: `std` could also refer to the name defined here
+ --> $DIR/macro-path-prelude-shadowing.rs:37:9
+ |
+LL | std::panic!(); //~ ERROR `std` is ambiguous
+ | ^^^
+ = note: consider adding an explicit import of `std` to disambiguate
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
println!("{} %f", "one", 2.0); //~ ERROR never used
println!("Hi there, $NAME.", NAME="Tim"); //~ ERROR never used
+ println!("$1 $0 $$ $NAME", 1, 2, NAME=3);
+ //~^ ERROR multiple unused formatting arguments
}
--> $DIR/format-foreign.rs:24:39
|
LL | println!("Hi there, $NAME.", NAME="Tim"); //~ ERROR never used
- | ^^^^^
+ | ----- ^^^^^
+ | |
+ | help: format specifiers use curly braces: `{NAME}`
|
- = help: `$NAME` should be written as `{NAME}`
= note: shell formatting not supported; see the documentation for `std::fmt`
-error: aborting due to 5 previous errors
+error: multiple unused formatting arguments
+ --> $DIR/format-foreign.rs:25:32
+ |
+LL | println!("$1 $0 $$ $NAME", 1, 2, NAME=3);
+ | ---------------- ^ ^ ^
+ | |
+ | multiple missing formatting specifiers
+ |
+ = note: shell formatting not supported; see the documentation for `std::fmt`
+help: format specifiers use curly braces
+ |
+LL | println!("{1} {0} $$ {NAME}", 1, 2, NAME=3);
+ | ^^^ ^^^ ^^^^^^
+
+error: aborting due to 6 previous errors
--> $DIR/format-unused-lables.rs:24:9
|
LL | println!("Some more $STUFF",
- | ------------------ multiple missing formatting specifiers
+ | ------------------
+ | | |
+ | | help: format specifiers use curly braces: `{STUFF}`
+ | multiple missing formatting specifiers
LL | "woo!", //~ ERROR multiple unused formatting arguments
| ^^^^^^
LL | STUFF=
LL | , UNUSED="args");
| ^^^^^^
|
- = help: `$STUFF` should be written as `{STUFF}`
= note: shell formatting not supported; see the documentation for `std::fmt`
error: aborting due to 4 previous errors
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expanding `println! { "Hello, World!" }`
- = note: to `{
- # [ cfg ( not ( stage0 ) ) ] {
- ( $crate :: io :: _print ( format_args_nl ! ( "Hello, World!" ) ) ) ; } # [
- cfg ( stage0 ) ] { print ! ( "{}/n" , format_args ! ( "Hello, World!" ) ) } }`
+ = note: to `{ $crate :: io :: _print ( format_args_nl ! ( "Hello, World!" ) ) ; }`
--- /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.
+
+// check that accesses due to a closure capture give a special note
+
+#![feature(nll)]
+
+fn closure_imm_capture_conflict(mut x: i32) {
+ let r = &mut x;
+ || x; //~ ERROR
+ r.use_mut();
+}
+
+fn closure_mut_capture_conflict(mut x: i32) {
+ let r = &mut x;
+ || x = 2; //~ ERROR
+ r.use_mut();
+}
+
+fn closure_unique_capture_conflict(mut x: &mut i32) {
+ let r = &mut x;
+ || *x = 2; //~ ERROR
+ r.use_mut();
+}
+
+fn closure_copy_capture_conflict(mut x: i32) {
+ let r = &mut x;
+ move || x; //~ ERROR
+ r.use_ref();
+}
+
+fn closure_move_capture_conflict(mut x: String) {
+ let r = &x;
+ || x; //~ ERROR
+ r.use_ref();
+}
+
+fn closure_imm_capture_moved(mut x: String) {
+ let r = x;
+ || x.len(); //~ ERROR
+}
+
+fn closure_mut_capture_moved(mut x: String) {
+ let r = x;
+ || x = String::new(); //~ ERROR
+}
+
+fn closure_unique_capture_moved(x: &mut String) {
+ let r = x;
+ || *x = String::new(); //~ ERROR
+}
+
+fn closure_move_capture_moved(x: &mut String) {
+ let r = x;
+ || x; //~ ERROR
+}
+
+fn main() {}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } }
+impl<T> Fake for T { }
--- /dev/null
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+ --> $DIR/closure-access-spans.rs:17:5
+ |
+LL | let r = &mut x;
+ | ------ mutable borrow occurs here
+LL | || x; //~ ERROR
+ | ^^ - second borrow occurs due to use of `x` in closure
+ | |
+ | immutable borrow occurs here
+LL | r.use_mut();
+ | - borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+ --> $DIR/closure-access-spans.rs:23:5
+ |
+LL | let r = &mut x;
+ | ------ first mutable borrow occurs here
+LL | || x = 2; //~ ERROR
+ | ^^ - second borrow occurs due to use of `x` in closure
+ | |
+ | second mutable borrow occurs here
+LL | r.use_mut();
+ | - borrow later used here
+
+error[E0500]: closure requires unique access to `x` but it is already borrowed
+ --> $DIR/closure-access-spans.rs:29:5
+ |
+LL | let r = &mut x;
+ | ------ borrow occurs here
+LL | || *x = 2; //~ ERROR
+ | ^^ - second borrow occurs due to use of `x` in closure
+ | |
+ | closure construction occurs here
+LL | r.use_mut();
+ | - borrow later used here
+
+error[E0503]: cannot use `x` because it was mutably borrowed
+ --> $DIR/closure-access-spans.rs:35:13
+ |
+LL | let r = &mut x;
+ | ------ borrow of `x` occurs here
+LL | move || x; //~ ERROR
+ | ^ use of borrowed `x`
+LL | r.use_ref();
+ | - borrow later used here
+
+error[E0505]: cannot move out of `x` because it is borrowed
+ --> $DIR/closure-access-spans.rs:41:5
+ |
+LL | let r = &x;
+ | -- borrow of `x` occurs here
+LL | || x; //~ ERROR
+ | ^^ - move occurs due to use in closure
+ | |
+ | move out of `x` occurs here
+LL | r.use_ref();
+ | - borrow later used here
+
+error[E0382]: borrow of moved value: `x`
+ --> $DIR/closure-access-spans.rs:47:5
+ |
+LL | let r = x;
+ | - value moved here
+LL | || x.len(); //~ ERROR
+ | ^^ - borrow occurs due to use in closure
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `x`
+ --> $DIR/closure-access-spans.rs:52:5
+ |
+LL | let r = x;
+ | - value moved here
+LL | || x = String::new(); //~ ERROR
+ | ^^ - borrow occurs due to use in closure
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `x`
+ --> $DIR/closure-access-spans.rs:57:5
+ |
+LL | let r = x;
+ | - value moved here
+LL | || *x = String::new(); //~ ERROR
+ | ^^ - borrow occurs due to use in closure
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x`
+ --> $DIR/closure-access-spans.rs:62:5
+ |
+LL | let r = x;
+ | - value moved here
+LL | || x; //~ ERROR
+ | ^^ - use occurs due to use in closure
+ | |
+ | value used here after move
+ |
+ = note: move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
+
+error: aborting due to 9 previous errors
+
+Some errors occurred: E0382, E0499, E0500, E0502, E0503, E0505.
+For more information about an error, try `rustc --explain E0382`.
--- /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.
+
+// check that existing borrows due to a closure capture give a special note
+
+#![feature(nll)]
+
+fn move_while_borrowed(x: String) {
+ let f = || x.len();
+ let y = x; //~ ERROR
+ f.use_ref();
+}
+
+fn borrow_mut_while_borrowed(mut x: i32) {
+ let f = || x;
+ let y = &mut x; //~ ERROR
+ f.use_ref();
+}
+
+fn drop_while_borrowed() {
+ let f;
+ {
+ let x = 1;
+ f = || x; //~ ERROR
+ }
+ f.use_ref();
+}
+
+fn assign_while_borrowed(mut x: i32) {
+ let f = || x;
+ x = 1; //~ ERROR
+ f.use_ref();
+}
+
+fn copy_while_borrowed_mut(mut x: i32) {
+ let f = || x = 0;
+ let y = x; //~ ERROR
+ f.use_ref();
+}
+
+fn borrow_while_borrowed_mut(mut x: i32) {
+ let f = || x = 0;
+ let y = &x; //~ ERROR
+ f.use_ref();
+}
+
+fn borrow_mut_while_borrowed_mut(mut x: i32) {
+ let f = || x = 0;
+ let y = &mut x; //~ ERROR
+ f.use_ref();
+}
+
+fn drop_while_borrowed_mut() {
+ let f;
+ {
+ let mut x = 1;
+ f = || x = 0; //~ ERROR
+ }
+ f.use_ref();
+}
+
+fn assign_while_borrowed_mut(mut x: i32) {
+ let f = || x = 0;
+ x = 1; //~ ERROR
+ f.use_ref();
+}
+
+fn copy_while_borrowed_unique(x: &mut i32) {
+ let f = || *x = 0;
+ let y = x; //~ ERROR
+ f.use_ref();
+}
+
+fn borrow_while_borrowed_unique(x: &mut i32) {
+ let f = || *x = 0;
+ let y = &x; //~ ERROR
+ f.use_ref();
+}
+
+fn borrow_mut_while_borrowed_unique(mut x: &mut i32) {
+ let f = || *x = 0;
+ let y = &mut x; //~ ERROR
+ f.use_ref();
+}
+
+fn drop_while_borrowed_unique() {
+ let mut z = 1;
+ let f;
+ {
+ let x = &mut z;
+ f = || *x = 0; //~ ERROR
+ }
+ f.use_ref();
+}
+
+fn assign_while_borrowed_unique(x: &mut i32) {
+ let f = || *x = 0;
+ *x = 1; //~ ERROR
+ f.use_ref();
+}
+
+fn main() {}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } }
+impl<T> Fake for T { }
--- /dev/null
+error[E0505]: cannot move out of `x` because it is borrowed
+ --> $DIR/closure-borrow-spans.rs:17:13
+ |
+LL | let f = || x.len();
+ | -- - borrow occurs due to use in closure
+ | |
+ | borrow of `x` occurs here
+LL | let y = x; //~ ERROR
+ | ^ move out of `x` occurs here
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
+ --> $DIR/closure-borrow-spans.rs:23:13
+ |
+LL | let f = || x;
+ | -- - first borrow occurs due to use of `x` in closure
+ | |
+ | immutable borrow occurs here
+LL | let y = &mut x; //~ ERROR
+ | ^^^^^^ mutable borrow occurs here
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/closure-borrow-spans.rs:31:16
+ |
+LL | f = || x; //~ ERROR
+ | -- ^ borrowed value does not live long enough
+ | |
+ | value captured here
+LL | }
+ | - `x` dropped here while still borrowed
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/closure-borrow-spans.rs:38:5
+ |
+LL | let f = || x;
+ | -- - borrow occurs due to use in closure
+ | |
+ | borrow of `x` occurs here
+LL | x = 1; //~ ERROR
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0503]: cannot use `x` because it was mutably borrowed
+ --> $DIR/closure-borrow-spans.rs:44:13
+ |
+LL | let f = || x = 0;
+ | -- - borrow occurs due to use of `x` in closure
+ | |
+ | borrow of `x` occurs here
+LL | let y = x; //~ ERROR
+ | ^ use of borrowed `x`
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+ --> $DIR/closure-borrow-spans.rs:50:13
+ |
+LL | let f = || x = 0;
+ | -- - first borrow occurs due to use of `x` in closure
+ | |
+ | mutable borrow occurs here
+LL | let y = &x; //~ ERROR
+ | ^^ immutable borrow occurs here
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+ --> $DIR/closure-borrow-spans.rs:56:13
+ |
+LL | let f = || x = 0;
+ | -- - first borrow occurs due to use of `x` in closure
+ | |
+ | first mutable borrow occurs here
+LL | let y = &mut x; //~ ERROR
+ | ^^^^^^ second mutable borrow occurs here
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/closure-borrow-spans.rs:64:16
+ |
+LL | f = || x = 0; //~ ERROR
+ | -- ^ borrowed value does not live long enough
+ | |
+ | value captured here
+LL | }
+ | - `x` dropped here while still borrowed
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/closure-borrow-spans.rs:71:5
+ |
+LL | let f = || x = 0;
+ | -- - borrow occurs due to use in closure
+ | |
+ | borrow of `x` occurs here
+LL | x = 1; //~ ERROR
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0505]: cannot move out of `x` because it is borrowed
+ --> $DIR/closure-borrow-spans.rs:77:13
+ |
+LL | let f = || *x = 0;
+ | -- - borrow occurs due to use in closure
+ | |
+ | borrow of `x` occurs here
+LL | let y = x; //~ ERROR
+ | ^ move out of `x` occurs here
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access
+ --> $DIR/closure-borrow-spans.rs:83:13
+ |
+LL | let f = || *x = 0;
+ | -- - first borrow occurs due to use of `x` in closure
+ | |
+ | closure construction occurs here
+LL | let y = &x; //~ ERROR
+ | ^^ borrow occurs here
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0501]: cannot borrow `x` as mutable because previous closure requires unique access
+ --> $DIR/closure-borrow-spans.rs:89:13
+ |
+LL | let f = || *x = 0;
+ | -- - first borrow occurs due to use of `x` in closure
+ | |
+ | closure construction occurs here
+LL | let y = &mut x; //~ ERROR
+ | ^^^^^^ borrow occurs here
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0597]: `x` does not live long enough
+ --> $DIR/closure-borrow-spans.rs:98:17
+ |
+LL | f = || *x = 0; //~ ERROR
+ | -- ^ borrowed value does not live long enough
+ | |
+ | value captured here
+LL | }
+ | - `x` dropped here while still borrowed
+LL | f.use_ref();
+ | - borrow later used here
+
+error[E0506]: cannot assign to `*x` because it is borrowed
+ --> $DIR/closure-borrow-spans.rs:105:5
+ |
+LL | let f = || *x = 0;
+ | -- - borrow occurs due to use in closure
+ | |
+ | borrow of `*x` occurs here
+LL | *x = 1; //~ ERROR
+ | ^^^^^^ assignment to borrowed `*x` occurs here
+LL | f.use_ref();
+ | - borrow later used here
+
+error: aborting due to 14 previous errors
+
+Some errors occurred: E0499, E0501, E0502, E0503, E0505, E0506, E0597.
+For more information about an error, try `rustc --explain E0499`.
#![allow(unused)]
#![feature(nll)]
-// Should have one error per assigment
+// Should have one error per assignment
fn one_closure(x: i32) {
||
--- /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.
+
+// check that moves due to a closure capture give a special note
+
+#![feature(nll)]
+
+fn move_after_move(x: String) {
+ || x;
+ let y = x; //~ ERROR
+}
+
+fn borrow_after_move(x: String) {
+ || x;
+ let y = &x; //~ ERROR
+}
+
+fn borrow_mut_after_move(mut x: String) {
+ || x;
+ let y = &mut x; //~ ERROR
+}
+
+fn fn_ref<F: Fn()>(f: F) -> F { f }
+fn fn_mut<F: FnMut()>(f: F) -> F { f }
+
+fn main() {}
--- /dev/null
+error[E0382]: use of moved value: `x`
+ --> $DIR/closure-move-spans.rs:17:13
+ |
+LL | || x;
+ | -- - variable moved due to use in closure
+ | |
+ | value moved into closure here
+LL | let y = x; //~ ERROR
+ | ^ value used here after move
+ |
+ = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `x`
+ --> $DIR/closure-move-spans.rs:22:13
+ |
+LL | || x;
+ | -- - variable moved due to use in closure
+ | |
+ | value moved into closure here
+LL | let y = &x; //~ ERROR
+ | ^^ value borrowed here after move
+ |
+ = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `x`
+ --> $DIR/closure-move-spans.rs:27:13
+ |
+LL | || x;
+ | -- - variable moved due to use in closure
+ | |
+ | value moved into closure here
+LL | let y = &mut x; //~ ERROR
+ | ^^^^^^ value borrowed here after move
+ |
+ = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
LL | let mut closure = expect_sig(|p, y| *p = y);
| ^
-error: unsatisfied lifetime constraints
- --> $DIR/escape-argument-callee.rs:36:45
- |
-LL | let mut closure = expect_sig(|p, y| *p = y);
- | - - ^^^^^^ requires that `'1` must outlive `'2`
- | | |
- | | has type `&'1 i32`
- | has type `&mut &'2 i32`
-
note: No external requirements
--> $DIR/escape-argument-callee.rs:36:38
|
for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) i32))
]
+error: unsatisfied lifetime constraints
+ --> $DIR/escape-argument-callee.rs:36:45
+ |
+LL | let mut closure = expect_sig(|p, y| *p = y);
+ | - - ^^^^^^ requires that `'1` must outlive `'2`
+ | | |
+ | | has type `&'1 i32`
+ | has type `&mut &'2 i32`
+
note: No external requirements
--> $DIR/escape-argument-callee.rs:30:1
|
{
let y = 22;
- let mut closure = || { //~ ERROR `y` does not live long enough [E0597]
- let mut closure1 = || p = &y;
+ let mut closure = || {
+ let mut closure1 = || p = &y; //~ ERROR `y` does not live long enough [E0597]
closure1();
};
note: External requirements
--> $DIR/escape-upvar-nested.rs:31:32
|
-LL | let mut closure1 = || p = &y;
+LL | let mut closure1 = || p = &y; //~ ERROR `y` does not live long enough [E0597]
| ^^^^^^^^^
|
= note: defining type: DefId(0/1:10 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]::{{closure}}[0]) with closure substs [
note: External requirements
--> $DIR/escape-upvar-nested.rs:30:27
|
-LL | let mut closure = || { //~ ERROR `y` does not live long enough [E0597]
+LL | let mut closure = || {
| ___________________________^
-LL | | let mut closure1 = || p = &y;
+LL | | let mut closure1 = || p = &y; //~ ERROR `y` does not live long enough [E0597]
LL | | closure1();
LL | | };
| |_________^
= note: defining type: DefId(0/0:3 ~ escape_upvar_nested[317d]::test[0]) with substs []
error[E0597]: `y` does not live long enough
- --> $DIR/escape-upvar-nested.rs:30:27
+ --> $DIR/escape-upvar-nested.rs:31:40
|
-LL | let mut closure = || { //~ ERROR `y` does not live long enough [E0597]
- | ___________________________^
-LL | | let mut closure1 = || p = &y;
-LL | | closure1();
-LL | | };
- | |_________^ borrowed value does not live long enough
+LL | let mut closure = || {
+ | -- value captured here
+LL | let mut closure1 = || p = &y; //~ ERROR `y` does not live long enough [E0597]
+ | ^ borrowed value does not live long enough
...
-LL | }
- | - `y` dropped here while still borrowed
+LL | }
+ | - `y` dropped here while still borrowed
LL |
-LL | deref(p);
- | - borrow later used here
+LL | deref(p);
+ | - borrow later used here
error: aborting due to previous error
= note: defining type: DefId(0/0:3 ~ escape_upvar_ref[317d]::test[0]) with substs []
error[E0597]: `y` does not live long enough
- --> $DIR/escape-upvar-ref.rs:33:27
+ --> $DIR/escape-upvar-ref.rs:33:35
|
LL | let mut closure = || p = &y;
- | ^^^^^^^^^ borrowed value does not live long enough
+ | -- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `y` dropped here while still borrowed
LL | let p = x.get();
| ^^^^^^^
-error: unsatisfied lifetime constraints
- --> $DIR/propagate-approximated-fail-no-postdom.rs:57:13
- |
-LL | |_outlives1, _outlives2, _outlives3, x, y| {
- | ---------- ---------- has type `std::cell::Cell<&'2 &u32>`
- | |
- | has type `std::cell::Cell<&&'1 u32>`
-...
-LL | demand_y(x, y, p) //~ ERROR
- | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
-
note: No external requirements
--> $DIR/propagate-approximated-fail-no-postdom.rs:53:9
|
for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
]
+error: unsatisfied lifetime constraints
+ --> $DIR/propagate-approximated-fail-no-postdom.rs:57:13
+ |
+LL | |_outlives1, _outlives2, _outlives3, x, y| {
+ | ---------- ---------- has type `std::cell::Cell<&'2 &u32>`
+ | |
+ | has type `std::cell::Cell<&&'1 u32>`
+...
+LL | demand_y(x, y, p) //~ ERROR
+ | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
note: No external requirements
--> $DIR/propagate-approximated-fail-no-postdom.rs:48:1
|
LL | foo(cell, |cell_a, cell_x| {
| ^^^
-error: borrowed data escapes outside of closure
- --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:9
- |
-LL | foo(cell, |cell_a, cell_x| {
- | ------ ------ `cell_x` is a reference that is only valid in the closure body
- | |
- | `cell_a` is declared here, outside of the closure body
-LL | //~^ WARNING not reporting region error due to nll
-LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
- | ^^^^^^^^^^^^^^^^^^^^^^^^ `cell_x` escapes the closure body here
-
note: No external requirements
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:15
|
for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>))
]
+error: borrowed data escapes outside of closure
+ --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:33:9
+ |
+LL | foo(cell, |cell_a, cell_x| {
+ | ------ ------ `cell_x` is a reference that is only valid in the closure body
+ | |
+ | `cell_a` is declared here, outside of the closure body
+LL | //~^ WARNING not reporting region error due to nll
+LL | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ `cell_x` escapes the closure body here
+
note: No external requirements
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:28:1
|
= note: number of external vids: 4
= note: where '_#1r: '_#0r
-error: borrowed data escapes outside of function
- --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5
- |
-LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
- | ------ `cell_a` is a reference that is only valid in the function body
-LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-LL | | //~^ ERROR
-LL | |
-LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
-LL | | });
- | |______^ `cell_a` escapes the function body here
-
note: No external requirements
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:44:1
|
|
= note: defining type: DefId(0/0:6 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]) with substs []
+error: borrowed data escapes outside of function
+ --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:45:5
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ------ `cell_a` is a reference that is only valid in the function body
+LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+LL | | //~^ ERROR
+LL | |
+LL | | // Only works if 'x: 'y:
+LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
+LL | | });
+ | |______^ `cell_a` escapes the function body here
+
error: aborting due to previous error
= note: number of external vids: 5
= note: where '_#1r: '_#0r
-error: borrowed data escapes outside of function
- --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5
- |
-LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
- | ------ `cell_a` is a reference that is only valid in the function body
-LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-LL | | //~^ ERROR
-LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get())
-LL | | //~^ WARNING not reporting region error due to nll
-LL | | });
- | |______^ `cell_a` escapes the function body here
-
note: No external requirements
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:47:1
|
|
= note: defining type: DefId(0/0:6 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]) with substs []
+error: borrowed data escapes outside of function
+ --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:48:5
+ |
+LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
+ | ------ `cell_a` is a reference that is only valid in the function body
+LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+LL | | //~^ ERROR
+LL | | // Only works if 'x: 'y:
+LL | | demand_y(x, y, x.get())
+LL | | //~^ WARNING not reporting region error due to nll
+LL | | });
+ | |______^ `cell_a` escapes the function body here
+
error: aborting due to previous error
LL | demand_y(x, y, x.get())
| ^^^^^^^^^^^^^^^^^^^^^^^
-error: unsatisfied lifetime constraints
- --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9
- |
-LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
- | --------- - has type `&std::cell::Cell<&'1 u32>`
- | |
- | has type `&std::cell::Cell<&'2 &u32>`
-LL | // Only works if 'x: 'y:
-LL | demand_y(x, y, x.get())
- | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
-
note: No external requirements
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:45:47
|
for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>))
]
+error: unsatisfied lifetime constraints
+ --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+ | --------- - has type `&std::cell::Cell<&'1 u32>`
+ | |
+ | has type `&std::cell::Cell<&'2 &u32>`
+LL | // Only works if 'x: 'y:
+LL | demand_y(x, y, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
note: No external requirements
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:44:1
|
LL | demand_y(x, y, x.get())
| ^^^^^^^^^^^^^^^^^^^^^^^
-error: unsatisfied lifetime constraints
- --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:9
- |
-LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
- | ---------- ---------- has type `&std::cell::Cell<&'2 &u32>`
- | |
- | has type `&std::cell::Cell<&'1 &u32>`
-LL | // Only works if 'x: 'y:
-LL | demand_y(x, y, x.get())
- | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
-
note: No external requirements
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:49:47
|
for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>))
]
+error: unsatisfied lifetime constraints
+ --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:9
+ |
+LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+ | ---------- ---------- has type `&std::cell::Cell<&'2 &u32>`
+ | |
+ | has type `&std::cell::Cell<&'1 &u32>`
+LL | // Only works if 'x: 'y:
+LL | demand_y(x, y, x.get())
+ | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
+
note: No external requirements
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:48:1
|
= note: number of external vids: 3
= note: where T: '_#1r
-error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/propagate-from-trait-match.rs:42:36
- |
-LL | establish_relationships(value, |value| {
- | ____________________________________^
-LL | | //~^ ERROR the parameter type `T` may not live long enough
-LL | |
-LL | | // This function call requires that
-... |
-LL | | //~^ WARNING not reporting region error due to nll
-LL | | });
- | |_____^
- |
- = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
-
note: No external requirements
--> $DIR/propagate-from-trait-match.rs:38:1
|
T
]
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/propagate-from-trait-match.rs:42:36
+ |
+LL | establish_relationships(value, |value| {
+ | ____________________________________^
+LL | | //~^ ERROR the parameter type `T` may not live long enough
+LL | |
+LL | | // This function call requires that
+... |
+LL | | //~^ WARNING not reporting region error due to nll
+LL | | });
+ | |_____^
+ |
+ = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
+
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.
error: unsatisfied lifetime constraints
--> $DIR/region-lbr-named-does-not-outlive-static.rs:19:5
|
+LL | fn foo<'a>(x: &'a u32) -> &'static u32 {
+ | -- lifetime `'a` defined here
LL | &*x
| ^^^ requires that `'a` must outlive `'static`
LL | expect_sig(|a, b| b); // ought to return `a`
| ^
-error: unsatisfied lifetime constraints
- --> $DIR/return-wrong-bound-region.rs:21:23
- |
-LL | expect_sig(|a, b| b); // ought to return `a`
- | - - ^ closure was supposed to return data with lifetime `'1` but it is returning data with lifetime `'2`
- | | |
- | | has type `&'1 i32`
- | has type `&'2 i32`
-
note: No external requirements
--> $DIR/return-wrong-bound-region.rs:21:16
|
for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32
]
+error: unsatisfied lifetime constraints
+ --> $DIR/return-wrong-bound-region.rs:21:23
+ |
+LL | expect_sig(|a, b| b); // ought to return `a`
+ | - - ^ closure was supposed to return data with lifetime `'1` but it is returning data with lifetime `'2`
+ | | |
+ | | has type `&'1 i32`
+ | has type `&'2 i32`
+
note: No external requirements
--> $DIR/return-wrong-bound-region.rs:20: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.
+
+// check that liveness due to a closure capture gives a special note
+
+#![feature(nll)]
+
+fn use_as_borrow_capture(mut x: i32) {
+ let y = &x;
+ x = 0; //~ ERROR
+ || *y;
+}
+
+fn use_as_borrow_mut_capture(mut x: i32) {
+ let y = &mut x;
+ x = 0; //~ ERROR
+ || *y = 1;
+}
+
+fn use_as_move_capture(mut x: i32) {
+ let y = &x;
+ x = 0; //~ ERROR
+ move || *y;
+}
+
+fn main() {}
--- /dev/null
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/closure-use-spans.rs:17:5
+ |
+LL | let y = &x;
+ | -- borrow of `x` occurs here
+LL | x = 0; //~ ERROR
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | || *y;
+ | - borrow later captured here by closure
+
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/closure-use-spans.rs:23:5
+ |
+LL | let y = &mut x;
+ | ------ borrow of `x` occurs here
+LL | x = 0; //~ ERROR
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | || *y = 1;
+ | - borrow later captured here by closure
+
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/closure-use-spans.rs:29:5
+ |
+LL | let y = &x;
+ | -- borrow of `x` occurs here
+LL | x = 0; //~ ERROR
+ | ^^^^^ assignment to borrowed `x` occurs here
+LL | move || *y;
+ | - borrow later captured here by closure
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0506`.
--- /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.
+
+// Test messages where a closure capture conflicts with itself because it's in
+// a loop.
+
+#![feature(nll)]
+
+fn repreated_move(x: String) {
+ for i in 0..10 {
+ || x; //~ ERROR
+ }
+}
+
+fn repreated_mut_borrow(mut x: String) {
+ let mut v = Vec::new();
+ for i in 0..10 {
+ v.push(|| x = String::new()); //~ ERROR
+ }
+}
+
+fn repreated_unique_borrow(x: &mut String) {
+ let mut v = Vec::new();
+ for i in 0..10 {
+ v.push(|| *x = String::new()); //~ ERROR
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0382]: use of moved value: `x`
+ --> $DIR/closures-in-loops.rs:18:9
+ |
+LL | || x; //~ ERROR
+ | ^^ - use occurs due to use in closure
+ | |
+ | value moved into closure here in previous iteration of loop
+ |
+ = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
+
+error[E0499]: cannot borrow `x` as mutable more than once at a time
+ --> $DIR/closures-in-loops.rs:25:16
+ |
+LL | v.push(|| x = String::new()); //~ ERROR
+ | ^^ - borrows occur due to use of `x` in closure
+ | |
+ | mutable borrow starts here in previous iteration of loop
+
+error[E0524]: two closures require unique access to `x` at the same time
+ --> $DIR/closures-in-loops.rs:32:16
+ |
+LL | v.push(|| *x = String::new()); //~ ERROR
+ | ^^ - borrows occur due to use of `x` in closure
+ | |
+ | closures are constructed here in different iterations of loop
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0382, E0499, E0524.
+For more information about an error, try `rustc --explain E0382`.
);
}
+// Found when trying to bootstrap rustc
+fn if_guard(x: Result<i32, i32>) {
+ match x {
+ Ok(mut r) | Err(mut r) if true => r = 1,
+ _ => (),
+ }
+}
+
fn main() {
ref_argument(0);
mutable_upvar();
generator_mutable_upvar();
ref_closure_argument();
parse_dot_or_call_expr_with(Vec::new());
+ if_guard(Ok(0));
}
LL | Some(v) => {
LL | map.set(String::new()); // Both AST and MIR error here
| ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
-...
-LL | return v;
- | - borrow later used here
+ |
+note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
+ --> $DIR/get_default.rs:41:1
+ |
+LL | / fn err(map: &mut Map) -> &String {
+LL | | loop {
+LL | | match map.get() {
+LL | | Some(v) => {
+... |
+LL | | }
+LL | | }
+ | |_^
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
--> $DIR/get_default.rs:51:17
LL | Some(v) => {
LL | map.set(String::new()); // Both AST and MIR error here
| ^^^ mutable borrow occurs here
-...
-LL | return v;
- | - borrow later used here
+ |
+note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
+ --> $DIR/get_default.rs:41:1
+ |
+LL | / fn err(map: &mut Map) -> &String {
+LL | | loop {
+LL | | match map.get() {
+LL | | Some(v) => {
+... |
+LL | | }
+LL | | }
+ | |_^
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
--> $DIR/get_default.rs:51:17
| ||
LL | || //~^ ERROR cannot borrow `self.thing` as mutable because it is also borrowed as immutable [E0502]
LL | || &self.number;
- | || ---- previous borrow occurs due to use of `self` in closure
+ | || ---- first borrow occurs due to use of `self` in closure
LL | || });
| || ^
| ||__________|
--- /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.
+//
+
+#![allow(warnings)]
+#![feature(nll)]
+
+trait Bazinga { }
+impl<F> Bazinga for F { }
+
+fn produce1<'a>(data: &'a u32) -> impl Bazinga + 'a {
+ let x = move || {
+ let _data: &'a u32 = data;
+ };
+ x
+}
+
+fn produce2<'a>(data: &'a mut Vec<&'a u32>, value: &'a u32) -> impl Bazinga + 'a {
+ let x = move || {
+ let value: &'a u32 = value;
+ data.push(value);
+ };
+ x
+}
+
+
+fn produce3<'a, 'b: 'a>(data: &'a mut Vec<&'a u32>, value: &'b u32) -> impl Bazinga + 'a {
+ let x = move || {
+ let value: &'a u32 = value;
+ data.push(value);
+ };
+ x
+}
+
+fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
+ let x = move || { //~ ERROR lifetime mismatch
+ let value: &'a u32 = value;
+ data.push(value);
+ };
+ x
+}
+
+fn main() { }
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/issue-52113.rs:43:9
+ |
+LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
+ | -------------------- ------- these two types are declared with different lifetimes...
+LL | let x = move || { //~ ERROR lifetime mismatch
+ | ^ ...but data from `value` flows into `data` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
+++ /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.
-//
-
-#![allow(warnings)]
-#![feature(nll)]
-
-trait Bazinga { }
-impl<F> Bazinga for F { }
-
-fn produce1<'a>(data: &'a u32) -> impl Bazinga + 'a {
- let x = move || {
- let _data: &'a u32 = data;
- };
- x
-}
-
-fn produce2<'a>(data: &'a mut Vec<&'a u32>, value: &'a u32) -> impl Bazinga + 'a {
- let x = move || {
- let value: &'a u32 = value;
- data.push(value);
- };
- x
-}
-
-
-fn produce3<'a, 'b: 'a>(data: &'a mut Vec<&'a u32>, value: &'b u32) -> impl Bazinga + 'a {
- let x = move || {
- let value: &'a u32 = value;
- data.push(value);
- };
- x
-}
-
-fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
- let x = move || { //~ ERROR lifetime mismatch
- let value: &'a u32 = value;
- data.push(value);
- };
- x
-}
-
-fn main() { }
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/issue-52133.rs:43:9
- |
-LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> impl Bazinga + 'b {
- | -------------------- ------- these two types are declared with different lifetimes...
-LL | let x = move || { //~ ERROR lifetime mismatch
- | ^ ...but data from `value` flows into `data` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0623`.
error: unsatisfied lifetime constraints
--> $DIR/mir_check_cast_closure.rs:16:28
|
+LL | fn bar<'a, 'b>() -> fn(&'a u32, &'b u32) -> &'a u32 {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
LL | let g: fn(_, _) -> _ = |_x, y| y;
| ^^^^^^^^^ cast requires that `'b` must outlive `'a`
--> $DIR/mir_check_cast_unsize.rs:17:46
|
LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug {
- | ______________________________________________^
+ | ________--____________________________________^
+ | | |
+ | | lifetime `'a` defined here
LL | | //~^ ERROR unsatisfied lifetime constraints
LL | | x
LL | | //~^ WARNING not reporting region error due to nll
LL | let C(D(s)) = c;
| - ^ cannot move out of here
| |
+ | data moved here
| help: to prevent move, use ref or ref mut: `ref s`
error[E0507]: cannot move out of borrowed content
| ^ cannot move out of here
...
LL | B::U(D(s)) => (),
- | - help: to prevent move, use ref or ref mut: `ref s`
+ | -
+ | |
+ | data moved here
+ | help: to prevent move, use ref or ref mut: `ref s`
error[E0509]: cannot move out of type `D`, which implements the `Drop` trait
--> $DIR/move-errors.rs:105:11
| ^ cannot move out of here
...
LL | (D(s), &t) => (),
- | - help: to prevent move, use ref or ref mut: `ref s`
+ | -
+ | |
+ | data moved here
+ | help: to prevent move, use ref or ref mut: `ref s`
error[E0507]: cannot move out of borrowed content
--> $DIR/move-errors.rs:105:11
| ^ cannot move out of borrowed content
...
LL | (D(s), &t) => (),
- | - help: to prevent move, use ref or ref mut: `ref t`
+ | -
+ | |
+ | data moved here
+ | help: to prevent move, use ref or ref mut: `ref t`
error[E0509]: cannot move out of type `F`, which implements the `Drop` trait
--> $DIR/move-errors.rs:115:11
|
LL | match x {
| ^ cannot move out of here
+LL | //~^ ERROR
+LL | F(s, mut t) => (),
+ | - ----- ... and here
+ | |
+ | data moved here
help: to prevent move, use ref or ref mut
|
-LL | F(ref s, mut t) => (),
- | ^^^^^
-help: to prevent move, use ref or ref mut
- |
-LL | F(s, ref mut t) => (),
- | ^^^^^^^^^
+LL | F(ref s, ref mut t) => (),
+ | ^^^^^ ^^^^^^^^^
error[E0507]: cannot move out of borrowed content
--> $DIR/move-errors.rs:123:11
--- /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.
+
+// Check that mutable promoted length zero arrays don't check for conflicting
+// access
+
+// run-pass
+
+#![feature(nll)]
+
+pub fn main() {
+ let mut x: Vec<&[i32; 0]> = Vec::new();
+ for i in 0..10 {
+ x.push(&[]);
+ }
+}
error[E0597]: borrowed value does not live long enough
--> $DIR/return-ref-mut-issue-46557.rs:17:21
|
-LL | fn gimme_static_mut() -> &'static mut u32 {
- | ___________________________________________-
-LL | | let ref mut x = 1234543; //~ ERROR borrowed value does not live long enough [E0597]
- | | ^^^^^^^ temporary value does not live long enough
-LL | | x
-LL | | }
- | | -
- | | |
- | |_temporary value only lives until here
- | borrow later used here
+LL | let ref mut x = 1234543; //~ ERROR borrowed value does not live long enough [E0597]
+ | ^^^^^^^ temporary value does not live long enough
+LL | x
+LL | }
+ | - temporary value only lives until here
+ |
+ = note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error
= note: number of external vids: 4
= note: where <T as std::iter::Iterator>::Item: '_#2r
-error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
- --> $DIR/projection-no-regions-closure.rs:35:23
- |
-LL | with_signature(x, |mut y| Box::new(y.next()))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`...
-
note: No external requirements
--> $DIR/projection-no-regions-closure.rs:31:1
|
T
]
+error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
+ --> $DIR/projection-no-regions-closure.rs:35:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`...
+
note: External requirements
--> $DIR/projection-no-regions-closure.rs:45:23
|
= note: number of external vids: 5
= note: where <T as std::iter::Iterator>::Item: '_#3r
-error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
- --> $DIR/projection-no-regions-closure.rs:53:23
- |
-LL | with_signature(x, |mut y| Box::new(y.next()))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`...
-
note: No external requirements
--> $DIR/projection-no-regions-closure.rs:49:1
|
T
]
+error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
+ --> $DIR/projection-no-regions-closure.rs:53:23
+ |
+LL | with_signature(x, |mut y| Box::new(y.next()))
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`...
+
note: External requirements
--> $DIR/projection-no-regions-closure.rs:64:23
|
= note: where T: '_#2r
= note: where '_#1r: '_#2r
-error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/projection-one-region-closure.rs:55:29
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`...
-
-error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-closure.rs:55:5
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
-
note: No external requirements
--> $DIR/projection-one-region-closure.rs:51:1
|
T
]
+error: unsatisfied lifetime constraints
+ --> $DIR/projection-one-region-closure.rs:55:5
+ |
+LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/projection-one-region-closure.rs:55:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`...
+
note: External requirements
--> $DIR/projection-one-region-closure.rs:67:29
|
= note: where T: '_#3r
= note: where '_#2r: '_#3r
-error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/projection-one-region-closure.rs:67:29
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
-
-error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-closure.rs:67:5
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
-
note: No external requirements
--> $DIR/projection-one-region-closure.rs:62:1
|
T
]
+error: unsatisfied lifetime constraints
+ --> $DIR/projection-one-region-closure.rs:67:5
+ |
+LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/projection-one-region-closure.rs:67:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
+
note: External requirements
--> $DIR/projection-one-region-closure.rs:89:29
|
= note: where T: '_#3r
= note: where '_#2r: '_#3r
-error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/projection-one-region-closure.rs:89:29
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
-
-error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-closure.rs:89:5
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
-
note: No external requirements
--> $DIR/projection-one-region-closure.rs:74:1
|
T
]
+error: unsatisfied lifetime constraints
+ --> $DIR/projection-one-region-closure.rs:89:5
+ |
+LL | fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/projection-one-region-closure.rs:89:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
+
note: External requirements
--> $DIR/projection-one-region-closure.rs:102:29
|
= note: number of external vids: 5
= note: where '_#1r: '_#2r
-error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-trait-bound-closure.rs:47:5
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
-
note: No external requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:43:1
|
T
]
+error: unsatisfied lifetime constraints
+ --> $DIR/projection-one-region-trait-bound-closure.rs:47:5
+ |
+LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:58:29
|
= note: number of external vids: 5
= note: where '_#2r: '_#3r
-error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-trait-bound-closure.rs:58:5
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
-
note: No external requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:53:1
|
T
]
+error: unsatisfied lifetime constraints
+ --> $DIR/projection-one-region-trait-bound-closure.rs:58:5
+ |
+LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:79:29
|
= note: number of external vids: 5
= note: where '_#2r: '_#3r
-error: unsatisfied lifetime constraints
- --> $DIR/projection-one-region-trait-bound-closure.rs:79:5
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
-
note: No external requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:64:1
|
T
]
+error: unsatisfied lifetime constraints
+ --> $DIR/projection-one-region-trait-bound-closure.rs:79:5
+ |
+LL | fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+
note: External requirements
--> $DIR/projection-one-region-trait-bound-closure.rs:90:29
|
= note: number of external vids: 6
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#2r)>>::AssocType: '_#3r
-error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
- --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: ReFree(DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:18), 'a))`...
-
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:44:1
|
T
]
+error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
+ --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: ReFree(DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:18), 'a))`...
+
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:59:29
|
= note: number of external vids: 6
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
-error[E0309]: the associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
- --> $DIR/projection-two-region-trait-bound-closure.rs:59:29
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `<T as Anything<'_#7r, '_#8r>>::AssocType: ReEarlyBound(0, 'a)`...
-
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:54:1
|
T
]
+error[E0309]: the associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
+ --> $DIR/projection-two-region-trait-bound-closure.rs:59:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Anything<'_#7r, '_#8r>>::AssocType: ReEarlyBound(0, 'a)`...
+
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:80:29
|
= note: number of external vids: 6
= note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r
-error[E0309]: the associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
- --> $DIR/projection-two-region-trait-bound-closure.rs:80:29
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `<T as Anything<'_#7r, '_#8r>>::AssocType: ReEarlyBound(0, 'a)`...
-
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:65:1
|
T
]
+error[E0309]: the associated type `<T as Anything<'_#7r, '_#8r>>::AssocType` may not live long enough
+ --> $DIR/projection-two-region-trait-bound-closure.rs:80:29
+ |
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `<T as Anything<'_#7r, '_#8r>>::AssocType: ReEarlyBound(0, 'a)`...
+
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:91:29
|
= note: number of external vids: 5
= note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r
-error: unsatisfied lifetime constraints
- --> $DIR/projection-two-region-trait-bound-closure.rs:108:5
- |
-LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
-
note: No external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:104:1
|
T
]
+error: unsatisfied lifetime constraints
+ --> $DIR/projection-two-region-trait-bound-closure.rs:108:5
+ |
+LL | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | with_signature(cell, t, |cell, t| require(cell, t));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+
note: External requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:119:29
|
= note: number of external vids: 4
= note: where T: '_#1r
-error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:24
- |
-LL | twice(cell, value, |a, b| invoke(a, b));
- | ^^^^^^^^^^^^^^^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(crate0:DefIndex(1:15), 'a))`...
-
note: No external requirements
--> $DIR/ty-param-closure-approximate-lower-bound.rs:41:1
|
T
]
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:24
+ |
+LL | twice(cell, value, |a, b| invoke(a, b));
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(crate0:DefIndex(1:15), 'a))`...
+
error: aborting due to previous error
For more information about this error, try `rustc --explain E0309`.
= note: number of external vids: 4
= note: where T: '_#2r
-error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-closure-outlives-from-return-type.rs:36:23
- |
-LL | with_signature(x, |y| y)
- | ^^^^^
- |
- = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
-
note: No external requirements
--> $DIR/ty-param-closure-outlives-from-return-type.rs:25:1
|
T
]
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-outlives-from-return-type.rs:36:23
+ |
+LL | with_signature(x, |y| y)
+ | ^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`...
+
error[E0309]: the parameter type `T` may not live long enough
--> $DIR/ty-param-closure-outlives-from-return-type.rs:52:5
|
= note: number of external vids: 4
= note: where T: '_#1r
-error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:26
- |
-LL | with_signature(a, b, |x, y| {
- | __________________________^
-LL | | //~^ ERROR the parameter type `T` may not live long enough
-LL | | //
-LL | | // See `correct_region`, which explains the point of this
-... |
-LL | | //~^ WARNING not reporting region error due to nll
-LL | | })
- | |_____^
- |
- = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(1:14), 'a))`...
-
note: No external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:36:1
|
T
]
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | __________________________^
+LL | | //~^ ERROR the parameter type `T` may not live long enough
+LL | | //
+LL | | // See `correct_region`, which explains the point of this
+... |
+LL | | //~^ WARNING not reporting region error due to nll
+LL | | })
+ | |_____^
+ |
+ = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(1:14), 'a))`...
+
note: External requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:54:26
|
= note: number of external vids: 5
= note: where T: '_#2r
-error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:75:26
- |
-LL | with_signature(a, b, |x, y| {
- | __________________________^
-LL | | //~^ ERROR the parameter type `T` may not live long enough
-LL | | // See `correct_region`
-LL | | require(&x, &y)
-LL | | //~^ WARNING not reporting region error due to nll
-LL | | })
- | |_____^
- |
- = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(1:20), 'a))`...
-
note: No external requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:71:1
|
T
]
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:75:26
+ |
+LL | with_signature(a, b, |x, y| {
+ | __________________________^
+LL | | //~^ ERROR the parameter type `T` may not live long enough
+LL | | // See `correct_region`
+LL | | require(&x, &y)
+LL | | //~^ WARNING not reporting region error due to nll
+LL | | })
+ | |_____^
+ |
+ = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(1:20), 'a))`...
+
note: External requirements
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:89:26
|
error[E0597]: `x` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:19:17
+ --> $DIR/region-borrow-params-issue-29793-small.rs:19:34
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | };
| - `x` dropped here while still borrowed
error[E0597]: `y` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:19:17
+ --> $DIR/region-borrow-params-issue-29793-small.rs:19:45
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | };
| - `y` dropped here while still borrowed
error[E0597]: `x` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:34:17
+ --> $DIR/region-borrow-params-issue-29793-small.rs:34:34
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | };
| - `x` dropped here while still borrowed
error[E0597]: `y` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:34:17
+ --> $DIR/region-borrow-params-issue-29793-small.rs:34:45
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | };
| - `y` dropped here while still borrowed
error[E0597]: `x` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:65:17
+ --> $DIR/region-borrow-params-issue-29793-small.rs:65:34
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | };
| - `x` dropped here while still borrowed
| ^^
error[E0597]: `y` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:65:17
+ --> $DIR/region-borrow-params-issue-29793-small.rs:65:45
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | };
| - `y` dropped here while still borrowed
| ^^
error[E0597]: `x` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:76:17
+ --> $DIR/region-borrow-params-issue-29793-small.rs:76:34
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | };
| - `x` dropped here while still borrowed
| ^^
error[E0597]: `y` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:76:17
+ --> $DIR/region-borrow-params-issue-29793-small.rs:76:45
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | };
| - `y` dropped here while still borrowed
| ^^
error[E0597]: `x` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:100:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:100:38
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `x` dropped here while still borrowed
| ^^
error[E0597]: `y` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:100:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:100:49
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `y` dropped here while still borrowed
| ^^
error[E0597]: `x` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:114:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:114:38
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `x` dropped here while still borrowed
| ^^
error[E0597]: `y` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:114:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:114:49
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `y` dropped here while still borrowed
| ^^
error[E0597]: `x` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:142:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:142:38
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `x` dropped here while still borrowed
| ^^
error[E0597]: `y` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:142:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:142:49
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `y` dropped here while still borrowed
| ^^
error[E0597]: `x` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:157:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:157:38
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `x` dropped here while still borrowed
| ^^
error[E0597]: `y` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:157:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:157:49
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `y` dropped here while still borrowed
| ^^
error[E0597]: `x` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:185:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:185:38
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `x` dropped here while still borrowed
| ^^
error[E0597]: `y` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:185:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:185:49
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `y` dropped here while still borrowed
| ^^
error[E0597]: `x` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:199:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:199:38
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `x` dropped here while still borrowed
| ^^
error[E0597]: `y` does not live long enough
- --> $DIR/region-borrow-params-issue-29793-small.rs:199:21
+ --> $DIR/region-borrow-params-issue-29793-small.rs:199:49
|
LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`)
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+ | --------- ^ borrowed value does not live long enough
+ | |
+ | value captured here
...
LL | }
| - `y` dropped here while still borrowed
error[E0597]: `y` does not live long enough
- --> $DIR/regions-nested-fns-2.rs:16:9
+ --> $DIR/regions-nested-fns-2.rs:18:25
|
-LL | / |z| {
-LL | | //~^ ERROR E0373
-LL | | if false { &y } else { z }
-LL | | });
- | |_________^ borrowed value does not live long enough
-LL | }
- | - `y` dropped here while still borrowed
+LL | |z| {
+ | --- value captured here
+LL | //~^ ERROR E0373
+LL | if false { &y } else { z }
+ | ^ borrowed value does not live long enough
+LL | });
+LL | }
+ | - `y` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
| ^^^^^^^^^^^^ mutable borrow occurs here
LL | //~^ ERROR cannot borrow `foo` as mutable
LL | println!("foo={:?}", *string);
- | ------- borrow later used here
+ | ------- borrow used here in later iteration of loop
error: aborting due to previous error
// aux-build:macro-use-warned-against2.rs
// compile-pass
-#![warn(rust_2018_idioms, unused)]
+#![warn(macro_use_extern_crate, unused)]
#![feature(use_extern_macros)]
#[macro_use] //~ WARN should be replaced at use sites with a `use` statement
note: lint level defined here
--> $DIR/macro-use-warned-against.rs:15:9
|
-LL | #![warn(rust_2018_idioms, unused)]
- | ^^^^^^^^^^^^^^^^
- = note: #[warn(macro_use_extern_crate)] implied by #[warn(rust_2018_idioms)]
+LL | #![warn(macro_use_extern_crate, unused)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
warning: unused `#[macro_use]` import
--> $DIR/macro-use-warned-against.rs:20:1
| ^^^^^^^^^^^^
|
note: lint level defined here
- --> $DIR/macro-use-warned-against.rs:15:27
+ --> $DIR/macro-use-warned-against.rs:15:33
|
-LL | #![warn(rust_2018_idioms, unused)]
- | ^^^^^^
+LL | #![warn(macro_use_extern_crate, unused)]
+ | ^^^^^^
= note: #[warn(unused_imports)] implied by #[warn(unused)]
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:102:5
|
LL | fn assign_field2<'a>(x: &'a Own<Point>) {
- | -------------- help: consider changing this to be a mutable reference: `&mut Own<Point>`
+ | -------------- help: consider changing this to be a mutable reference: `&'a mut Own<Point>`
LL | x.y = 3; //~ ERROR cannot borrow
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:143:6
|
LL | fn assign_method2<'a>(x: &'a Own<Point>) {
- | -------------- help: consider changing this to be a mutable reference: `&mut Own<Point>`
+ | -------------- help: consider changing this to be a mutable reference: `&'a mut Own<Point>`
LL | *x.y_mut() = 3; //~ ERROR cannot borrow
| ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:51:11
|
LL | fn deref_extend_mut1<'a>(x: &'a Own<isize>) -> &'a mut isize {
- | -------------- help: consider changing this to be a mutable reference: `&mut Own<isize>`
+ | -------------- help: consider changing this to be a mutable reference: `&'a mut Own<isize>`
LL | &mut **x //~ ERROR cannot borrow
| ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:63:6
|
LL | fn assign2<'a>(x: &'a Own<isize>) {
- | -------------- help: consider changing this to be a mutable reference: `&mut Own<isize>`
+ | -------------- help: consider changing this to be a mutable reference: `&'a mut Own<isize>`
LL | **x = 3; //~ ERROR cannot borrow
| ^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
| |
LL | | //~^ ERROR: cannot borrow `f` as mutable more than once
LL | | f((Box::new(|| {})))
- | | - borrow occurs due to use of `f` in closure
+ | | - second borrow occurs due to use of `f` in closure
LL | | }));
| |_______- borrow later used here
error[E0505]: cannot move out of `f` because it is borrowed
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:65:16
|
-LL | f(Box::new(|a| {
- | _____-__________^
- | | |
- | |_____borrow of `f` occurs here
- | ||
-LL | || foo(f);
-LL | || //~^ ERROR cannot move `f` into closure because it is borrowed
-LL | || //~| ERROR cannot move out of captured outer variable in an `FnMut` closure
-LL | || }), 3);
- | ||_____^____- borrow later used here
- | |_____|
- | move out of `f` occurs here
+LL | f(Box::new(|a| {
+ | - ^^^ move out of `f` occurs here
+ | |
+ | _____borrow of `f` occurs here
+ | |
+LL | | foo(f);
+ | | - move occurs due to use in closure
+LL | | //~^ ERROR cannot move `f` into closure because it is borrowed
+LL | | //~| ERROR cannot move out of captured outer variable in an `FnMut` closure
+LL | | }), 3);
+ | |__________- borrow later used here
error: aborting due to 5 previous errors
| |
| `*m` dropped here while still borrowed
| borrow later used here, when `m` is dropped
- |
- = note: values in a scope are dropped in the opposite order they are defined
error: aborting due to previous error
-error[E0597]: `b3` does not live long enough
- --> $DIR/dropck_arr_cycle_checked.rs:105:24
+error[E0597]: `b2` does not live long enough
+ --> $DIR/dropck_arr_cycle_checked.rs:103:24
|
-LL | b1.a[1].v.set(Some(&b3));
+LL | b1.a[0].v.set(Some(&b2));
| ^^^ borrowed value does not live long enough
...
LL | }
| -
| |
- | `b3` dropped here while still borrowed
+ | `b2` dropped here while still borrowed
| borrow later used here, when `b1` is dropped
-error[E0597]: `b2` does not live long enough
- --> $DIR/dropck_arr_cycle_checked.rs:103:24
+error[E0597]: `b3` does not live long enough
+ --> $DIR/dropck_arr_cycle_checked.rs:105:24
|
-LL | b1.a[0].v.set(Some(&b2));
+LL | b1.a[1].v.set(Some(&b3));
| ^^^ borrowed value does not live long enough
...
LL | }
| -
| |
- | `b2` dropped here while still borrowed
+ | `b3` dropped here while still borrowed
| borrow later used here, when `b1` is dropped
error[E0597]: `b1` does not live long enough
-error[E0597]: `c3` does not live long enough
- --> $DIR/dropck_vec_cycle_checked.rs:115:24
+error[E0597]: `c2` does not live long enough
+ --> $DIR/dropck_vec_cycle_checked.rs:113:24
|
-LL | c1.v[1].v.set(Some(&c3));
+LL | c1.v[0].v.set(Some(&c2));
| ^^^ borrowed value does not live long enough
...
LL | }
| -
| |
- | `c3` dropped here while still borrowed
+ | `c2` dropped here while still borrowed
| borrow later used here, when `c1` is dropped
-error[E0597]: `c2` does not live long enough
- --> $DIR/dropck_vec_cycle_checked.rs:113:24
+error[E0597]: `c3` does not live long enough
+ --> $DIR/dropck_vec_cycle_checked.rs:115:24
|
-LL | c1.v[0].v.set(Some(&c2));
+LL | c1.v[1].v.set(Some(&c3));
| ^^^ borrowed value does not live long enough
...
LL | }
| -
| |
- | `c2` dropped here while still borrowed
+ | `c3` dropped here while still borrowed
| borrow later used here, when `c1` is dropped
error[E0597]: `c1` does not live long enough
--> $DIR/mut-arg-hint.rs:18:5
|
LL | pub fn foo<'a>(mut a: &'a String) {
- | ---------- help: consider changing this to be a mutable reference: `&mut std::string::String`
+ | ---------- help: consider changing this to be a mutable reference: `&'a mut String`
LL | a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content
| ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable
-error[E0597]: `b` does not live long enough
- --> $DIR/range-2.rs:17:13
+error[E0597]: `a` does not live long enough
+ --> $DIR/range-2.rs:17:9
|
LL | &a..&b
- | ^^ borrowed value does not live long enough
+ | ^^ borrowed value does not live long enough
LL | };
- | - `b` dropped here while still borrowed
+ | - `a` dropped here while still borrowed
...
LL | r.use_ref();
| - borrow later used here
-error[E0597]: `a` does not live long enough
- --> $DIR/range-2.rs:17:9
+error[E0597]: `b` does not live long enough
+ --> $DIR/range-2.rs:17:13
|
LL | &a..&b
- | ^^ borrowed value does not live long enough
+ | ^^ borrowed value does not live long enough
LL | };
- | - `a` dropped here while still borrowed
+ | - `b` dropped here while still borrowed
...
LL | r.use_ref();
| - borrow later used here
--> $DIR/regions-escape-loop-via-variable.rs:21:13
|
LL | let x = 1 + *p;
- | -- borrow later used here
+ | -- borrow used here in later iteration of loop
LL | p = &x;
| ^^ borrowed value does not live long enough
LL | }
| ^ use of borrowed `x`
LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed
LL | _y.push(&mut z);
- | -- borrow later used here
+ | -- borrow used here in later iteration of loop
error[E0503]: cannot use `x` because it was mutably borrowed
--> $DIR/regions-escape-loop-via-vec.rs:16:21
LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed
| ^ use of borrowed `x`
LL | _y.push(&mut z);
- | -- borrow later used here
+ | -- borrow used here in later iteration of loop
+
+error[E0597]: `z` does not live long enough
+ --> $DIR/regions-escape-loop-via-vec.rs:17:17
+ |
+LL | _y.push(&mut z);
+ | -- ^^^^^^ borrowed value does not live long enough
+ | |
+ | borrow used here in later iteration of loop
+...
+LL | }
+ | - `z` dropped here while still borrowed
error[E0503]: cannot use `x` because it was mutably borrowed
--> $DIR/regions-escape-loop-via-vec.rs:19:9
| ------ borrow of `x` occurs here
...
LL | _y.push(&mut z);
- | -- borrow later used here
+ | -- borrow used here in later iteration of loop
LL | //~^ ERROR `z` does not live long enough
LL | x += 1; //~ ERROR cannot assign
| ^^^^^^ use of borrowed `x`
-error[E0597]: `z` does not live long enough
- --> $DIR/regions-escape-loop-via-vec.rs:17:17
- |
-LL | _y.push(&mut z);
- | -- ^^^^^^ borrowed value does not live long enough
- | |
- | borrow later used here
-...
-LL | }
- | - `z` dropped here while still borrowed
-
error: aborting due to 4 previous errors
Some errors occurred: E0503, E0597.
-error[E0597]: `y` does not live long enough
- --> $DIR/send-is-not-static-ensures-scoping.rs:29:16
- |
-LL | scoped(|| {
- | ________________^
-LL | | let _z = y;
-LL | | //~^ ERROR `y` does not live long enough
-LL | | })
- | |_________^ borrowed value does not live long enough
-LL | };
- | - `y` dropped here while still borrowed
-LL |
-LL | bad.join();
- | --- borrow later used here
-
error[E0597]: `x` does not live long enough
--> $DIR/send-is-not-static-ensures-scoping.rs:26:17
|
LL | bad.join();
| --- borrow later used here
+error[E0597]: `y` does not live long enough
+ --> $DIR/send-is-not-static-ensures-scoping.rs:30:22
+ |
+LL | scoped(|| {
+ | -- value captured here
+LL | let _z = y;
+ | ^ borrowed value does not live long enough
+...
+LL | };
+ | - `y` dropped here while still borrowed
+LL |
+LL | bad.join();
+ | --- borrow later used here
+
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0597`.
-error[E0597]: `y` does not live long enough
- --> $DIR/vec_refs_data_with_early_death.rs:29:12
+error[E0597]: `x` does not live long enough
+ --> $DIR/vec_refs_data_with_early_death.rs:27:12
|
-LL | v.push(&y);
+LL | v.push(&x);
| ^^ borrowed value does not live long enough
...
LL | }
| -
| |
- | `y` dropped here while still borrowed
+ | `x` dropped here while still borrowed
| borrow later used here, when `v` is dropped
|
= note: values in a scope are dropped in the opposite order they are defined
-error[E0597]: `x` does not live long enough
- --> $DIR/vec_refs_data_with_early_death.rs:27:12
+error[E0597]: `y` does not live long enough
+ --> $DIR/vec_refs_data_with_early_death.rs:29:12
|
-LL | v.push(&x);
+LL | v.push(&y);
| ^^ borrowed value does not live long enough
...
LL | }
| -
| |
- | `x` dropped here while still borrowed
+ | `y` dropped here while still borrowed
| borrow later used here, when `v` is dropped
|
= note: values in a scope are dropped in the opposite order they are defined
// ignore-aarch64
// ignore-wasm
// ignore-emscripten
+// ignore-mips
+// ignore-mips64
// gate-test-sse4a_target_feature
// gate-test-powerpc_target_feature
// gate-test-avx512_target_feature
error[E0658]: the target feature `avx512bw` is currently unstable (see issue #44839)
- --> $DIR/target-feature-gate.rs:26:18
+ --> $DIR/target-feature-gate.rs:28:18
|
LL | #[target_feature(enable = "avx512bw")]
| ^^^^^^^^^^^^^^^^^^^
// ignore-wasm
// ignore-emscripten
// ignore-mips
+// ignore-mips64
// ignore-powerpc
// ignore-powerpc64
// ignore-powerpc64le
error: #[target_feature] attribute must be of the form #[target_feature(..)]
- --> $DIR/target-feature-wrong.rs:25:1
+ --> $DIR/target-feature-wrong.rs:26:1
|
LL | #[target_feature = "+sse2"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the feature named `foo` is not valid for this target
- --> $DIR/target-feature-wrong.rs:27:18
+ --> $DIR/target-feature-wrong.rs:28:18
|
LL | #[target_feature(enable = "foo")]
| ^^^^^^^^^^^^^^
error: #[target_feature(..)] only accepts sub-keys of `enable` currently
- --> $DIR/target-feature-wrong.rs:29:18
+ --> $DIR/target-feature-wrong.rs:30:18
|
LL | #[target_feature(bar)]
| ^^^
error: #[target_feature(..)] only accepts sub-keys of `enable` currently
- --> $DIR/target-feature-wrong.rs:31:18
+ --> $DIR/target-feature-wrong.rs:32:18
|
LL | #[target_feature(disable = "baz")]
| ^^^^^^^^^^^^^^^
error: #[target_feature(..)] can only be applied to `unsafe` function
- --> $DIR/target-feature-wrong.rs:35:1
+ --> $DIR/target-feature-wrong.rs:36:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: attribute should be applied to a function
- --> $DIR/target-feature-wrong.rs:39:1
+ --> $DIR/target-feature-wrong.rs:40:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| -------------- not a function
error: cannot use #[inline(always)] with #[target_feature]
- --> $DIR/target-feature-wrong.rs:43:1
+ --> $DIR/target-feature-wrong.rs:44:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
--- /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.
+
+// If macro modularization (`use_extern_macros`) is not enabled,
+// then tool attributes are treated as custom attributes.
+
+#[rustfmt::bar] //~ ERROR The attribute `rustfmt::bar` is currently unknown to the compiler
+fn main() {}
--- /dev/null
+error[E0658]: The attribute `rustfmt::bar` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
+ --> $DIR/tool-attributes-disabled-1.rs:14:1
+ |
+LL | #[rustfmt::bar] //~ ERROR The attribute `rustfmt::bar` is currently unknown to the compiler
+ | ^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(custom_attribute)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /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.
+
+// If macro modularization (`use_extern_macros`) is not enabled,
+// then tool attributes are treated as custom attributes.
+
+// compile-pass
+
+#![feature(custom_attribute)]
+
+#[rustfmt::bar]
+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(tool_attributes)]
+
+type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt`
+type B = rustfmt::skip; //~ ERROR expected type, found non-macro attribute `rustfmt::skip`
+
+#[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
+struct S;
+
+#[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
+fn check() {}
+
+#[rustfmt::skip] // OK
+fn main() {
+ rustfmt; //~ ERROR expected value, found tool module `rustfmt`
+ rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope
+
+ rustfmt::skip; //~ ERROR expected value, found non-macro attribute `rustfmt::skip`
+}
--- /dev/null
+error: cannot find derive macro `rustfmt` in this scope
+ --> $DIR/tool-attributes-misplaced-1.rs:16:10
+ |
+LL | #[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
+ | ^^^^^^^
+
+error: cannot find attribute macro `rustfmt` in this scope
+ --> $DIR/tool-attributes-misplaced-1.rs:19:3
+ |
+LL | #[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
+ | ^^^^^^^
+
+error: cannot find macro `rustfmt!` in this scope
+ --> $DIR/tool-attributes-misplaced-1.rs:25:5
+ |
+LL | rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope
+ | ^^^^^^^
+
+error[E0573]: expected type, found tool module `rustfmt`
+ --> $DIR/tool-attributes-misplaced-1.rs:13:10
+ |
+LL | type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt`
+ | ^^^^^^^ not a type
+
+error[E0573]: expected type, found non-macro attribute `rustfmt::skip`
+ --> $DIR/tool-attributes-misplaced-1.rs:14:10
+ |
+LL | type B = rustfmt::skip; //~ ERROR expected type, found non-macro attribute `rustfmt::skip`
+ | ^^^^^^^^^^^^^ not a type
+
+error[E0423]: expected value, found tool module `rustfmt`
+ --> $DIR/tool-attributes-misplaced-1.rs:24:5
+ |
+LL | rustfmt; //~ ERROR expected value, found tool module `rustfmt`
+ | ^^^^^^^ not a value
+
+error[E0423]: expected value, found non-macro attribute `rustfmt::skip`
+ --> $DIR/tool-attributes-misplaced-1.rs:27:5
+ |
+LL | rustfmt::skip; //~ ERROR expected value, found non-macro attribute `rustfmt::skip`
+ | ^^^^^^^^^^^^^ not a value
+
+error: aborting due to 7 previous errors
+
+Some errors occurred: E0423, E0573.
+For more information about an error, try `rustc --explain E0423`.
--- /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(tool_attributes)]
+
+#[derive(rustfmt::skip)] //~ ERROR expected a macro, found non-macro attribute
+struct S;
+
+fn main() {
+ rustfmt::skip!(); //~ ERROR expected a macro, found non-macro attribute
+}
--- /dev/null
+error: expected a macro, found non-macro attribute
+ --> $DIR/tool-attributes-misplaced-2.rs:13:10
+ |
+LL | #[derive(rustfmt::skip)] //~ ERROR expected a macro, found non-macro attribute
+ | ^^^^^^^^^^^^^
+
+error: expected a macro, found non-macro attribute
+ --> $DIR/tool-attributes-misplaced-2.rs:17:5
+ |
+LL | rustfmt::skip!(); //~ ERROR expected a macro, found non-macro attribute
+ | ^^^^^^^^^^^^^
+
+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.
+
+#![feature(tool_attributes, proc_macro_path_invoc)]
+
+mod rustfmt {}
+
+#[rustfmt::skip] //~ ERROR failed to resolve. Could not find `skip` in `rustfmt`
+fn main() {}
--- /dev/null
+error[E0433]: failed to resolve. Could not find `skip` in `rustfmt`
+ --> $DIR/tool-attributes-shadowing.rs:15:12
+ |
+LL | #[rustfmt::skip] //~ ERROR failed to resolve. Could not find `skip` in `rustfmt`
+ | ^^^^ Could not find `skip` in `rustfmt`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
--> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:16:5
|
LL | fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
- | --------------- help: consider changing this to be a mutable reference: `&mut &mut i32`
+ | --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32`
LL | *t //~ ERROR
| ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable
--> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:20:6
|
LL | fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
- | --------------- help: consider changing this to be a mutable reference: `&mut &mut i32`
+ | --------------- help: consider changing this to be a mutable reference: `&'a mut &'a mut i32`
LL | {*t} //~ ERROR
| ^^ `t` is a `&` reference, so the data it refers to cannot be borrowed as mutable
"powerpc64-unknown-linux-gnu",
"powerpc64le-unknown-linux-gnu",
"powerpc64le-unknown-linux-musl",
+ "riscv32imac-unknown-none-elf",
"s390x-unknown-linux-gnu",
"sparc-unknown-linux-gnu",
"sparc64-unknown-linux-gnu",
"x86_64-sun-solaris",
"x86_64-unknown-cloudabi",
"x86_64-unknown-freebsd",
+ "x86_64-unknown-hermit",
"x86_64-unknown-linux-gnu",
"x86_64-unknown-linux-gnux32",
"x86_64-unknown-linux-musl",
-Subproject commit 2cd36b4ed1aef1ae39a30783e006411d1a4218ac
+Subproject commit b42488270ed29d73445d6c81d303b6a7476f6bb1
-Subproject commit afd91248eda02cf2968e4e02c77b6c10ecd3fd4f
+Subproject commit 7e5e4c1e7e80ed689a49101569dde2c19753dc8d
pub normalize_stderr: Vec<(String, String)>,
pub failure_status: i32,
pub run_rustfix: bool,
+ pub rustfix_only_machine_applicable: bool,
}
impl TestProps {
normalize_stderr: vec![],
failure_status: -1,
run_rustfix: false,
+ rustfix_only_machine_applicable: false,
}
}
if !self.run_rustfix {
self.run_rustfix = config.parse_run_rustfix(ln);
}
+
+ if !self.rustfix_only_machine_applicable {
+ self.rustfix_only_machine_applicable =
+ config.parse_rustfix_only_machine_applicable(ln);
+ }
});
if self.failure_status == -1 {
self.parse_name_directive(line, "run-rustfix")
}
+ fn parse_rustfix_only_machine_applicable(&self, line: &str) -> bool {
+ self.parse_name_directive(line, "rustfix-only-machine-applicable")
+ }
+
fn parse_edition(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "edition")
}
let suggestions = get_suggestions_from_json(
&proc_res.stderr,
&HashSet::new(),
- Filter::Everything,
+ if self.props.rustfix_only_machine_applicable {
+ Filter::MachineApplicableOnly
+ } else {
+ Filter::Everything
+ },
).unwrap();
let fixed_code = apply_suggestions(&unfixed_code, &suggestions).expect(&format!(
"failed to apply suggestions for {:?} with rustfix",
if !res.status.success() {
self.fatal_proc_rec("failed to compile fixed code", &res);
}
- if !res.stderr.is_empty() {
+ if !res.stderr.is_empty() && !self.props.rustfix_only_machine_applicable {
self.fatal_proc_rec("fixed code is still producing diagnostics", &res);
}
}
("freebsd", "freebsd"),
("fuchsia", "fuchsia"),
("haiku", "haiku"),
+ ("hermit", "hermit"),
("ios", "ios"),
("l4re", "l4re"),
("linux", "linux"),
use std::io::{Read, Write};
use std::path::Path;
use std::path::PathBuf;
+use std::cell::RefCell;
use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
-use rustdoc::html::markdown::{Markdown, PLAYGROUND};
+use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, PLAYGROUND};
use rustc_serialize::json;
enum OutputFormat {
impl OutputFormat {
fn from(format: &str) -> OutputFormat {
match &*format.to_lowercase() {
- "html" => OutputFormat::HTML(HTMLFormatter),
+ "html" => OutputFormat::HTML(HTMLFormatter(RefCell::new(IdMap::new()))),
"markdown" => OutputFormat::Markdown(MarkdownFormatter),
s => OutputFormat::Unknown(s.to_owned()),
}
fn footer(&self, output: &mut dyn Write) -> Result<(), Box<dyn Error>>;
}
-struct HTMLFormatter;
+struct HTMLFormatter(RefCell<IdMap>);
struct MarkdownFormatter;
impl Formatter for HTMLFormatter {
// Description rendered as markdown.
match info.description {
- Some(ref desc) => write!(output, "{}", Markdown(desc, &[]))?,
+ Some(ref desc) => {
+ let mut id_map = self.0.borrow_mut();
+ write!(output, "{}",
+ Markdown(desc, &[], RefCell::new(&mut id_map), ErrorCodes::Yes))?
+ },
None => write!(output, "<p>No description.</p>\n")?,
}
-Subproject commit 8214ccf861d538671b0a1436dbf4538dc4a64d09
+Subproject commit f76ea3ca16ed22dde8ef929db74a4b4df6f2f899
-Subproject commit 4c7cc91d5518bd29d3d59599cfb7a2e7e848d7b7
+Subproject commit 6d72813199d24838636389c7025ce95c427692f7
--- /dev/null
+[package]
+name = "rustc-workspace-hack"
+version = "1.0.0"
+authors = ["Alex Crichton <alex@alexcrichton.com>"]
+license = 'MIT/Apache-2.0'
+description = """
+Hack for the compiler's own build system
+"""
+
+[lib]
+path = "lib.rs"
+
+# For documentation about what this is and why in the world these dependencies
+# are appearing, see `README.md`.
+
+[build-dependencies]
+# Currently Cargo/RLS depend on `failure` which depends on `synstructure` which
+# enables this feature. Clippy, however, does not depend on anything that
+# enables this feature. Enable it unconditionally.
+syn = { version = "0.14", features = ['extra-traits'] }
+
+[target.'cfg(windows)'.dependencies.winapi]
+version = "0.3"
+features = [
+ "profileapi",
+ "memoryapi",
+ "minschannel",
+ "securitybaseapi",
+ "jobapi2",
+ "schannel",
+ "sysinfoapi",
+ "jobapi",
+ "synchapi",
+ "wincrypt",
+ "winbase",
+ "minwinbase",
+ "ntsecapi",
+ "basetsd",
+ "ntstatus",
+ "psapi",
+ "timezoneapi",
+ "lmcons",
+ "wincon",
+]
--- /dev/null
+# `rustc-workspace-hack`
+
+This crate is a bit of a hack to make workspaces in rustc work a bit better.
+The rationale for this existence is a bit subtle, but the general idea is that
+we want commands like `./x.py build src/tools/{rls,clippy,cargo}` to share as
+many dependencies as possible.
+
+Each invocation is a different invocation of Cargo, however. Each time Cargo
+runs a build it will re-resolve the dependency graph, notably selecting
+different features sometimes for each build.
+
+For example, let's say there's a very deep dependency like `num-traits` in each
+of these builds. For Cargo the `num-traits`'s `default` feature is turned off.
+In RLS, however, the `default` feature is turned. This means that building Cargo
+and then the RLS will actually build Cargo twice (as a transitive dependency
+changed). This is bad!
+
+The goal of this crate is to solve this problem and ensure that the resolved
+dependency graph for all of these tools is the same in the various subsets of
+each tool, notably enabling the same features of transitive dependencies.
+
+All tools vendored here depend on the `rustc-workspace-hack` crate on crates.io.
+When on crates.io this crate is an empty crate that is just a noop. We override
+it, however, in this workspace to this crate here, which means we can control
+crates in the dependency graph for each of these tools.
--- /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.
+
+// intentionally left blank
-Subproject commit 69ad879d52606ac03440744efa5b4d8ca8cc7566
+Subproject commit da17b689595ddc863b02eb1ba6831c87cefc1e21