Use scope tree depths to speed up `nearest_common_ancestor`.
This patch adds depth markings to all entries in the `ScopeTree`'s
`parent_map`. This change increases memory usage somewhat, but permits a
much faster algorithm to be used:
- If one scope has a greater depth than the other, the deeper scope is
moved upward until they are at equal depths.
- Then we move the two scopes upward in lockstep until they match.
This avoids the need to keep track of which scopes have already been
seen, which was the major part of the cost of the old algorithm. It also
reduces the number of child-to-parent moves (which are hash table
lookups) when the scopes start at different levels, because it never
goes past the nearest common ancestor the way the old algorithm did.
Finally, the case where one of the scopes is the root is now handled in
advance, because that is moderately common and lets us skip everything.
This change speeds up runs of several rust-perf benchmarks, the best by
6%.
A selection of the bigger improvements:
```
clap-rs-check
avg: -2.6% min: -6.6% max: 0.0%
syn-check
avg: -2.2% min: -5.0% max: 0.0%
style-servo-check
avg: -2.9%? min: -4.8%? max: 0.0%?
cargo-check
avg: -1.3% min: -2.8% max: 0.0%
sentry-cli-check
avg: -1.0% min: -2.1% max: 0.0%
webrender-check
avg: -0.9% min: -2.0% max: 0.0%
style-servo
avg: -0.9%? min: -1.8%? max: -0.0%?
ripgrep-check
avg: -0.7% min: -1.8% max: 0.1%
clap-rs
avg: -0.9% min: -1.6% max: -0.2%
regex-check
avg: -0.2% min: -1.3% max: 0.1%
syn
avg: -0.6% min: -1.3% max: 0.1%
hyper-check
avg: -0.5% min: -1.1% max: 0.0%
```
The idea came from multiple commenters on my blog and on Reddit. Thank you!
r? @nikomatsakis
rm -rf obj/build/dist/doc &&
cp -r obj/build/dist/* deploy/$TRAVIS_COMMIT;
fi
- - travis_retry gem update --system
- ls -la deploy/$TRAVIS_COMMIT
deploy:
[[package]]
name = "polonius-engine"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"datafrog 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
"clippy_lints 0.0.205 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"json 0.11.13 (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.41.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-analysis 0.13.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.3.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-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfmt-nightly 0.8.2",
+ "rustfmt-nightly 0.8.2 (git+https://github.com/rust-lang-nursery/rustfmt?rev=f3906267)",
"serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rls-rustc"
-version = "0.3.0"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
"jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "polonius-engine 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "polonius-engine 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"proc_macro 0.0.0",
+ "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)",
"rustc_apfloat 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"rustc_target 0.0.0",
+ "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
[[package]]
name = "rustc-ap-arena"
-version = "147.0.0"
+version = "149.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc-ap-rustc_data_structures 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-ap-arena"
+version = "156.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rustc-ap-rustc_data_structures 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-rustc_cratesio_shim"
-version = "147.0.0"
+version = "149.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-rustc_cratesio_shim"
+version = "156.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-ap-rustc_data_structures"
+version = "149.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.5.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 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 149.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)",
+ "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-rustc_data_structures"
-version = "147.0.0"
+version = "156.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.5.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 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 156.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.0 (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.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-rustc_errors"
-version = "147.0.0"
+version = "149.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 149.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.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-ap-rustc_errors"
+version = "156.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 156.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.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-rustc_target"
-version = "147.0.0"
+version = "149.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_cratesio_shim 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-ap-rustc_target"
+version = "156.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-serialize"
-version = "147.0.0"
+version = "149.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rustc-ap-serialize"
+version = "156.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-ap-syntax"
-version = "147.0.0"
+version = "149.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_errors 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_target 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-syntax"
+version = "156.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-ap-syntax_pos"
+version = "149.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc-ap-arena 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-syntax_pos"
-version = "147.0.0"
+version = "156.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rustc-ap-arena 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-arena 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-rayon"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-rayon-core"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.2.0 (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-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-rayon-core 0.1.0 (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)",
"rustc_cratesio_shim 0.0.0",
"serialize 0.0.0",
"stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
- "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_allocator 0.0.0",
"rustc_borrowck 0.0.0",
"rustc_codegen_utils 0.0.0",
"graphviz 0.0.0",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "polonius-engine 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "polonius-engine 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_apfloat 0.0.0",
"rustc_data_structures 0.0.0",
version = "0.0.0"
dependencies = [
"arena 0.0.0",
- "fmt_macros 0.0.0",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustfmt-nightly"
+version = "0.8.2"
+source = "git+https://github.com/rust-lang-nursery/rustfmt?rev=f3906267#f390626778c1bbb13911556d585850eb2fa67923"
+dependencies = [
+ "cargo_metadata 0.5.4 (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.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.1 (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)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustfmt-nightly"
version = "0.8.2"
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_target 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
-"checksum polonius-engine 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9385a6d8f8ff6fd7e48a803c6a77fb89cc929dc7e2af6bf972494bbc8ff8b9e4"
+"checksum polonius-engine 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b6b0a7f5f4278b991ffd14abce1d01b013121ad297460237ef0a2f08d43201"
"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
"checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6"
"checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118"
"checksum rls-analysis 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da9794cd1f80f2cb888c00641a32f9855d0226c954ee31cef145784914c7142e"
"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.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ed5342b2bbbe8663c04600af506c8902b6b4d3e627b006eb1bd65aa14805f4d"
+"checksum rls-rustc 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c8c09117ae2887baaa4b17fe1cb572f9b22e4d2c6a5cda04093d8b366b0be99"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb"
-"checksum rustc-ap-arena 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1304956fbbdd070e4478672d040f0453374604a12a0938aaba4b38a2bd124667"
-"checksum rustc-ap-rustc_cratesio_shim 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d1dcd0fafa3c7875b76e33feaf69b332870180475ba3eb8dd003bcc2a2dc069"
-"checksum rustc-ap-rustc_data_structures 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76c1a3fe4a0104b922ffc8080bd7c703dc20f2874b7c982638f6adb6c378b77a"
-"checksum rustc-ap-rustc_errors 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2812e295d2930bf3b3c22dbe8ef0bb8ae98a497ae6ad379d0709434387a9004b"
-"checksum rustc-ap-rustc_target 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bd371121f16da666f6d6d5e6ff57cd972cc8206cc80377ba411b99607d49cbd"
-"checksum rustc-ap-serialize 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bde493c1c16d724e42536117c385b69f2eae9b2ec38bab841c45373bce4a9d8f"
-"checksum rustc-ap-syntax 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "402c1f402e6d47defcd884d3f715aaa8c6f2cbdd5f13cb06fea70486d512426b"
-"checksum rustc-ap-syntax_pos 147.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb707a229093791dc3fc35aca61d9bf0e3708f23da4536683527857bc624b061"
+"checksum rustc-ap-arena 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e794b25832224eea9252ebfa9f94ab7070d0a60c977793112c611501cb56b48d"
+"checksum rustc-ap-arena 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83e91a01cd6c5a9e4f68c2b5c81b62b172aa9e00fc2fec862c0899e3fac1fd32"
+"checksum rustc-ap-rustc_cratesio_shim 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a78241b2ecb82ebb9221b4b7d37c024ff1f2e43f1b099f38a997f030fc7894b0"
+"checksum rustc-ap-rustc_cratesio_shim 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e8ea8fadc5d66c1527771816e83f7e7599543bd2e1583e279855370ab2f18e5"
+"checksum rustc-ap-rustc_data_structures 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5529c3927f32b0b56d1f6449a34f2218dc2160c6a6dde0cf47954d83a9a45764"
+"checksum rustc-ap-rustc_data_structures 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "742ba74bc7d0f3ded56148329650f137fa5b90f7f0ecc4b4952150f32c66b147"
+"checksum rustc-ap-rustc_errors 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1fef44a7d63f5d204c981adb26a14e85fe7ee5962050a4f664df6f425f9b48"
+"checksum rustc-ap-rustc_errors 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3714046c6f8c1c259822aefcca21b1862710a6cec24fd34c0796117f074c6769"
+"checksum rustc-ap-rustc_target 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a3939a9f7bf063536dd646894ca43b1378ec6a56ac5b2698cc6ba0b42bfadbdc"
+"checksum rustc-ap-rustc_target 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b982c4517c18080895b06149ce8aa8279fd013f629030bb7a179bfcff6d74ef2"
+"checksum rustc-ap-serialize 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "692169d0bac8a4547f9778039460799e162664477a1eaec15d31507705f8c736"
+"checksum rustc-ap-serialize 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "27c7700595bff1a64ddb6f593c69db3f6d66b76b059b26137236c7e21e36db70"
+"checksum rustc-ap-syntax 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22e93ee3817b007d56b5c5b151e6cd7c7063455a1facaf9e0ca01f9d9365b716"
+"checksum rustc-ap-syntax 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6482d98c8be57d3cfe55dab744dd1a87f8462dc2ea0a8a4960f7bb1565be049"
+"checksum rustc-ap-syntax_pos 149.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe5d24a137d6e202cd6eb96cb74f8cb4a2b257c42b74dd624e136b4e19f0a47d"
+"checksum rustc-ap-syntax_pos 156.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20af5e200b61a3e5ba4f58ed3cbd7593569faf8f0956d5233f4f27fee51b4c81"
"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
-"checksum rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1aa5cd8c3a706edb19b6ec6aa7b056bdc635b6e99c5cf7014f9af9d92f15e99"
-"checksum rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d69983f8613a9c3ba1a3bbf5e8bdf2fd5c42317b1d8dd8623ca8030173bf8a6b"
+"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.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9da3cf9b79dc889a2c9879643f26d7a53e37e9361c7566b7d2787d5ace0d8396"
+"checksum rustfmt-nightly 0.8.2 (git+https://github.com/rust-lang-nursery/rustfmt?rev=f3906267)" = "<none>"
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade"
"checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4"
# goes ahead and sets it for all builders.
args="$args --privileged"
+if [ "$CI" != "" ]; then
+ args="$args --dns 8.8.8.8 --dns 8.8.4.4 --dns 1.1.1.1 --dns 1.0.0.1"
+fi
+
exec docker \
run \
--volume "$root_dir:/checkout:ro" \
an example block that looks like this:
```text
-/// Some documentation.
-# fn foo() {}
+/// /// Some documentation.
+/// # fn foo() {} // this function will be hidden
+/// println!("Hello, World!");
```
It will render like this:
```rust
/// Some documentation.
# fn foo() {}
+println!("Hello, World!");
```
Yes, that's right: you can add lines that start with `# `, and they will
compiles, while only showing the parts that are relevant to that part of your
explanation.
-Another case where the use of `#` is handy is when you want to ignore
-error handling. Lets say you want the following,
+
+## Using `?` in doc tests
+
+When writing an example, it is rarely useful to include a complete error
+handling, as it would add significant amounts of boilerplate code. Instead, you
+may want the following:
```ignore
+/// ```
/// use std::io;
/// let mut input = String::new();
/// io::stdin().read_line(&mut input)?;
+/// ```
```
-The problem is that `?` returns a `Result<T, E>` and test functions
-don't return anything so this will give a mismatched types error.
+The problem is that `?` returns a `Result<T, E>` and test functions don't
+return anything, so this will give a mismatched types error.
+
+You can get around this limitation by manually adding a `main` that returns
+`Result<T, E>`, because `Result<T, E>` implements the `Termination` trait:
```ignore
/// A doc test using ?
///
/// ```
/// use std::io;
-/// # fn foo() -> io::Result<()> {
+///
+/// fn main() -> io::Result<()> {
+/// let mut input = String::new();
+/// io::stdin().read_line(&mut input)?;
+/// Ok(())
+/// }
+/// ```
+```
+
+Together with the `# ` from the section above, you arrive at a solution that
+appears to the reader as the initial idea but works with doc tests:
+
+```ignore
+/// ```
+/// use std::io;
+/// # fn main() -> io::Result<()> {
/// let mut input = String::new();
/// io::stdin().read_line(&mut input)?;
/// # Ok(())
/// # }
/// ```
-# fn foo() {}
```
-You can get around this by wrapping the code in a function. This catches
-and swallows the `Result<T, E>` when running tests on the docs. This
-pattern appears regularly in the standard library.
-
-### Documenting macros
+## Documenting macros
Here’s an example of documenting a macro:
def check_tree_text(tree, path, pat, regexp):
path = normalize_xpath(path)
ret = False
- for e in tree.findall(path):
- try:
- value = flatten(e)
- except KeyError:
- continue
- else:
- ret = check_string(value, pat, regexp)
- if ret:
- break
+ try:
+ for e in tree.findall(path):
+ try:
+ value = flatten(e)
+ except KeyError:
+ continue
+ else:
+ ret = check_string(value, pat, regexp)
+ if ret:
+ break
+ except Exception as e:
+ print('Failed to get path "{}"'.format(path))
+ raise e
return ret
use core::borrow;
use core::cmp::Ordering;
use core::fmt;
+use core::future::Future;
use core::hash::{Hash, Hasher};
use core::iter::FusedIterator;
use core::marker::{Unpin, Unsize};
use core::mem::{self, PinMut};
use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
use core::ptr::{self, NonNull, Unique};
+use core::task::{Context, Poll, UnsafePoll, TaskObj};
use core::convert::From;
use raw_vec::RawVec;
/// A pinned, heap allocated reference.
#[unstable(feature = "pin", issue = "49150")]
#[fundamental]
+#[repr(transparent)]
pub struct PinBox<T: ?Sized> {
inner: Box<T>,
}
#[unstable(feature = "pin", issue = "49150")]
impl<T: ?Sized> PinBox<T> {
/// Get a pinned reference to the data in this PinBox.
+ #[inline]
pub fn as_pin_mut<'a>(&'a mut self) -> PinMut<'a, T> {
unsafe { PinMut::new_unchecked(&mut *self.inner) }
}
+ /// Constructs a `PinBox` from a raw pointer.
+ ///
+ /// After calling this function, the raw pointer is owned by the
+ /// resulting `PinBox`. Specifically, the `PinBox` destructor will call
+ /// the destructor of `T` and free the allocated memory. Since the
+ /// way `PinBox` allocates and releases memory is unspecified, the
+ /// only valid pointer to pass to this function is the one taken
+ /// from another `PinBox` via the [`PinBox::into_raw`] function.
+ ///
+ /// This function is unsafe because improper use may lead to
+ /// memory problems. For example, a double-free may occur if the
+ /// function is called twice on the same raw pointer.
+ ///
+ /// [`PinBox::into_raw`]: struct.PinBox.html#method.into_raw
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(pin)]
+ /// use std::boxed::PinBox;
+ /// let x = PinBox::new(5);
+ /// let ptr = PinBox::into_raw(x);
+ /// let x = unsafe { PinBox::from_raw(ptr) };
+ /// ```
+ #[inline]
+ pub unsafe fn from_raw(raw: *mut T) -> Self {
+ PinBox { inner: Box::from_raw(raw) }
+ }
+
+ /// Consumes the `PinBox`, returning the wrapped raw pointer.
+ ///
+ /// After calling this function, the caller is responsible for the
+ /// memory previously managed by the `PinBox`. In particular, the
+ /// caller should properly destroy `T` and release the memory. The
+ /// proper way to do so is to convert the raw pointer back into a
+ /// `PinBox` with the [`PinBox::from_raw`] function.
+ ///
+ /// Note: this is an associated function, which means that you have
+ /// to call it as `PinBox::into_raw(b)` instead of `b.into_raw()`. This
+ /// is so that there is no conflict with a method on the inner type.
+ ///
+ /// [`PinBox::from_raw`]: struct.PinBox.html#method.from_raw
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(pin)]
+ /// use std::boxed::PinBox;
+ /// let x = PinBox::new(5);
+ /// let ptr = PinBox::into_raw(x);
+ /// ```
+ #[inline]
+ pub fn into_raw(b: PinBox<T>) -> *mut T {
+ Box::into_raw(b.inner)
+ }
+
/// Get a mutable reference to the data inside this PinBox.
///
/// This function is unsafe. Users must guarantee that the data is never
/// moved out of this reference.
+ #[inline]
pub unsafe fn get_mut<'a>(this: &'a mut PinBox<T>) -> &'a mut T {
&mut *this.inner
}
///
/// This function is unsafe. Users must guarantee that the data is never
/// moved out of the box.
+ #[inline]
pub unsafe fn unpin(this: PinBox<T>) -> Box<T> {
this.inner
}
#[unstable(feature = "pin", issue = "49150")]
impl<T: ?Sized> Unpin for PinBox<T> {}
+
+#[unstable(feature = "futures_api", issue = "50547")]
+unsafe impl<F: Future<Output = ()> + Send + 'static> UnsafePoll for PinBox<F> {
+ fn into_raw(self) -> *mut () {
+ PinBox::into_raw(self) as *mut ()
+ }
+
+ unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()> {
+ let ptr = task as *mut F;
+ let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
+ pin.poll(cx)
+ }
+
+ unsafe fn drop(task: *mut ()) {
+ drop(PinBox::from_raw(task as *mut F))
+ }
+}
+
+#[unstable(feature = "futures_api", issue = "50547")]
+impl<F: Future<Output = ()> + Send + 'static> From<PinBox<F>> for TaskObj {
+ fn from(boxed: PinBox<F>) -> Self {
+ TaskObj::from_poll_task(boxed)
+ }
+}
+
+#[unstable(feature = "futures_api", issue = "50547")]
+impl<F: Future<Output = ()> + Send + 'static> From<Box<F>> for TaskObj {
+ fn from(boxed: Box<F>) -> Self {
+ TaskObj::from_poll_task(PinBox::from(boxed))
+ }
+}
pub use core::fmt::{write, ArgumentV1, Arguments};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};
+#[stable(feature = "fmt_flags_align", since = "1.28.0")]
+pub use core::fmt::{Alignment};
use string;
#![feature(fmt_internals)]
#![feature(from_ref)]
#![feature(fundamental)]
+#![feature(futures_api)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(needs_allocator)]
#![feature(pin)]
#![feature(ptr_internals)]
#![feature(ptr_offset_from)]
+#![feature(repr_transparent)]
#![feature(rustc_attrs)]
#![feature(specialization)]
#![feature(staged_api)]
pub use alloc::*;
}
+#[unstable(feature = "futures_api",
+ reason = "futures in libcore are unstable",
+ issue = "50547")]
+pub mod task;
// Primitive types using the heaps above
--- /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.
+
+//! Types and Traits for working with asynchronous tasks.
+
+pub use core::task::*;
+
+#[cfg(target_has_atomic = "ptr")]
+pub use self::if_arc::*;
+
+#[cfg(target_has_atomic = "ptr")]
+mod if_arc {
+ use super::*;
+ use arc::Arc;
+ use core::marker::PhantomData;
+ use core::mem;
+ use core::ptr::{self, NonNull};
+
+ /// A way of waking up a specific task.
+ ///
+ /// Any task executor must provide a way of signaling that a task it owns
+ /// is ready to be `poll`ed again. Executors do so by implementing this trait.
+ pub trait Wake: Send + Sync {
+ /// Indicates that the associated task is ready to make progress and should
+ /// be `poll`ed.
+ ///
+ /// Executors generally maintain a queue of "ready" tasks; `wake` should place
+ /// the associated task onto this queue.
+ fn wake(arc_self: &Arc<Self>);
+
+ /// Indicates that the associated task is ready to make progress and should
+ /// be `poll`ed. This function is like `wake`, but can only be called from the
+ /// thread on which this `Wake` was created.
+ ///
+ /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place
+ /// the associated task onto this queue.
+ #[inline]
+ unsafe fn wake_local(arc_self: &Arc<Self>) {
+ Self::wake(arc_self);
+ }
+ }
+
+ #[cfg(target_has_atomic = "ptr")]
+ struct ArcWrapped<T>(PhantomData<T>);
+
+ unsafe impl<T: Wake + 'static> UnsafeWake for ArcWrapped<T> {
+ #[inline]
+ unsafe fn clone_raw(&self) -> Waker {
+ let me: *const ArcWrapped<T> = self;
+ let arc = (*(&me as *const *const ArcWrapped<T> as *const Arc<T>)).clone();
+ Waker::from(arc)
+ }
+
+ #[inline]
+ unsafe fn drop_raw(&self) {
+ let mut me: *const ArcWrapped<T> = self;
+ let me = &mut me as *mut *const ArcWrapped<T> as *mut Arc<T>;
+ ptr::drop_in_place(me);
+ }
+
+ #[inline]
+ unsafe fn wake(&self) {
+ let me: *const ArcWrapped<T> = self;
+ T::wake(&*(&me as *const *const ArcWrapped<T> as *const Arc<T>))
+ }
+
+ #[inline]
+ unsafe fn wake_local(&self) {
+ let me: *const ArcWrapped<T> = self;
+ T::wake_local(&*(&me as *const *const ArcWrapped<T> as *const Arc<T>))
+ }
+ }
+
+ impl<T> From<Arc<T>> for Waker
+ where T: Wake + 'static,
+ {
+ fn from(rc: Arc<T>) -> Self {
+ unsafe {
+ let ptr = mem::transmute::<Arc<T>, NonNull<ArcWrapped<T>>>(rc);
+ Waker::new(ptr)
+ }
+ }
+ }
+
+ /// Creates a `LocalWaker` from a local `wake`.
+ ///
+ /// This function requires that `wake` is "local" (created on the current thread).
+ /// The resulting `LocalWaker` will call `wake.wake_local()` when awoken, and
+ /// will call `wake.wake()` if awoken after being converted to a `Waker`.
+ #[inline]
+ pub unsafe fn local_waker<W: Wake + 'static>(wake: Arc<W>) -> LocalWaker {
+ let ptr = mem::transmute::<Arc<W>, NonNull<ArcWrapped<W>>>(wake);
+ LocalWaker::new(ptr)
+ }
+
+ struct NonLocalAsLocal<T>(ArcWrapped<T>);
+
+ unsafe impl<T: Wake + 'static> UnsafeWake for NonLocalAsLocal<T> {
+ #[inline]
+ unsafe fn clone_raw(&self) -> Waker {
+ self.0.clone_raw()
+ }
+
+ #[inline]
+ unsafe fn drop_raw(&self) {
+ self.0.drop_raw()
+ }
+
+ #[inline]
+ unsafe fn wake(&self) {
+ self.0.wake()
+ }
+
+ #[inline]
+ unsafe fn wake_local(&self) {
+ // Since we're nonlocal, we can't call wake_local
+ self.0.wake()
+ }
+ }
+
+ /// Creates a `LocalWaker` from a non-local `wake`.
+ ///
+ /// This function is similar to `local_waker`, but does not require that `wake`
+ /// is local to the current thread. The resulting `LocalWaker` will call
+ /// `wake.wake()` when awoken.
+ #[inline]
+ pub fn local_waker_from_nonlocal<W: Wake + 'static>(wake: Arc<W>) -> LocalWaker {
+ unsafe {
+ let ptr = mem::transmute::<Arc<W>, NonNull<NonLocalAsLocal<W>>>(wake);
+ LocalWaker::new(ptr)
+ }
+ }
+}
/// ```
/// extern crate core;
///
- /// use std::fmt;
- /// use core::fmt::Alignment;
+ /// use std::fmt::{self, Alignment};
///
/// struct 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.
+
+#![unstable(feature = "futures_api",
+ reason = "futures in libcore are unstable",
+ issue = "50547")]
+
+//! Asynchronous values.
+
+use mem::PinMut;
+use task::{self, Poll};
+
+/// A future represents an asychronous computation.
+///
+/// A future is a value that may not have finished computing yet. This kind of
+/// "asynchronous value" makes it possible for a thread to continue doing useful
+/// work while it waits for the value to become available.
+///
+/// # The `poll` method
+///
+/// The core method of future, `poll`, *attempts* to resolve the future into a
+/// final value. This method does not block if the value is not ready. Instead,
+/// the current task is scheduled to be woken up when it's possible to make
+/// further progress by `poll`ing again. The wake up is performed using
+/// `cx.waker()`, a handle for waking up the current task.
+///
+/// When using a future, you generally won't call `poll` directly, but instead
+/// `await!` the value.
+pub trait Future {
+ /// The result of the `Future`.
+ type Output;
+
+ /// Attempt to resolve the future to a final value, registering
+ /// the current task for wakeup if the value is not yet available.
+ ///
+ /// # Return value
+ ///
+ /// This function returns:
+ ///
+ /// - `Poll::Pending` if the future is not ready yet
+ /// - `Poll::Ready(val)` with the result `val` of this future if it finished
+ /// successfully.
+ ///
+ /// Once a future has finished, clients should not `poll` it again.
+ ///
+ /// When a future is not ready yet, `poll` returns
+ /// [`Poll::Pending`](::task::Poll). The future will *also* register the
+ /// interest of the current task in the value being produced. For example,
+ /// if the future represents the availability of data on a socket, then the
+ /// task is recorded so that when data arrives, it is woken up (via
+ /// [`cx.waker()`](::task::Context::waker)). Once a task has been woken up,
+ /// it should attempt to `poll` the future again, which may or may not
+ /// produce a final value.
+ ///
+ /// Note that if `Pending` is returned it only means that the *current* task
+ /// (represented by the argument `cx`) will receive a notification. Tasks
+ /// from previous calls to `poll` will *not* receive notifications.
+ ///
+ /// # Runtime characteristics
+ ///
+ /// Futures alone are *inert*; they must be *actively* `poll`ed to make
+ /// progress, meaning that each time the current task is woken up, it should
+ /// actively re-`poll` pending futures that it still has an interest in.
+ ///
+ /// The `poll` function is not called repeatedly in a tight loop for
+ /// futures, but only whenever the future itself is ready, as signaled via
+ /// the `Waker` inside `task::Context`. If you're familiar with the
+ /// `poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures
+ /// typically do *not* suffer the same problems of "all wakeups must poll
+ /// all events"; they are more like `epoll(4)`.
+ ///
+ /// An implementation of `poll` should strive to return quickly, and must
+ /// *never* block. Returning quickly prevents unnecessarily clogging up
+ /// threads or event loops. If it is known ahead of time that a call to
+ /// `poll` may end up taking awhile, the work should be offloaded to a
+ /// thread pool (or something similar) to ensure that `poll` can return
+ /// quickly.
+ ///
+ /// # Panics
+ ///
+ /// Once a future has completed (returned `Ready` from `poll`),
+ /// then any future calls to `poll` may panic, block forever, or otherwise
+ /// cause bad behavior. The `Future` trait itself provides no guarantees
+ /// about the behavior of `poll` after a future has completed.
+ fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output>;
+}
#![feature(optin_builtin_traits)]
#![feature(prelude_import)]
#![feature(repr_simd, platform_intrinsics)]
+#![feature(repr_transparent)]
#![feature(rustc_attrs)]
#![feature(rustc_const_unstable)]
#![feature(simd_ffi)]
pub mod unicode;
+/* Async */
+pub mod future;
+pub mod task;
+
/* Heap memory allocator trait */
#[allow(missing_docs)]
pub mod alloc;
--- /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.
+
+#![unstable(feature = "futures_api",
+ reason = "futures in libcore are unstable",
+ issue = "50547")]
+
+//! Types and Traits for working with asynchronous tasks.
+
+use fmt;
+use ptr::NonNull;
+
+/// Indicates whether a value is available or if the current task has been
+/// scheduled to receive a wakeup instead.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub enum Poll<T> {
+ /// Represents that a value is immediately ready.
+ Ready(T),
+
+ /// Represents that a value is not ready yet.
+ ///
+ /// When a function returns `Pending`, the function *must* also
+ /// ensure that the current task is scheduled to be awoken when
+ /// progress can be made.
+ Pending,
+}
+
+/// A `Waker` is a handle for waking up a task by notifying its executor that it
+/// is ready to be run.
+///
+/// This handle contains a trait object pointing to an instance of the `UnsafeWake`
+/// trait, allowing notifications to get routed through it.
+#[repr(transparent)]
+pub struct Waker {
+ inner: NonNull<UnsafeWake>,
+}
+
+unsafe impl Send for Waker {}
+unsafe impl Sync for Waker {}
+
+impl Waker {
+ /// Constructs a new `Waker` directly.
+ ///
+ /// Note that most code will not need to call this. Implementers of the
+ /// `UnsafeWake` trait will typically provide a wrapper that calls this
+ /// but you otherwise shouldn't call it directly.
+ ///
+ /// If you're working with the standard library then it's recommended to
+ /// use the `Waker::from` function instead which works with the safe
+ /// `Arc` type and the safe `Wake` trait.
+ #[inline]
+ pub unsafe fn new(inner: NonNull<UnsafeWake>) -> Self {
+ Waker { inner: inner }
+ }
+
+ /// Wake up the task associated with this `Waker`.
+ #[inline]
+ pub fn wake(&self) {
+ unsafe { self.inner.as_ref().wake() }
+ }
+
+ /// Returns whether or not this `Waker` and `other` awaken the same task.
+ ///
+ /// This function works on a best-effort basis, and may return false even
+ /// when the `Waker`s would awaken the same task. However, if this function
+ /// returns true, it is guaranteed that the `Waker`s will awaken the same
+ /// task.
+ ///
+ /// This function is primarily used for optimization purposes.
+ #[inline]
+ pub fn will_wake(&self, other: &Waker) -> bool {
+ self.inner == other.inner
+ }
+}
+
+impl Clone for Waker {
+ #[inline]
+ fn clone(&self) -> Self {
+ unsafe {
+ self.inner.as_ref().clone_raw()
+ }
+ }
+}
+
+impl fmt::Debug for Waker {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Waker")
+ .finish()
+ }
+}
+
+impl Drop for Waker {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ self.inner.as_ref().drop_raw()
+ }
+ }
+}
+
+/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it
+/// is ready to be run.
+///
+/// This is similar to the `Waker` type, but cannot be sent across threads.
+/// Task executors can use this type to implement more optimized singlethreaded wakeup
+/// behavior.
+#[repr(transparent)]
+pub struct LocalWaker {
+ inner: NonNull<UnsafeWake>,
+}
+
+impl !Send for LocalWaker {}
+impl !Sync for LocalWaker {}
+
+impl LocalWaker {
+ /// Constructs a new `LocalWaker` directly.
+ ///
+ /// Note that most code will not need to call this. Implementers of the
+ /// `UnsafeWake` trait will typically provide a wrapper that calls this
+ /// but you otherwise shouldn't call it directly.
+ ///
+ /// If you're working with the standard library then it's recommended to
+ /// use the `LocalWaker::from` function instead which works with the safe
+ /// `Rc` type and the safe `LocalWake` trait.
+ ///
+ /// For this function to be used safely, it must be sound to call `inner.wake_local()`
+ /// on the current thread.
+ #[inline]
+ pub unsafe fn new(inner: NonNull<UnsafeWake>) -> Self {
+ LocalWaker { inner: inner }
+ }
+
+ /// Wake up the task associated with this `LocalWaker`.
+ #[inline]
+ pub fn wake(&self) {
+ unsafe { self.inner.as_ref().wake_local() }
+ }
+
+ /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task.
+ ///
+ /// This function works on a best-effort basis, and may return false even
+ /// when the `LocalWaker`s would awaken the same task. However, if this function
+ /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
+ /// task.
+ ///
+ /// This function is primarily used for optimization purposes.
+ #[inline]
+ pub fn will_wake(&self, other: &LocalWaker) -> bool {
+ self.inner == other.inner
+ }
+
+ /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task.
+ ///
+ /// This function works on a best-effort basis, and may return false even
+ /// when the `Waker`s would awaken the same task. However, if this function
+ /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
+ /// task.
+ ///
+ /// This function is primarily used for optimization purposes.
+ #[inline]
+ pub fn will_wake_nonlocal(&self, other: &Waker) -> bool {
+ self.inner == other.inner
+ }
+}
+
+impl From<LocalWaker> for Waker {
+ #[inline]
+ fn from(local_waker: LocalWaker) -> Self {
+ Waker { inner: local_waker.inner }
+ }
+}
+
+impl Clone for LocalWaker {
+ #[inline]
+ fn clone(&self) -> Self {
+ unsafe {
+ LocalWaker { inner: self.inner.as_ref().clone_raw().inner }
+ }
+ }
+}
+
+impl fmt::Debug for LocalWaker {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Waker")
+ .finish()
+ }
+}
+
+impl Drop for LocalWaker {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ self.inner.as_ref().drop_raw()
+ }
+ }
+}
+
+/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`.
+///
+/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is
+/// most often essentially just `Arc<dyn Wake>`. However, in some contexts
+/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some
+/// custom memory management strategy. This trait is designed to allow for such
+/// customization.
+///
+/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for
+/// `Arc<T>` where `T: Wake` and `Rc<T>` where `T: LocalWake`.
+///
+/// Although the methods on `UnsafeWake` take pointers rather than references,
+pub unsafe trait UnsafeWake: Send + Sync {
+ /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`.
+ ///
+ /// This function will create a new uniquely owned handle that under the
+ /// hood references the same notification instance. In other words calls
+ /// to `wake` on the returned handle should be equivalent to calls to
+ /// `wake` on this handle.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe to call because it's asserting the `UnsafeWake`
+ /// value is in a consistent state, i.e. hasn't been dropped.
+ unsafe fn clone_raw(&self) -> Waker;
+
+ /// Drops this instance of `UnsafeWake`, deallocating resources
+ /// associated with it.
+ ///
+ /// FIXME(cramertj)
+ /// This method is intended to have a signature such as:
+ ///
+ /// ```ignore (not-a-doctest)
+ /// fn drop_raw(self: *mut Self);
+ /// ```
+ ///
+ /// Unfortunately in Rust today that signature is not object safe.
+ /// Nevertheless it's recommended to implement this function *as if* that
+ /// were its signature. As such it is not safe to call on an invalid
+ /// pointer, nor is the validity of the pointer guaranteed after this
+ /// function returns.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe to call because it's asserting the `UnsafeWake`
+ /// value is in a consistent state, i.e. hasn't been dropped.
+ unsafe fn drop_raw(&self);
+
+ /// Indicates that the associated task is ready to make progress and should
+ /// be `poll`ed.
+ ///
+ /// Executors generally maintain a queue of "ready" tasks; `wake` should place
+ /// the associated task onto this queue.
+ ///
+ /// # Panics
+ ///
+ /// Implementations should avoid panicking, but clients should also be prepared
+ /// for panics.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe to call because it's asserting the `UnsafeWake`
+ /// value is in a consistent state, i.e. hasn't been dropped.
+ unsafe fn wake(&self);
+
+ /// Indicates that the associated task is ready to make progress and should
+ /// be `poll`ed. This function is the same as `wake`, but can only be called
+ /// from the thread that this `UnsafeWake` is "local" to. This allows for
+ /// implementors to provide specialized wakeup behavior specific to the current
+ /// thread. This function is called by `LocalWaker::wake`.
+ ///
+ /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place
+ /// the associated task onto this queue.
+ ///
+ /// # Panics
+ ///
+ /// Implementations should avoid panicking, but clients should also be prepared
+ /// for panics.
+ ///
+ /// # Unsafety
+ ///
+ /// This function is unsafe to call because it's asserting the `UnsafeWake`
+ /// value is in a consistent state, i.e. hasn't been dropped, and that the
+ /// `UnsafeWake` hasn't moved from the thread on which it was created.
+ unsafe fn wake_local(&self) {
+ self.wake()
+ }
+}
+
+/// Information about the currently-running task.
+///
+/// Contexts are always tied to the stack, since they are set up specifically
+/// when performing a single `poll` step on a task.
+pub struct Context<'a> {
+ local_waker: &'a LocalWaker,
+ executor: &'a mut Executor,
+}
+
+impl<'a> fmt::Debug for Context<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Context")
+ .finish()
+ }
+}
+
+impl<'a> Context<'a> {
+ /// Create a new task `Context` with the provided `local_waker`, `waker`, and `executor`.
+ #[inline]
+ pub fn new(local_waker: &'a LocalWaker, executor: &'a mut Executor) -> Context<'a> {
+ Context {
+ local_waker,
+ executor,
+ }
+ }
+
+ /// Get the `LocalWaker` associated with the current task.
+ #[inline]
+ pub fn local_waker(&self) -> &'a LocalWaker {
+ self.local_waker
+ }
+
+ /// Get the `Waker` associated with the current task.
+ #[inline]
+ pub fn waker(&self) -> &'a Waker {
+ unsafe { &*(self.local_waker as *const LocalWaker as *const Waker) }
+ }
+
+ /// Get the default executor associated with this task.
+ ///
+ /// This method is useful primarily if you want to explicitly handle
+ /// spawn failures.
+ #[inline]
+ pub fn executor(&mut self) -> &mut Executor {
+ self.executor
+ }
+
+ /// Produce a context like the current one, but using the given waker instead.
+ ///
+ /// This advanced method is primarily used when building "internal
+ /// schedulers" within a task, where you want to provide some customized
+ /// wakeup logic.
+ #[inline]
+ pub fn with_waker<'b>(&'b mut self, local_waker: &'b LocalWaker) -> Context<'b> {
+ Context {
+ local_waker,
+ executor: self.executor,
+ }
+ }
+
+ /// Produce a context like the current one, but using the given executor
+ /// instead.
+ ///
+ /// This advanced method is primarily used when building "internal
+ /// schedulers" within a task.
+ #[inline]
+ pub fn with_executor<'b, E>(&'b mut self, executor: &'b mut E) -> Context<'b>
+ where E: Executor
+ {
+ Context {
+ local_waker: self.local_waker,
+ executor: executor,
+ }
+ }
+}
+
+/// A task executor.
+///
+/// A *task* is a `()`-producing async value that runs at the top level, and will
+/// be `poll`ed until completion. It's also the unit at which wake-up
+/// notifications occur. Executors, such as thread pools, allow tasks to be
+/// spawned and are responsible for putting tasks onto ready queues when
+/// they are woken up, and polling them when they are ready.
+pub trait Executor {
+ /// Spawn the given task, polling it until completion.
+ ///
+ /// # Errors
+ ///
+ /// The executor may be unable to spawn tasks, either because it has
+ /// been shut down or is resource-constrained.
+ fn spawn_obj(&mut self, task: TaskObj) -> Result<(), SpawnObjError>;
+
+ /// Determine whether the executor is able to spawn new tasks.
+ ///
+ /// # Returns
+ ///
+ /// An `Ok` return means the executor is *likely* (but not guaranteed)
+ /// to accept a subsequent spawn attempt. Likewise, an `Err` return
+ /// means that `spawn` is likely, but not guaranteed, to yield an error.
+ #[inline]
+ fn status(&self) -> Result<(), SpawnErrorKind> {
+ Ok(())
+ }
+}
+
+/// A custom trait object for polling tasks, roughly akin to
+/// `Box<Future<Output = ()> + Send>`.
+pub struct TaskObj {
+ ptr: *mut (),
+ poll: unsafe fn(*mut (), &mut Context) -> Poll<()>,
+ drop: unsafe fn(*mut ()),
+}
+
+impl fmt::Debug for TaskObj {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("TaskObj")
+ .finish()
+ }
+}
+
+unsafe impl Send for TaskObj {}
+unsafe impl Sync for TaskObj {}
+
+/// A custom implementation of a task trait object for `TaskObj`, providing
+/// a hand-rolled vtable.
+///
+/// This custom representation is typically used only in `no_std` contexts,
+/// where the default `Box`-based implementation is not available.
+///
+/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
+/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
+/// called.
+pub unsafe trait UnsafePoll: Send + 'static {
+ /// Convert a owned instance into a (conceptually owned) void pointer.
+ fn into_raw(self) -> *mut ();
+
+ /// Poll the task represented by the given void pointer.
+ ///
+ /// # Safety
+ ///
+ /// The trait implementor must guarantee that it is safe to repeatedly call
+ /// `poll` with the result of `into_raw` until `drop` is called; such calls
+ /// are not, however, allowed to race with each other or with calls to `drop`.
+ unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>;
+
+ /// Drops the task represented by the given void pointer.
+ ///
+ /// # Safety
+ ///
+ /// The trait implementor must guarantee that it is safe to call this
+ /// function once per `into_raw` invocation; that call cannot race with
+ /// other calls to `drop` or `poll`.
+ unsafe fn drop(task: *mut ());
+}
+
+impl TaskObj {
+ /// Create a `TaskObj` from a custom trait object representation.
+ #[inline]
+ pub fn from_poll_task<T: UnsafePoll>(t: T) -> TaskObj {
+ TaskObj {
+ ptr: t.into_raw(),
+ poll: T::poll,
+ drop: T::drop,
+ }
+ }
+
+ /// Poll the task.
+ ///
+ /// The semantics here are identical to that for futures, but unlike
+ /// futures only an `&mut self` reference is needed here.
+ #[inline]
+ pub fn poll_task(&mut self, cx: &mut Context) -> Poll<()> {
+ unsafe {
+ (self.poll)(self.ptr, cx)
+ }
+ }
+}
+
+impl Drop for TaskObj {
+ fn drop(&mut self) {
+ unsafe {
+ (self.drop)(self.ptr)
+ }
+ }
+}
+
+/// Provides the reason that an executor was unable to spawn.
+pub struct SpawnErrorKind {
+ _hidden: (),
+}
+
+impl fmt::Debug for SpawnErrorKind {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_tuple("SpawnErrorKind")
+ .field(&"shutdown")
+ .finish()
+ }
+}
+
+impl SpawnErrorKind {
+ /// Spawning is failing because the executor has been shut down.
+ pub fn shutdown() -> SpawnErrorKind {
+ SpawnErrorKind { _hidden: () }
+ }
+
+ /// Check whether this error is the `shutdown` error.
+ pub fn is_shutdown(&self) -> bool {
+ true
+ }
+}
+
+/// The result of a failed spawn
+#[derive(Debug)]
+pub struct SpawnObjError {
+ /// The kind of error
+ pub kind: SpawnErrorKind,
+
+ /// The task for which spawning was attempted
+ pub task: TaskObj,
+}
graphviz = { path = "../libgraphviz" }
jobserver = "0.1"
lazy_static = "1.0.0"
+scoped-tls = { version = "0.1.1", features = ["nightly"] }
log = { version = "0.4", features = ["release_max_level_info", "std"] }
-polonius-engine = "0.4.0"
+polonius-engine = "0.5.0"
proc_macro = { path = "../libproc_macro" }
+rustc-rayon = "0.1.1"
+rustc-rayon-core = "0.1.1"
rustc_apfloat = { path = "../librustc_apfloat" }
rustc_target = { path = "../librustc_target" }
rustc_data_structures = { path = "../librustc_data_structures" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
backtrace = "0.3.3"
+parking_lot = "0.5.5"
byteorder = { version = "1.1", features = ["i128"]}
chalk-engine = { version = "0.6.0", default-features=false }
impl_stable_hash_for!(struct ::middle::const_val::FrameInfo {
span,
+ lint_root,
location
});
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
- NonConstPath |
TypeckError |
+ CouldNotResolve |
CheckMatchError => {
// nothing to do
}
- UnimplementedConstVal(s) => {
- s.hash_stable(hcx, hasher);
- }
- IndexOutOfBounds { len, index } => {
- len.hash_stable(hcx, hasher);
- index.hash_stable(hcx, hasher);
- }
- LayoutError(ref layout_error) => {
- layout_error.hash_stable(hcx, hasher);
- }
Miri(ref err, ref trace) => {
err.hash_stable(hcx, hasher);
trace.hash_stable(hcx, hasher);
RemainderByZero |
DivisionByZero |
GeneratorResumedAfterReturn |
- GeneratorResumedAfterPanic |
- ReferencedConstant => {}
+ GeneratorResumedAfterPanic => {}
+ ReferencedConstant(ref err) => err.hash_stable(hcx, hasher),
MachineError(ref err) => err.hash_stable(hcx, hasher),
FunctionPointerTyMismatch(a, b) => {
a.hash_stable(hcx, hasher);
#![feature(unboxed_closures)]
#![feature(trace_macros)]
#![feature(trusted_len)]
+#![feature(vec_remove_item)]
#![feature(catch_expr)]
#![feature(integer_atomics)]
#![feature(test)]
extern crate getopts;
extern crate graphviz;
#[macro_use] extern crate lazy_static;
+#[macro_use] extern crate scoped_tls;
#[cfg(windows)]
extern crate libc;
extern crate polonius_engine;
extern crate rustc_target;
#[macro_use] extern crate rustc_data_structures;
extern crate serialize;
+extern crate parking_lot;
extern crate rustc_errors as errors;
+extern crate rustc_rayon as rayon;
+extern crate rustc_rayon_core as rayon_core;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;
use errors::{Applicability, DiagnosticBuilder};
use lint::{LintPass, LateLintPass, LintArray};
use session::Session;
+use syntax::ast;
use syntax::codemap::Span;
declare_lint! {
"warns about duplicate associated type bindings in generics"
}
+declare_lint! {
+ pub DUPLICATE_MACRO_EXPORTS,
+ Deny,
+ "detects duplicate macro exports"
+}
+
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
UNSTABLE_NAME_COLLISIONS,
DUPLICATE_ASSOCIATED_TYPE_BINDINGS,
+ DUPLICATE_MACRO_EXPORTS,
)
}
}
Normal,
BareTraitObject(Span, /* is_global */ bool),
AbsPathWithModule(Span),
+ DuplicatedMacroExports(ast::Ident, Span, Span),
}
impl BuiltinLintDiagnostics {
};
db.span_suggestion_with_applicability(span, "use `crate`", sugg, app);
}
+ BuiltinLintDiagnostics::DuplicatedMacroExports(ident, earlier_span, later_span) => {
+ db.span_label(later_span, format!("`{}` already exported", ident));
+ db.span_note(earlier_span, "previous macro export is now shadowed");
+ }
}
}
}
f(self);
self.param_env = old_param_env;
}
+ pub fn current_lint_root(&self) -> ast::NodeId {
+ self.last_ast_node_with_lint_attrs
+ }
}
impl<'a, 'tcx> LayoutOf for &'a LateContext<'a, 'tcx> {
// except according to those terms.
use hir::def_id::DefId;
-use ty::{self, TyCtxt, layout};
+use ty;
use ty::subst::Substs;
+use ty::maps::TyCtxtAt;
use mir::interpret::ConstValue;
use errors::DiagnosticBuilder;
use graphviz::IntoCow;
use syntax_pos::Span;
+use syntax::ast;
use std::borrow::Cow;
use rustc_data_structures::sync::Lrc;
Value(ConstValue<'tcx>),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ConstEvalErr<'tcx> {
pub span: Span,
pub kind: Lrc<ErrKind<'tcx>>,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum ErrKind<'tcx> {
- NonConstPath,
- UnimplementedConstVal(&'static str),
- IndexOutOfBounds { len: u64, index: u64 },
-
- LayoutError(layout::LayoutError<'tcx>),
-
+ CouldNotResolve,
TypeckError,
CheckMatchError,
Miri(::mir::interpret::EvalError<'tcx>, Vec<FrameInfo>),
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct FrameInfo {
pub span: Span,
pub location: String,
+ pub lint_root: Option<ast::NodeId>,
}
#[derive(Clone, Debug)]
}
match *self.kind {
- NonConstPath => simple!("non-constant path in constant expression"),
- UnimplementedConstVal(what) =>
- simple!("unimplemented constant expression: {}", what),
- IndexOutOfBounds { len, index } => {
- simple!("index out of bounds: the len is {} but the index is {}",
- len, index)
- }
-
- LayoutError(ref err) => Simple(err.to_string().into_cow()),
-
+ CouldNotResolve => simple!("could not resolve"),
TypeckError => simple!("type-checking failed"),
CheckMatchError => simple!("match-checking failed"),
Miri(ref err, ref trace) => Backtrace(err, trace),
}
pub fn struct_error(&self,
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- primary_span: Span,
- primary_kind: &str)
- -> DiagnosticBuilder<'gcx>
+ tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
+ message: &str)
+ -> Option<DiagnosticBuilder<'tcx>>
{
- let mut diag = struct_error(tcx, self.span, "constant evaluation error");
- self.note(tcx, primary_span, primary_kind, &mut diag);
- diag
+ self.struct_generic(tcx, message, None, true)
}
- pub fn note(&self,
- _tcx: TyCtxt<'a, 'gcx, 'tcx>,
- primary_span: Span,
- primary_kind: &str,
- diag: &mut DiagnosticBuilder)
- {
- match self.description() {
- ConstEvalErrDescription::Simple(message) => {
- diag.span_label(self.span, message);
- }
- ConstEvalErrDescription::Backtrace(miri, frames) => {
- diag.span_label(self.span, format!("{}", miri));
- for frame in frames {
- diag.span_label(frame.span, format!("inside call to `{}`", frame.location));
- }
- }
+ pub fn report_as_error(&self,
+ tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
+ message: &str
+ ) {
+ let err = self.struct_generic(tcx, message, None, true);
+ if let Some(mut err) = err {
+ err.emit();
}
+ }
- if !primary_span.contains(self.span) {
- diag.span_note(primary_span,
- &format!("for {} here", primary_kind));
+ pub fn report_as_lint(&self,
+ tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
+ message: &str,
+ lint_root: ast::NodeId,
+ ) {
+ let lint = self.struct_generic(
+ tcx,
+ message,
+ Some(lint_root),
+ false,
+ );
+ if let Some(mut lint) = lint {
+ lint.emit();
}
}
- pub fn report(&self,
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- primary_span: Span,
- primary_kind: &str)
- {
- match *self.kind {
- ErrKind::TypeckError | ErrKind::CheckMatchError => return,
- ErrKind::Miri(ref miri, _) => {
+ fn struct_generic(
+ &self,
+ tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
+ message: &str,
+ lint_root: Option<ast::NodeId>,
+ as_err: bool,
+ ) -> Option<DiagnosticBuilder<'tcx>> {
+ let (msg, frames): (_, &[_]) = match *self.kind {
+ ErrKind::TypeckError | ErrKind::CheckMatchError => return None,
+ ErrKind::Miri(ref miri, ref frames) => {
match miri.kind {
::mir::interpret::EvalErrorKind::TypeckError |
- ::mir::interpret::EvalErrorKind::Layout(_) => return,
- _ => {},
+ ::mir::interpret::EvalErrorKind::Layout(_) => return None,
+ ::mir::interpret::EvalErrorKind::ReferencedConstant(ref inner) => {
+ inner.struct_generic(tcx, "referenced constant", lint_root, as_err)?.emit();
+ (miri.to_string(), frames)
+ },
+ _ => (miri.to_string(), frames),
}
}
- _ => {}
+ _ => (self.description().into_oneline().to_string(), &[]),
+ };
+ trace!("reporting const eval failure at {:?}", self.span);
+ let mut err = if as_err {
+ struct_error(tcx, message)
+ } else {
+ let node_id = frames
+ .iter()
+ .rev()
+ .filter_map(|frame| frame.lint_root)
+ .next()
+ .or(lint_root)
+ .expect("some part of a failing const eval must be local");
+ tcx.struct_span_lint_node(
+ ::rustc::lint::builtin::CONST_ERR,
+ node_id,
+ tcx.span,
+ message,
+ )
+ };
+ err.span_label(self.span, msg);
+ for FrameInfo { span, location, .. } in frames {
+ err.span_label(*span, format!("inside call to `{}`", location));
}
- self.struct_error(tcx, primary_span, primary_kind).emit();
+ Some(err)
}
}
pub fn struct_error<'a, 'gcx, 'tcx>(
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- span: Span,
+ tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
msg: &str,
-) -> DiagnosticBuilder<'gcx> {
- struct_span_err!(tcx.sess, span, E0080, "{}", msg)
+) -> DiagnosticBuilder<'tcx> {
+ struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
}
use std::{fmt, env};
use mir;
+use middle::const_val::ConstEvalErr;
use ty::{FnSig, Ty, layout};
use ty::layout::{Size, Align};
use backtrace::Backtrace;
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
pub struct EvalError<'tcx> {
pub kind: EvalErrorKind<'tcx, u64>,
- pub backtrace: Option<Backtrace>,
}
impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
- let backtrace = match env::var("MIRI_BACKTRACE") {
- Ok(ref val) if !val.is_empty() => Some(Backtrace::new_unresolved()),
- _ => None
- };
+ match env::var("MIRI_BACKTRACE") {
+ Ok(ref val) if !val.is_empty() => {
+ let backtrace = Backtrace::new();
+
+ use std::fmt::Write;
+ let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
+ write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap();
+ 'frames: for (i, frame) in backtrace.frames().iter().enumerate() {
+ if frame.symbols().is_empty() {
+ write!(trace_text, "{}: no symbols\n", i).unwrap();
+ }
+ for symbol in frame.symbols() {
+ write!(trace_text, "{}: ", i).unwrap();
+ if let Some(name) = symbol.name() {
+ write!(trace_text, "{}\n", name).unwrap();
+ } else {
+ write!(trace_text, "<unknown>\n").unwrap();
+ }
+ write!(trace_text, "\tat ").unwrap();
+ if let Some(file_path) = symbol.filename() {
+ write!(trace_text, "{}", file_path.display()).unwrap();
+ } else {
+ write!(trace_text, "<unknown_file>").unwrap();
+ }
+ if let Some(line) = symbol.lineno() {
+ write!(trace_text, ":{}\n", line).unwrap();
+ } else {
+ write!(trace_text, "\n").unwrap();
+ }
+ }
+ }
+ error!("{}", trace_text);
+ },
+ _ => {},
+ }
EvalError {
kind,
- backtrace,
}
}
}
TypeckError,
/// Cannot compute this constant because it depends on another one
/// which already produced an error
- ReferencedConstant,
+ ReferencedConstant(ConstEvalErr<'tcx>),
GeneratorResumedAfterReturn,
GeneratorResumedAfterPanic,
}
"there were unresolved type arguments during trait selection",
TypeckError =>
"encountered constants with type errors, stopping evaluation",
- ReferencedConstant =>
+ ReferencedConstant(_) =>
"referenced constant has errors",
Overflow(mir::BinOp::Add) => "attempt to add with overflow",
Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
}
ConstEvalFailure(ref err) => {
- if let ::middle::const_val::ErrKind::TypeckError = *err.kind {
- return;
+ match err.struct_error(
+ self.tcx.at(span),
+ "could not evaluate constant expression",
+ ) {
+ Some(err) => err,
+ None => return,
}
- err.struct_error(self.tcx, span, "constant expression")
}
Overflow => {
} else {
Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr {
span: obligation.cause.span,
- kind: ErrKind::UnimplementedConstVal("could not resolve")
- .into(),
+ kind: ErrKind::CouldNotResolve.into(),
})))
}
},
pub mod tls {
use super::{GlobalCtxt, TyCtxt};
- use std::cell::Cell;
use std::fmt;
use std::mem;
use syntax_pos;
use ty::maps;
use errors::{Diagnostic, TRACK_DIAGNOSTICS};
use rustc_data_structures::OnDrop;
- use rustc_data_structures::sync::{self, Lrc};
+ use rustc_data_structures::sync::{self, Lrc, Lock};
use dep_graph::OpenTask;
+ #[cfg(not(parallel_queries))]
+ use std::cell::Cell;
+
+ #[cfg(parallel_queries)]
+ use rayon_core;
+
/// This is the implicit state of rustc. It contains the current
/// TyCtxt and query. It is updated when creating a local interner or
/// executing a new query. Whenever there's a TyCtxt value available
pub task: &'a OpenTask,
}
- // A thread local value which stores a pointer to the current ImplicitCtxt
+ /// Sets Rayon's thread local variable which is preserved for Rayon jobs
+ /// to `value` during the call to `f`. It is restored to its previous value after.
+ /// This is used to set the pointer to the new ImplicitCtxt.
+ #[cfg(parallel_queries)]
+ fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R {
+ rayon_core::tlv::with(value, f)
+ }
+
+ /// Gets Rayon's thread local variable which is preserved for Rayon jobs.
+ /// This is used to get the pointer to the current ImplicitCtxt.
+ #[cfg(parallel_queries)]
+ fn get_tlv() -> usize {
+ rayon_core::tlv::get()
+ }
+
+ /// A thread local variable which stores a pointer to the current ImplicitCtxt
+ #[cfg(not(parallel_queries))]
thread_local!(static TLV: Cell<usize> = Cell::new(0));
+ /// Sets TLV to `value` during the call to `f`.
+ /// It is restored to its previous value after.
+ /// This is used to set the pointer to the new ImplicitCtxt.
+ #[cfg(not(parallel_queries))]
fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R {
let old = get_tlv();
let _reset = OnDrop(move || TLV.with(|tlv| tlv.set(old)));
f()
}
+ /// This is used to get the pointer to the current ImplicitCtxt.
+ #[cfg(not(parallel_queries))]
fn get_tlv() -> usize {
TLV.with(|tlv| tlv.get())
}
where F: for<'a> FnOnce(TyCtxt<'a, 'gcx, 'gcx>) -> R
{
with_thread_locals(|| {
+ // Update GCX_PTR to indicate there's a GlobalCtxt available
+ GCX_PTR.with(|lock| {
+ *lock.lock() = gcx as *const _ as usize;
+ });
+ // Set GCX_PTR back to 0 when we exit
+ let _on_drop = OnDrop(move || {
+ GCX_PTR.with(|lock| *lock.lock() = 0);
+ });
+
let tcx = TyCtxt {
gcx,
interners: &gcx.global_interners,
})
}
+ /// Stores a pointer to the GlobalCtxt if one is available.
+ /// This is used to access the GlobalCtxt in the deadlock handler
+ /// given to Rayon.
+ scoped_thread_local!(pub static GCX_PTR: Lock<usize>);
+
+ /// Creates a TyCtxt and ImplicitCtxt based on the GCX_PTR thread local.
+ /// This is used in the deadlock handler.
+ pub unsafe fn with_global<F, R>(f: F) -> R
+ where F: for<'a, 'gcx, 'tcx> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> R
+ {
+ let gcx = GCX_PTR.with(|lock| *lock.lock());
+ assert!(gcx != 0);
+ let gcx = &*(gcx as *const GlobalCtxt<'_>);
+ let tcx = TyCtxt {
+ gcx,
+ interners: &gcx.global_interners,
+ };
+ let icx = ImplicitCtxt {
+ query: None,
+ tcx,
+ layout_depth: 0,
+ task: &OpenTask::Ignore,
+ };
+ enter_context(&icx, |_| f(tcx))
+ }
+
/// Allows access to the current ImplicitCtxt in a closure if one is available
pub fn with_context_opt<F, R>(f: F) -> R
where F: for<'a, 'gcx, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'gcx, 'tcx>>) -> R
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc_data_structures::sync::{Lock, Lrc};
+#![allow(warnings)]
+
+use std::mem;
+use rustc_data_structures::sync::{Lock, LockGuard, Lrc, Weak};
+use rustc_data_structures::OnDrop;
use syntax_pos::Span;
use ty::tls;
use ty::maps::Query;
use ty::maps::plumbing::CycleError;
use ty::context::TyCtxt;
use errors::Diagnostic;
+use std::process;
+use std::fmt;
+use std::collections::HashSet;
+#[cfg(parallel_queries)]
+use {
+ rayon_core,
+ parking_lot::{Mutex, Condvar},
+ std::sync::atomic::Ordering,
+ std::thread,
+ std::iter,
+ std::iter::FromIterator,
+ syntax_pos::DUMMY_SP,
+ rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, HashStable},
+};
/// Indicates the state of a query for a given key in a query map
pub(super) enum QueryResult<'tcx> {
/// Diagnostic messages which are emitted while the query executes
pub diagnostics: Lock<Vec<Diagnostic>>,
+
+ /// The latch which is used to wait on this job
+ #[cfg(parallel_queries)]
+ latch: QueryLatch<'tcx>,
}
impl<'tcx> QueryJob<'tcx> {
diagnostics: Lock::new(Vec::new()),
info,
parent,
+ #[cfg(parallel_queries)]
+ latch: QueryLatch::new(),
}
}
&self,
tcx: TyCtxt<'_, 'tcx, 'lcx>,
span: Span,
+ ) -> Result<(), CycleError<'tcx>> {
+ #[cfg(not(parallel_queries))]
+ {
+ self.find_cycle_in_stack(tcx, span)
+ }
+
+ #[cfg(parallel_queries)]
+ {
+ tls::with_related_context(tcx, move |icx| {
+ let mut waiter = Lrc::new(QueryWaiter {
+ query: icx.query.clone(),
+ span,
+ cycle: Lock::new(None),
+ condvar: Condvar::new(),
+ });
+ self.latch.await(&waiter);
+
+ match Lrc::get_mut(&mut waiter).unwrap().cycle.get_mut().take() {
+ None => Ok(()),
+ Some(cycle) => Err(cycle)
+ }
+ })
+ }
+ }
+
+ #[cfg(not(parallel_queries))]
+ fn find_cycle_in_stack<'lcx>(
+ &self,
+ tcx: TyCtxt<'_, 'tcx, 'lcx>,
+ span: Span,
) -> Result<(), CycleError<'tcx>> {
// Get the current executing query (waiter) and find the waitee amongst its parents
let mut current_job = tls::with_related_context(tcx, |icx| icx.query.clone());
///
/// This does nothing for single threaded rustc,
/// as there are no concurrent jobs which could be waiting on us
- pub fn signal_complete(&self) {}
+ pub fn signal_complete(&self) {
+ #[cfg(parallel_queries)]
+ self.latch.set();
+ }
+
+ fn as_ptr(&self) -> *const QueryJob<'tcx> {
+ self as *const _
+ }
+}
+
+#[cfg(parallel_queries)]
+struct QueryWaiter<'tcx> {
+ query: Option<Lrc<QueryJob<'tcx>>>,
+ condvar: Condvar,
+ span: Span,
+ cycle: Lock<Option<CycleError<'tcx>>>,
+}
+
+#[cfg(parallel_queries)]
+impl<'tcx> QueryWaiter<'tcx> {
+ fn notify(&self, registry: &rayon_core::Registry) {
+ rayon_core::mark_unblocked(registry);
+ self.condvar.notify_one();
+ }
+}
+
+#[cfg(parallel_queries)]
+struct QueryLatchInfo<'tcx> {
+ complete: bool,
+ waiters: Vec<Lrc<QueryWaiter<'tcx>>>,
+}
+
+#[cfg(parallel_queries)]
+struct QueryLatch<'tcx> {
+ info: Mutex<QueryLatchInfo<'tcx>>,
+}
+
+#[cfg(parallel_queries)]
+impl<'tcx> QueryLatch<'tcx> {
+ fn new() -> Self {
+ QueryLatch {
+ info: Mutex::new(QueryLatchInfo {
+ complete: false,
+ waiters: Vec::new(),
+ }),
+ }
+ }
+
+ /// Awaits the caller on this latch by blocking the current thread.
+ fn await(&self, waiter: &Lrc<QueryWaiter<'tcx>>) {
+ let mut info = self.info.lock();
+ if !info.complete {
+ // We push the waiter on to the `waiters` list. It can be accessed inside
+ // the `wait` call below, by 1) the `set` method or 2) by deadlock detection.
+ // Both of these will remove it from the `waiters` list before resuming
+ // this thread.
+ info.waiters.push(waiter.clone());
+
+ // If this detects a deadlock and the deadlock handler wants to resume this thread
+ // we have to be in the `wait` call. This is ensured by the deadlock handler
+ // getting the self.info lock.
+ rayon_core::mark_blocked();
+ waiter.condvar.wait(&mut info);
+ }
+ }
+
+ /// Sets the latch and resumes all waiters on it
+ fn set(&self) {
+ let mut info = self.info.lock();
+ debug_assert!(!info.complete);
+ info.complete = true;
+ let registry = rayon_core::Registry::current();
+ for waiter in info.waiters.drain(..) {
+ waiter.notify(®istry);
+ }
+ }
+
+ /// Remove a single waiter from the list of waiters.
+ /// This is used to break query cycles.
+ fn extract_waiter(
+ &self,
+ waiter: usize,
+ ) -> Lrc<QueryWaiter<'tcx>> {
+ let mut info = self.info.lock();
+ debug_assert!(!info.complete);
+ // Remove the waiter from the list of waiters
+ info.waiters.remove(waiter)
+ }
+}
+
+/// A resumable waiter of a query. The usize is the index into waiters in the query's latch
+#[cfg(parallel_queries)]
+type Waiter<'tcx> = (Lrc<QueryJob<'tcx>>, usize);
+
+/// Visits all the non-resumable and resumable waiters of a query.
+/// Only waiters in a query are visited.
+/// `visit` is called for every waiter and is passed a query waiting on `query_ref`
+/// and a span indicating the reason the query waited on `query_ref`.
+/// If `visit` returns Some, this function returns.
+/// For visits of non-resumable waiters it returns the return value of `visit`.
+/// For visits of resumable waiters it returns Some(Some(Waiter)) which has the
+/// required information to resume the waiter.
+/// If all `visit` calls returns None, this function also returns None.
+#[cfg(parallel_queries)]
+fn visit_waiters<'tcx, F>(query: Lrc<QueryJob<'tcx>>, mut visit: F) -> Option<Option<Waiter<'tcx>>>
+where
+ F: FnMut(Span, Lrc<QueryJob<'tcx>>) -> Option<Option<Waiter<'tcx>>>
+{
+ // Visit the parent query which is a non-resumable waiter since it's on the same stack
+ if let Some(ref parent) = query.parent {
+ if let Some(cycle) = visit(query.info.span, parent.clone()) {
+ return Some(cycle);
+ }
+ }
+
+ // Visit the explict waiters which use condvars and are resumable
+ for (i, waiter) in query.latch.info.lock().waiters.iter().enumerate() {
+ if let Some(ref waiter_query) = waiter.query {
+ if visit(waiter.span, waiter_query.clone()).is_some() {
+ // Return a value which indicates that this waiter can be resumed
+ return Some(Some((query.clone(), i)));
+ }
+ }
+ }
+ None
+}
+
+/// Look for query cycles by doing a depth first search starting at `query`.
+/// `span` is the reason for the `query` to execute. This is initially DUMMY_SP.
+/// If a cycle is detected, this initial value is replaced with the span causing
+/// the cycle.
+#[cfg(parallel_queries)]
+fn cycle_check<'tcx>(query: Lrc<QueryJob<'tcx>>,
+ span: Span,
+ stack: &mut Vec<(Span, Lrc<QueryJob<'tcx>>)>,
+ visited: &mut HashSet<*const QueryJob<'tcx>>
+) -> Option<Option<Waiter<'tcx>>> {
+ if visited.contains(&query.as_ptr()) {
+ return if let Some(p) = stack.iter().position(|q| q.1.as_ptr() == query.as_ptr()) {
+ // We detected a query cycle, fix up the initial span and return Some
+
+ // Remove previous stack entries
+ stack.splice(0..p, iter::empty());
+ // Replace the span for the first query with the cycle cause
+ stack[0].0 = span;
+ Some(None)
+ } else {
+ None
+ }
+ }
+
+ // Mark this query is visited and add it to the stack
+ visited.insert(query.as_ptr());
+ stack.push((span, query.clone()));
+
+ // Visit all the waiters
+ let r = visit_waiters(query, |span, successor| {
+ cycle_check(successor, span, stack, visited)
+ });
+
+ // Remove the entry in our stack if we didn't find a cycle
+ if r.is_none() {
+ stack.pop();
+ }
+
+ r
+}
+
+/// Finds out if there's a path to the compiler root (aka. code which isn't in a query)
+/// from `query` without going through any of the queries in `visited`.
+/// This is achieved with a depth first search.
+#[cfg(parallel_queries)]
+fn connected_to_root<'tcx>(
+ query: Lrc<QueryJob<'tcx>>,
+ visited: &mut HashSet<*const QueryJob<'tcx>>
+) -> bool {
+ // We already visited this or we're deliberately ignoring it
+ if visited.contains(&query.as_ptr()) {
+ return false;
+ }
+
+ // This query is connected to the root (it has no query parent), return true
+ if query.parent.is_none() {
+ return true;
+ }
+
+ visited.insert(query.as_ptr());
+
+ let mut connected = false;
+
+ visit_waiters(query, |_, successor| {
+ if connected_to_root(successor, visited) {
+ Some(None)
+ } else {
+ None
+ }
+ }).is_some()
+}
+
+/// Looks for query cycles starting from the last query in `jobs`.
+/// If a cycle is found, all queries in the cycle is removed from `jobs` and
+/// the function return true.
+/// If a cycle was not found, the starting query is removed from `jobs` and
+/// the function returns false.
+#[cfg(parallel_queries)]
+fn remove_cycle<'tcx>(
+ jobs: &mut Vec<Lrc<QueryJob<'tcx>>>,
+ wakelist: &mut Vec<Lrc<QueryWaiter<'tcx>>>,
+ tcx: TyCtxt<'_, 'tcx, '_>
+) -> bool {
+ let mut visited = HashSet::new();
+ let mut stack = Vec::new();
+ // Look for a cycle starting with the last query in `jobs`
+ if let Some(waiter) = cycle_check(jobs.pop().unwrap(),
+ DUMMY_SP,
+ &mut stack,
+ &mut visited) {
+ // Reverse the stack so earlier entries require later entries
+ stack.reverse();
+
+ // Extract the spans and queries into separate arrays
+ let mut spans: Vec<_> = stack.iter().map(|e| e.0).collect();
+ let queries = stack.into_iter().map(|e| e.1);
+
+ // Shift the spans so that queries are matched with the span for their waitee
+ let last = spans.pop().unwrap();
+ spans.insert(0, last);
+
+ // Zip them back together
+ let mut stack: Vec<_> = spans.into_iter().zip(queries).collect();
+
+ // Remove the queries in our cycle from the list of jobs to look at
+ for r in &stack {
+ if let Some(pos) = jobs.iter().position(|j| j.as_ptr() == r.1.as_ptr()) {
+ jobs.remove(pos);
+ }
+ }
+
+ // Find the queries in the cycle which are
+ // connected to queries outside the cycle
+ let entry_points: Vec<Lrc<QueryJob<'tcx>>> = stack.iter().filter_map(|query| {
+ // Mark all the other queries in the cycle as already visited
+ let mut visited = HashSet::from_iter(stack.iter().filter_map(|q| {
+ if q.1.as_ptr() != query.1.as_ptr() {
+ Some(q.1.as_ptr())
+ } else {
+ None
+ }
+ }));
+
+ if connected_to_root(query.1.clone(), &mut visited) {
+ Some(query.1.clone())
+ } else {
+ None
+ }
+ }).collect();
+
+ // Deterministically pick an entry point
+ // FIXME: Sort this instead
+ let mut hcx = tcx.create_stable_hashing_context();
+ let entry_point = entry_points.iter().min_by_key(|q| {
+ let mut stable_hasher = StableHasher::<u64>::new();
+ q.info.query.hash_stable(&mut hcx, &mut stable_hasher);
+ stable_hasher.finish()
+ }).unwrap().as_ptr();
+
+ // Shift the stack until our entry point is first
+ while stack[0].1.as_ptr() != entry_point {
+ let last = stack.pop().unwrap();
+ stack.insert(0, last);
+ }
+
+ // Create the cycle error
+ let mut error = CycleError {
+ usage: None,
+ cycle: stack.iter().map(|&(s, ref q)| QueryInfo {
+ span: s,
+ query: q.info.query.clone(),
+ } ).collect(),
+ };
+
+ // We unwrap `waiter` here since there must always be one
+ // edge which is resumeable / waited using a query latch
+ let (waitee_query, waiter_idx) = waiter.unwrap();
+
+ // Extract the waiter we want to resume
+ let waiter = waitee_query.latch.extract_waiter(waiter_idx);
+
+ // Set the cycle error so it will be picked up when resumed
+ *waiter.cycle.lock() = Some(error);
+
+ // Put the waiter on the list of things to resume
+ wakelist.push(waiter);
+
+ true
+ } else {
+ false
+ }
+}
+
+/// Creates a new thread and forwards information in thread locals to it.
+/// The new thread runs the deadlock handler.
+/// Must only be called when a deadlock is about to happen.
+#[cfg(parallel_queries)]
+pub unsafe fn handle_deadlock() {
+ use syntax;
+ use syntax_pos;
+
+ let registry = rayon_core::Registry::current();
+
+ let gcx_ptr = tls::GCX_PTR.with(|gcx_ptr| {
+ gcx_ptr as *const _
+ });
+ let gcx_ptr = &*gcx_ptr;
+
+ let syntax_globals = syntax::GLOBALS.with(|syntax_globals| {
+ syntax_globals as *const _
+ });
+ let syntax_globals = &*syntax_globals;
+
+ let syntax_pos_globals = syntax_pos::GLOBALS.with(|syntax_pos_globals| {
+ syntax_pos_globals as *const _
+ });
+ let syntax_pos_globals = &*syntax_pos_globals;
+ thread::spawn(move || {
+ tls::GCX_PTR.set(gcx_ptr, || {
+ syntax_pos::GLOBALS.set(syntax_pos_globals, || {
+ syntax_pos::GLOBALS.set(syntax_pos_globals, || {
+ tls::with_thread_locals(|| {
+ tls::with_global(|tcx| deadlock(tcx, ®istry))
+ })
+ })
+ })
+ })
+ });
+}
+
+/// Detects query cycles by using depth first search over all active query jobs.
+/// If a query cycle is found it will break the cycle by finding an edge which
+/// uses a query latch and then resuming that waiter.
+/// There may be multiple cycles involved in a deadlock, so this searches
+/// all active queries for cycles before finally resuming all the waiters at once.
+#[cfg(parallel_queries)]
+fn deadlock(tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) {
+ let on_panic = OnDrop(|| {
+ eprintln!("deadlock handler panicked, aborting process");
+ process::abort();
+ });
+
+ let mut wakelist = Vec::new();
+ let mut jobs: Vec<_> = tcx.maps.collect_active_jobs();
+
+ let mut found_cycle = false;
+
+ while jobs.len() > 0 {
+ if remove_cycle(&mut jobs, &mut wakelist, tcx) {
+ found_cycle = true;
+ }
+ }
+
+ // Check that a cycle was found. It is possible for a deadlock to occur without
+ // a query cycle if a query which can be waited on uses Rayon to do multithreading
+ // internally. Such a query (X) may be executing on 2 threads (A and B) and A may
+ // wait using Rayon on B. Rayon may then switch to executing another query (Y)
+ // which in turn will wait on X causing a deadlock. We have a false dependency from
+ // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here
+ // only considers the true dependency and won't detect a cycle.
+ assert!(found_cycle);
+
+ // FIXME: Ensure this won't cause a deadlock before we return
+ for waiter in wakelist.into_iter() {
+ waiter.notify(registry);
+ }
+
+ on_panic.disable();
}
#[macro_use]
mod plumbing;
use self::plumbing::*;
-pub use self::plumbing::force_from_dep_node;
+pub use self::plumbing::{force_from_dep_node, CycleError};
mod job;
pub use self::job::{QueryJob, QueryInfo};
+#[cfg(parallel_queries)]
+pub use self::job::handle_deadlock;
mod keys;
pub use self::keys::Key;
}
#[derive(Clone)]
-pub(super) struct CycleError<'tcx> {
+pub struct CycleError<'tcx> {
/// The query and related span which uses the cycle
pub(super) usage: Option<(Span, Query<'tcx>)>,
pub(super) cycle: Vec<QueryInfo<'tcx>>,
$($(#[$attr:meta])*
[$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => {
+ use std::mem;
+ use ty::maps::job::QueryResult;
use rustc_data_structures::sync::Lock;
+ use {
+ rustc_data_structures::stable_hasher::HashStable,
+ rustc_data_structures::stable_hasher::StableHasherResult,
+ rustc_data_structures::stable_hasher::StableHasher,
+ ich::StableHashingContext
+ };
define_map_struct! {
tcx: $tcx,
$($name: Lock::new(QueryMap::new())),*
}
}
+
+ pub fn collect_active_jobs(&self) -> Vec<Lrc<QueryJob<$tcx>>> {
+ let mut jobs = Vec::new();
+
+ // We use try_lock here since we are only called from the
+ // deadlock handler, and this shouldn't be locked
+ $(for v in self.$name.try_lock().unwrap().active.values() {
+ match *v {
+ QueryResult::Started(ref job) => jobs.push(job.clone()),
+ _ => (),
+ }
+ })*
+
+ return jobs;
+ }
}
#[allow(bad_style)]
- #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+ #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Query<$tcx> {
$($(#[$attr])* $name($K)),*
}
}
}
+ impl<'a, $tcx> HashStable<StableHashingContext<'a>> for Query<$tcx> {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ mem::discriminant(self).hash_stable(hcx, hasher);
+ match *self {
+ $(Query::$name(key) => key.hash_stable(hcx, hasher),)*
+ }
+ }
+ }
+
pub mod queries {
use std::marker::PhantomData;
} else {
info!("invalid enum discriminant: {:#?}", val);
::middle::const_val::struct_error(
- tcx,
- tcx.def_span(expr_did),
+ tcx.at(tcx.def_span(expr_did)),
"constant evaluation of enum discriminant resulted in non-integer",
).emit();
None
}
}
Err(err) => {
- err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
+ err.report_as_error(
+ tcx.at(tcx.def_span(expr_did)),
+ "could not evaluate enum discriminant",
+ );
if !expr_did.is_local() {
span_bug!(tcx.def_span(expr_did),
"variant discriminant evaluation succeeded \
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
Some(interpret::EvalError {
kind: tcx.lift(&self.kind)?,
- backtrace: self.backtrace.clone(),
})
}
}
PathNotFound(ref v) => PathNotFound(v.clone()),
UnimplementedTraitSelection => UnimplementedTraitSelection,
TypeckError => TypeckError,
- ReferencedConstant => ReferencedConstant,
+ ReferencedConstant(ref err) => ReferencedConstant(tcx.lift(err)?),
OverflowNeg => OverflowNeg,
Overflow(op) => Overflow(op),
DivisionByZero => DivisionByZero,
use middle::const_val::ErrKind::*;
Some(match *self {
- NonConstPath => NonConstPath,
- UnimplementedConstVal(s) => UnimplementedConstVal(s),
- IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index },
-
- LayoutError(ref e) => {
- return tcx.lift(e).map(LayoutError)
- }
-
+ CouldNotResolve => CouldNotResolve,
TypeckError => TypeckError,
CheckMatchError => CheckMatchError,
Miri(ref e, ref frames) => return tcx.lift(e).map(|e| Miri(e, frames.clone())),
};
self.note_and_explain_mutbl_error(&mut db, &err, &error_span);
- self.note_immutability_blame(&mut db, err.cmt.immutability_blame());
+ self.note_immutability_blame(&mut db, err.cmt.immutability_blame(), err.cmt.id);
db.emit();
}
err_out_of_scope(super_scope, sub_scope, cause) => {
Origin::Ast)
}
};
- self.note_immutability_blame(&mut err, blame);
+ self.note_immutability_blame(&mut err, blame, cmt.id);
if is_closure {
err.help("closures behind references must be called via `&mut`");
fn note_immutability_blame(&self,
db: &mut DiagnosticBuilder,
- blame: Option<ImmutabilityBlame>) {
+ blame: Option<ImmutabilityBlame>,
+ error_node_id: ast::NodeId) {
match blame {
None => {}
Some(ImmutabilityBlame::ClosureEnv(_)) => {}
Some(ImmutabilityBlame::ImmLocal(node_id)) => {
- let let_span = self.tcx.hir.span(node_id);
- if let ty::BindByValue(..) = self.local_binding_mode(node_id) {
- if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
- let (_, is_implicit_self) = self.local_ty(node_id);
- if is_implicit_self && snippet != "self" {
- // avoid suggesting `mut &self`.
- return
- }
- db.span_label(
- let_span,
- format!("consider changing this to `mut {}`", snippet)
- );
- }
- }
+ self.note_immutable_local(db, error_node_id, node_id)
}
Some(ImmutabilityBlame::LocalDeref(node_id)) => {
let let_span = self.tcx.hir.span(node_id);
}
}
+ // Suggest a fix when trying to mutably borrow an immutable local
+ // binding: either to make the binding mutable (if its type is
+ // not a mutable reference) or to avoid borrowing altogether
+ fn note_immutable_local(&self,
+ db: &mut DiagnosticBuilder,
+ borrowed_node_id: ast::NodeId,
+ binding_node_id: ast::NodeId) {
+ let let_span = self.tcx.hir.span(binding_node_id);
+ if let ty::BindByValue(..) = self.local_binding_mode(binding_node_id) {
+ if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) {
+ let (ty, is_implicit_self) = self.local_ty(binding_node_id);
+ if is_implicit_self && snippet != "self" {
+ // avoid suggesting `mut &self`.
+ return
+ }
+ if let Some(&hir::TyRptr(
+ _,
+ hir::MutTy {
+ mutbl: hir::MutMutable,
+ ..
+ },
+ )) = ty.map(|t| &t.node)
+ {
+ let borrow_expr_id = self.tcx.hir.get_parent_node(borrowed_node_id);
+ db.span_suggestion(
+ self.tcx.hir.span(borrow_expr_id),
+ "consider removing the `&mut`, as it is an \
+ immutable binding to a mutable reference",
+ snippet
+ );
+ } else {
+ db.span_label(
+ let_span,
+ format!("consider changing this to `mut {}`", snippet),
+ );
+ }
+ }
+ }
+ }
+
fn report_out_of_scope_escaping_closure_capture(&self,
err: &BckError<'a, 'tcx>,
capture_span: Span)
Ok((llval, constant.ty))
})
.unwrap_or_else(|e| {
- e.report(bx.tcx(), constant.span, "shuffle_indices");
+ e.report_as_error(
+ bx.tcx().at(constant.span),
+ "could not evaluate shuffle_indices at compile time",
+ );
// We've errored, so we don't have to produce working code.
let ty = self.monomorphize(&constant.ty);
let llty = bx.cx.layout_of(ty).llvm_type(bx.cx);
// FIXME: generate a panic here
},
mir::Literal::Value { .. } => {
- err.report(bx.tcx(), constant.span, "const operand");
+ err.report_as_error(
+ bx.tcx().at(constant.span),
+ "could not evaluate constant operand",
+ );
},
}
// We've errored, so we don't have to produce working code.
cfg-if = "0.1.2"
stable_deref_trait = "1.0.0"
parking_lot_core = "0.2.8"
-rustc-rayon = "0.1.0"
-rustc-rayon-core = "0.1.0"
+rustc-rayon = "0.1.1"
+rustc-rayon-core = "0.1.1"
rustc-hash = "1.0.1"
[dependencies.parking_lot]
pub struct OnDrop<F: Fn()>(pub F);
+impl<F: Fn()> OnDrop<F> {
+ /// Forgets the function which prevents it from running.
+ /// Ensure that the function owns no memory, otherwise it will be leaked.
+ pub fn disable(self) {
+ std::mem::forget(self);
+ }
+}
+
impl<F: Fn()> Drop for OnDrop<F> {
fn drop(&mut self) {
(self.0)();
self.0.get_mut()
}
+ #[cfg(parallel_queries)]
+ #[inline(always)]
+ pub fn try_lock(&self) -> Option<LockGuard<T>> {
+ self.0.try_lock()
+ }
+
+ #[cfg(not(parallel_queries))]
+ #[inline(always)]
+ pub fn try_lock(&self) -> Option<LockGuard<T>> {
+ self.0.try_borrow_mut().ok()
+ }
+
#[cfg(parallel_queries)]
#[inline(always)]
pub fn lock(&self) -> LockGuard<T> {
graphviz = { path = "../libgraphviz" }
log = "0.4"
env_logger = { version = "0.5", default-features = false }
-rustc-rayon = "0.1.0"
+rustc-rayon = "0.1.1"
scoped-tls = { version = "0.1.1", features = ["nightly"] }
rustc = { path = "../librustc" }
rustc_allocator = { path = "../librustc_allocator" }
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
-use rustc_data_structures::sync::{self, Lrc};
+use rustc_data_structures::sync::{self, Lrc, Lock};
use std::sync::mpsc;
use syntax::{self, ast, attr, diagnostics, visit};
use syntax::ext::base::ExtCtxt;
opts: config::Options,
f: F
) -> R {
- f(opts)
+ ty::tls::GCX_PTR.set(&Lock::new(0), || {
+ f(opts)
+ })
}
#[cfg(parallel_queries)]
use syntax_pos;
use rayon::{ThreadPoolBuilder, ThreadPool};
- let config = ThreadPoolBuilder::new().num_threads(Session::query_threads_from_opts(&opts))
- .stack_size(16 * 1024 * 1024);
+ let gcx_ptr = &Lock::new(0);
+
+ let config = ThreadPoolBuilder::new()
+ .num_threads(Session::query_threads_from_opts(&opts))
+ .deadlock_handler(|| unsafe { ty::maps::handle_deadlock() })
+ .stack_size(16 * 1024 * 1024);
let with_pool = move |pool: &ThreadPool| {
pool.install(move || f(opts))
syntax::GLOBALS.set(syntax_globals, || {
syntax_pos::GLOBALS.set(syntax_pos_globals, || {
ty::tls::with_thread_locals(|| {
- worker()
+ ty::tls::GCX_PTR.set(gcx_ptr, || {
+ worker()
+ })
})
})
})
}
}
+/// This implementation makes it easier to create a custom driver when you only want to hook
+/// into callbacks from `CompileController`.
+///
+/// # Example
+///
+/// ```no_run
+/// # extern crate rustc_driver;
+/// # use rustc_driver::driver::CompileController;
+/// let mut controller = CompileController::basic();
+/// controller.after_analysis.callback = Box::new(move |_state| {});
+/// rustc_driver::run_compiler(&[], Box::new(controller), None, None);
+/// ```
+impl<'a> ::CompilerCalls<'a> for CompileController<'a> {
+ fn early_callback(
+ &mut self,
+ matches: &::getopts::Matches,
+ sopts: &config::Options,
+ cfg: &ast::CrateConfig,
+ descriptions: &::errors::registry::Registry,
+ output: ::ErrorOutputType,
+ ) -> Compilation {
+ ::RustcDefaultCalls.early_callback(
+ matches,
+ sopts,
+ cfg,
+ descriptions,
+ output,
+ )
+ }
+ fn no_input(
+ &mut self,
+ matches: &::getopts::Matches,
+ sopts: &config::Options,
+ cfg: &ast::CrateConfig,
+ odir: &Option<PathBuf>,
+ ofile: &Option<PathBuf>,
+ descriptions: &::errors::registry::Registry,
+ ) -> Option<(Input, Option<PathBuf>)> {
+ ::RustcDefaultCalls.no_input(
+ matches,
+ sopts,
+ cfg,
+ odir,
+ ofile,
+ descriptions,
+ )
+ }
+ fn late_callback(
+ &mut self,
+ codegen_backend: &::CodegenBackend,
+ matches: &::getopts::Matches,
+ sess: &Session,
+ cstore: &::CrateStore,
+ input: &Input,
+ odir: &Option<PathBuf>,
+ ofile: &Option<PathBuf>,
+ ) -> Compilation {
+ ::RustcDefaultCalls
+ .late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile)
+ }
+ fn build_controller(
+ self: Box<Self>,
+ _: &Session,
+ _: &::getopts::Matches
+ ) -> CompileController<'a> {
+ *self
+ }
+}
+
pub struct PhaseController<'a> {
pub stop: Compilation,
// If true then the compiler will try to run the callback even if the phase
// See comments on CompilerCalls below for details about the callbacks argument.
// The FileLoader provides a way to load files from sources other than the file system.
pub fn run_compiler<'a>(args: &[String],
- callbacks: &mut (CompilerCalls<'a> + sync::Send),
+ callbacks: Box<CompilerCalls<'a> + sync::Send + 'a>,
file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
emitter_dest: Option<Box<Write + Send>>)
-> (CompileResult, Option<Session>)
matches: getopts::Matches,
sopts: config::Options,
cfg: ast::CrateConfig,
- callbacks: &mut (CompilerCalls<'a> + sync::Send),
+ mut callbacks: Box<CompilerCalls<'a> + sync::Send + 'a>,
file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
emitter_dest: Option<Box<Write + Send>>
) -> (CompileResult, Option<Session>) {
}
}
-// A trait for customising the compilation process. Offers a number of hooks for
-// executing custom code or customising input.
+/// A trait for customising the compilation process. Offers a number of hooks for
+/// executing custom code or customising input.
pub trait CompilerCalls<'a> {
- // Hook for a callback early in the process of handling arguments. This will
- // be called straight after options have been parsed but before anything
- // else (e.g., selecting input and output).
+ /// Hook for a callback early in the process of handling arguments. This will
+ /// be called straight after options have been parsed but before anything
+ /// else (e.g., selecting input and output).
fn early_callback(&mut self,
_: &getopts::Matches,
_: &config::Options,
Compilation::Continue
}
- // Hook for a callback late in the process of handling arguments. This will
- // be called just before actual compilation starts (and before build_controller
- // is called), after all arguments etc. have been completely handled.
+ /// Hook for a callback late in the process of handling arguments. This will
+ /// be called just before actual compilation starts (and before build_controller
+ /// is called), after all arguments etc. have been completely handled.
fn late_callback(&mut self,
_: &CodegenBackend,
_: &getopts::Matches,
Compilation::Continue
}
- // Called after we extract the input from the arguments. Gives the implementer
- // an opportunity to change the inputs or to add some custom input handling.
- // The default behaviour is to simply pass through the inputs.
+ /// Called after we extract the input from the arguments. Gives the implementer
+ /// an opportunity to change the inputs or to add some custom input handling.
+ /// The default behaviour is to simply pass through the inputs.
fn some_input(&mut self,
input: Input,
input_path: Option<PathBuf>)
(input, input_path)
}
- // Called after we extract the input from the arguments if there is no valid
- // input. Gives the implementer an opportunity to supply alternate input (by
- // returning a Some value) or to add custom behaviour for this error such as
- // emitting error messages. Returning None will cause compilation to stop
- // at this point.
+ /// Called after we extract the input from the arguments if there is no valid
+ /// input. Gives the implementer an opportunity to supply alternate input (by
+ /// returning a Some value) or to add custom behaviour for this error such as
+ /// emitting error messages. Returning None will cause compilation to stop
+ /// at this point.
fn no_input(&mut self,
_: &getopts::Matches,
_: &config::Options,
// Create a CompilController struct for controlling the behaviour of
// compilation.
- fn build_controller(&mut self, _: &Session, _: &getopts::Matches) -> CompileController<'a>;
+ fn build_controller(
+ self: Box<Self>,
+ _: &Session,
+ _: &getopts::Matches
+ ) -> CompileController<'a>;
}
-// CompilerCalls instance for a regular rustc build.
+/// CompilerCalls instance for a regular rustc build.
#[derive(Copy, Clone)]
pub struct RustcDefaultCalls;
.and_then(|| RustcDefaultCalls::list_metadata(sess, cstore, matches, input))
}
- fn build_controller(&mut self,
+ fn build_controller(self: Box<Self>,
sess: &Session,
matches: &getopts::Matches)
-> CompileController<'a> {
}))
.collect::<Vec<_>>();
run_compiler(&args,
- &mut RustcDefaultCalls,
+ Box::new(RustcDefaultCalls),
None,
None)
});
});
// length of the code to be substituted
- let snippet_len = (span_end_pos - span_start_pos) as isize;
+ let snippet_len = span_end_pos as isize - span_start_pos as isize;
// For multiple substitutions, use the position *after* the previous
// substitutions have happened.
offset += full_sub_len - snippet_len;
};
if let Err(err) = cx.tcx.const_eval(param_env.and(cid)) {
let span = cx.tcx.def_span(def_id);
- let mut diag = cx.struct_span_lint(
- CONST_ERR,
- span,
+ err.report_as_lint(
+ cx.tcx.at(span),
&format!("this {} cannot be used", what),
+ cx.current_lint_root(),
);
- use rustc::middle::const_val::ConstEvalErrDescription;
- match err.description() {
- ConstEvalErrDescription::Simple(message) => {
- diag.span_label(span, message);
- }
- ConstEvalErrDescription::Backtrace(miri, frames) => {
- diag.span_label(span, format!("{}", miri));
- for frame in frames {
- diag.span_label(frame.span, format!("inside call to `{}`", frame.location));
- }
- }
- }
- diag.emit()
}
}
reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
edition: None,
},
+ FutureIncompatibleInfo {
+ id: LintId::of(DUPLICATE_MACRO_EXPORTS),
+ reference: "issue #35896 <https://github.com/rust-lang/rust/issues/35896>",
+ edition: Some(Edition::Edition2018),
+ },
FutureIncompatibleInfo {
id: LintId::of(SAFE_EXTERN_STATICS),
reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>",
graphviz = { path = "../libgraphviz" }
log = "0.4"
log_settings = "0.1.1"
-polonius-engine = "0.4.0"
+polonius-engine = "0.5.0"
rustc = { path = "../librustc" }
rustc_target = { path = "../librustc_target" }
rustc_data_structures = { path = "../librustc_data_structures" }
use rustc::util::nodemap::FxHashMap;
use std::collections::BTreeSet;
use std::fmt::Debug;
+use std::env;
use std::io;
use std::path::PathBuf;
use std::rc::Rc;
+use std::str::FromStr;
use transform::MirSource;
use util::liveness::{LivenessResults, LocalSet};
}
if infcx.tcx.sess.opts.debugging_opts.polonius {
+ let algorithm = env::var("POLONIUS_ALGORITHM")
+ .unwrap_or(String::from("DatafrogOpt"));
+ let algorithm = Algorithm::from_str(&algorithm).unwrap();
+ debug!("compute_regions: using polonius algorithm {:?}", algorithm);
Some(Rc::new(Output::compute(
&all_facts,
- Algorithm::DatafrogOpt,
+ algorithm,
false,
)))
} else {
location, live_local
);
- self.flow_inits.each_state_bit(|mpi_init| {
- debug!(
- "add_liveness_constraints: location={:?} initialized={:?}",
- location,
- &self.flow_inits.operator().move_data().move_paths[mpi_init]
- );
- });
+ if log_enabled!(::log::Level::Debug) {
+ self.flow_inits.each_state_bit(|mpi_init| {
+ debug!(
+ "add_liveness_constraints: location={:?} initialized={:?}",
+ location,
+ &self.flow_inits.operator().move_data().move_paths[mpi_init]
+ );
+ });
+ }
let mpi = self.move_data.rev_lookup.find_local(live_local);
if let Some(initialized_child) = self.flow_inits.has_any_child_of(mpi) {
let count = match cx.tcx.at(span).const_eval(cx.param_env.and(global_id)) {
Ok(cv) => cv.unwrap_usize(cx.tcx),
Err(e) => {
- e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
+ e.report_as_error(cx.tcx.at(span), "could not evaluate array length");
0
},
};
PatternError::FloatBug => {
// FIXME(#31407) this is only necessary because float parsing is buggy
::rustc::middle::const_val::struct_error(
- self.tcx, pat_span,
+ self.tcx.at(pat_span),
"could not evaluate float literal (see issue #31407)",
).emit();
}
PatternError::NonConstPath(span) => {
::rustc::middle::const_val::struct_error(
- self.tcx, span,
+ self.tcx.at(span),
"runtime values cannot be referenced in patterns",
).emit();
}
return self.const_to_pat(instance, value, id, span)
},
Err(err) => {
- err.report(self.tcx, span, "pattern");
+ err.report_as_error(
+ self.tcx.at(span),
+ "could not evaluate constant pattern",
+ );
PatternKind::Wild
},
}
cid: GlobalId<'tcx>,
mir: &'mir mir::Mir<'tcx>,
param_env: ty::ParamEnv<'tcx>,
-) -> Option<(Value, Scalar, Ty<'tcx>)> {
+) -> EvalResult<'tcx, (Value, Scalar, Ty<'tcx>)> {
ecx.with_fresh_body(|ecx| {
- let res = eval_body_using_ecx(ecx, cid, Some(mir), param_env);
- match res {
- Ok(val) => Some(val),
- Err(mut err) => {
- ecx.report(&mut err, false, None);
- None
- }
- }
+ eval_body_using_ecx(ecx, cid, Some(mir), param_env)
})
}
-pub fn eval_body<'a, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- cid: GlobalId<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
-) -> Option<(Value, Scalar, Ty<'tcx>)> {
- let (res, ecx) = eval_body_and_ecx(tcx, cid, None, param_env);
- match res {
- Ok(val) => Some(val),
- Err(mut err) => {
- ecx.report(&mut err, true, None);
- None
- }
- }
-}
-
pub fn value_to_const_value<'tcx>(
ecx: &EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>,
val: Value,
})();
match val {
Ok(val) => ty::Const::from_const_value(ecx.tcx.tcx, val, ty),
- Err(mut err) => {
- ecx.report(&mut err, true, None);
- bug!("miri error occured when converting Value to ConstValue")
+ Err(err) => {
+ let (frames, span) = ecx.generate_stacktrace(None);
+ let err = ConstEvalErr {
+ span,
+ kind: ErrKind::Miri(err, frames).into(),
+ };
+ 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")
}
}
}
val = ecx.try_read_by_ref(val, miri_ty)?;
}
Ok(value_to_const_value(&ecx, val, miri_ty))
- }).map_err(|mut err| {
- if tcx.is_static(def_id).is_some() {
- ecx.report(&mut err, true, None);
- }
+ }).map_err(|err| {
let (trace, span) = ecx.generate_stacktrace(None);
let err = ErrKind::Miri(err, trace);
- ConstEvalErr {
+ let err = ConstEvalErr {
kind: err.into(),
span,
+ };
+ if tcx.is_static(def_id).is_some() {
+ err.report_as_error(ecx.tcx, "could not evaluate static initializer");
}
+ err
})
}
use rustc::hir::def_id::DefId;
use rustc::hir::def::Def;
use rustc::hir::map::definitions::DefPathData;
-use rustc::middle::const_val::{ConstVal, ErrKind};
+use rustc::middle::const_val::ConstVal;
use rustc::mir;
use rustc::ty::layout::{self, Size, Align, HasDataLayout, IntegerExt, LayoutOf, TyLayout};
use rustc::ty::subst::{Subst, Substs};
use syntax::ast::Mutability;
use rustc::mir::interpret::{
GlobalId, Value, Scalar,
- EvalError, EvalResult, EvalErrorKind, Pointer, ConstValue,
+ EvalResult, EvalErrorKind, Pointer, ConstValue,
};
use std::mem;
} else {
self.param_env
};
- self.tcx.const_eval(param_env.and(gid)).map_err(|err| match *err.kind {
- ErrKind::Miri(ref err, _) => match err.kind {
- EvalErrorKind::TypeckError |
- EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
- _ => EvalErrorKind::ReferencedConstant.into(),
- },
- ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
- ref other => bug!("const eval returned {:?}", other),
- })
+ self.tcx.const_eval(param_env.and(gid)).map_err(|err| EvalErrorKind::ReferencedConstant(err).into())
}
pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> {
let mut last_span = None;
let mut frames = Vec::new();
// skip 1 because the last frame is just the environment of the constant
- for &Frame { instance, span, .. } in self.stack().iter().skip(1).rev() {
+ for &Frame { instance, span, mir, block, stmt, .. } in self.stack().iter().skip(1).rev() {
// make sure we don't emit frames that are duplicates of the previous
if explicit_span == Some(span) {
last_span = Some(span);
} else {
instance.to_string()
};
- frames.push(FrameInfo { span, location });
- }
- trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
- (frames, self.tcx.span)
- }
-
- pub fn report(&self, e: &mut EvalError, as_err: bool, explicit_span: Option<Span>) {
- match e.kind {
- EvalErrorKind::Layout(_) |
- EvalErrorKind::TypeckError => return,
- _ => {},
- }
- if let Some(ref mut backtrace) = e.backtrace {
- let mut trace_text = "\n\nAn error occurred in miri:\n".to_string();
- backtrace.resolve();
- write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap();
- 'frames: for (i, frame) in backtrace.frames().iter().enumerate() {
- if frame.symbols().is_empty() {
- write!(trace_text, "{}: no symbols\n", i).unwrap();
- }
- for symbol in frame.symbols() {
- write!(trace_text, "{}: ", i).unwrap();
- if let Some(name) = symbol.name() {
- write!(trace_text, "{}\n", name).unwrap();
- } else {
- write!(trace_text, "<unknown>\n").unwrap();
- }
- write!(trace_text, "\tat ").unwrap();
- if let Some(file_path) = symbol.filename() {
- write!(trace_text, "{}", file_path.display()).unwrap();
- } else {
- write!(trace_text, "<unknown_file>").unwrap();
- }
- if let Some(line) = symbol.lineno() {
- write!(trace_text, ":{}\n", line).unwrap();
- } else {
- write!(trace_text, "\n").unwrap();
- }
- }
- }
- error!("{}", trace_text);
- }
- if let Some(frame) = self.stack().last() {
- let block = &frame.mir.basic_blocks()[frame.block];
- let span = explicit_span.unwrap_or_else(|| if frame.stmt < block.statements.len() {
- block.statements[frame.stmt].source_info.span
- } else {
- block.terminator().source_info.span
- });
- trace!("reporting const eval failure at {:?}", span);
- let mut err = if as_err {
- ::rustc::middle::const_val::struct_error(*self.tcx, span, "constant evaluation error")
+ let block = &mir.basic_blocks()[block];
+ let source_info = if stmt < block.statements.len() {
+ block.statements[stmt].source_info
} else {
- let node_id = self
- .stack()
- .iter()
- .rev()
- .filter_map(|frame| self.tcx.hir.as_local_node_id(frame.instance.def_id()))
- .next()
- .expect("some part of a failing const eval must be local");
- self.tcx.struct_span_lint_node(
- ::rustc::lint::builtin::CONST_ERR,
- node_id,
- span,
- "constant evaluation error",
- )
+ block.terminator().source_info
};
- let (frames, span) = self.generate_stacktrace(explicit_span);
- err.span_label(span, e.to_string());
- for FrameInfo { span, location } in frames {
- err.span_note(span, &format!("inside call to `{}`", location));
- }
- err.emit();
- } else {
- self.tcx.sess.err(&e.to_string());
+ let lint_root = match mir.source_scope_local_data {
+ mir::ClearCrossCrate::Set(ref ivs) => Some(ivs[source_info.scope].lint_root),
+ mir::ClearCrossCrate::Clear => None,
+ };
+ frames.push(FrameInfo { span, location, lint_root });
}
+ trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
+ (frames, self.tcx.span)
}
pub fn sign_extend(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
use rustc::ty::maps::TyCtxtAt;
use rustc::ty::layout::{self, Align, TargetDataLayout, Size};
use syntax::ast::Mutability;
-use rustc::middle::const_val::{ConstVal, ErrKind};
+use rustc::middle::const_val::ConstVal;
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use rustc::mir::interpret::{Pointer, AllocId, Allocation, AccessKind, Value,
instance,
promoted: None,
};
- self.tcx.const_eval(ParamEnv::reveal_all().and(gid)).map_err(|err| {
- match *err.kind {
- ErrKind::Miri(ref err, _) => match err.kind {
- EvalErrorKind::TypeckError |
- EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
- _ => EvalErrorKind::ReferencedConstant.into(),
- },
- ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
- ref other => bug!("const eval returned {:?}", other),
- }
+ self.tcx.const_eval(ParamEnv::reveal_all().and(gid)).map_err(|_| {
+ // no need to report anything, the const_eval call takes care of that for statics
+ assert!(self.tcx.is_static(def_id).is_some());
+ EvalErrorKind::TypeckError.into()
}).map(|val| {
let const_val = match val.val {
ConstVal::Value(val) => val,
pub use self::const_eval::{
eval_promoted,
mk_borrowck_eval_cx,
- eval_body,
CompileTimeEvaluator,
const_value_to_allocation_provider,
const_eval_provider,
variant: Option<usize>,
field: mir::Field,
base_ty: Ty<'tcx>,
- ) -> EvalResult<'tcx, Option<(Value, Ty<'tcx>)>> {
+ ) -> EvalResult<'tcx, ValTy<'tcx>> {
let mut base_layout = self.layout_of(base_ty)?;
if let Some(variant_index) = variant {
base_layout = base_layout.for_variant(self, variant_index);
let field_index = field.index();
let field = base_layout.field(self, field_index)?;
if field.size.bytes() == 0 {
- return Ok(Some((Value::Scalar(Scalar::undef()), field.ty)))
+ return Ok(ValTy {
+ value: Value::Scalar(Scalar::undef()),
+ ty: field.ty,
+ });
}
let offset = base_layout.fields.offset(field_index);
- match base {
+ let value = match base {
// the field covers the entire type
Value::ScalarPair(..) |
- Value::Scalar(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some((base, field.ty))),
- // split fat pointers, 2 element tuples, ...
- Value::ScalarPair(a, b) if base_layout.fields.count() == 2 => {
- let val = [a, b][field_index];
- Ok(Some((Value::Scalar(val), field.ty)))
+ Value::Scalar(_) if offset.bytes() == 0 && field.size == base_layout.size => base,
+ // extract fields from types with `ScalarPair` ABI
+ Value::ScalarPair(a, b) => {
+ let val = if offset.bytes() == 0 { a } else { b };
+ Value::Scalar(val)
},
- // FIXME(oli-obk): figure out whether we should be calling `try_read_value` here
- _ => Ok(None),
- }
+ Value::ByRef(base_ptr, align) => {
+ let offset = base_layout.fields.offset(field_index);
+ let ptr = base_ptr.ptr_offset(offset, self)?;
+ let align = align.min(base_layout.align).min(field.align);
+ assert!(!field.is_unsized());
+ Value::ByRef(ptr, align)
+ },
+ Value::Scalar(val) => bug!("field access on non aggregate {:?}, {:?}", val, base_ty),
+ };
+ Ok(ValTy {
+ value,
+ ty: field.ty,
+ })
}
fn try_read_place_projection(
};
let base_ty = self.place_ty(&proj.base);
match proj.elem {
- Field(field, _) => Ok(self.read_field(base, None, field, base_ty)?.map(|(f, _)| f)),
+ Field(field, _) => Ok(Some(self.read_field(base, None, field, base_ty)?.value)),
// The NullablePointer cases should work fine, need to take care for normal enums
Downcast(..) |
Subslice { .. } |
use syntax::codemap::Span;
use rustc_target::spec::abi::Abi;
-use rustc::mir::interpret::{EvalResult, Scalar, Value};
+use rustc::mir::interpret::EvalResult;
use super::{EvalContext, Place, Machine, ValTy};
use rustc_data_structures::indexed_vec::Idx;
// unpack and write all other args
let layout = self.layout_of(args[1].ty)?;
- if let ty::TyTuple(..) = args[1].ty.sty {
+ if let ty::TyTuple(_) = args[1].ty.sty {
+ if layout.is_zst() {
+ // Nothing to do, no need to unpack zsts
+ return Ok(());
+ }
if self.frame().mir.args_iter().count() == layout.fields.count() + 1 {
- match args[1].value {
- Value::ByRef(ptr, align) => {
- for (i, arg_local) in arg_locals.enumerate() {
- let field = layout.field(&self, i)?;
- let offset = layout.fields.offset(i);
- let arg = Value::ByRef(ptr.ptr_offset(offset, &self)?,
- align.min(field.align));
- let dest =
- self.eval_place(&mir::Place::Local(arg_local))?;
- trace!(
- "writing arg {:?} to {:?} (type: {})",
- arg,
- dest,
- field.ty
- );
- let valty = ValTy {
- value: arg,
- ty: field.ty,
- };
- self.write_value(valty, dest)?;
- }
- }
- Value::Scalar(Scalar::Bits { defined: 0, .. }) => {}
- other => {
- trace!("{:#?}, {:#?}", other, layout);
- let mut layout = layout;
- 'outer: loop {
- for i in 0..layout.fields.count() {
- let field = layout.field(&self, i)?;
- if layout.fields.offset(i).bytes() == 0 && layout.size == field.size {
- layout = field;
- continue 'outer;
- }
- }
- break;
- }
- {
- let mut write_next = |value| {
- let dest = self.eval_place(&mir::Place::Local(
- arg_locals.next().unwrap(),
- ))?;
- let valty = ValTy {
- value: Value::Scalar(value),
- ty: layout.ty,
- };
- self.write_value(valty, dest)
- };
- match other {
- Value::Scalar(value) | Value::ScalarPair(value, _) => write_next(value)?,
- _ => unreachable!(),
- }
- if let Value::ScalarPair(_, value) = other {
- write_next(value)?;
- }
- }
- assert!(arg_locals.next().is_none());
- }
+ for (i, arg_local) in arg_locals.enumerate() {
+ let field = mir::Field::new(i);
+ let valty = self.read_field(args[1].value, None, field, args[1].ty)?;
+ let dest = self.eval_place(&mir::Place::Local(arg_local))?;
+ self.write_value(valty, dest)?;
}
} else {
trace!("manual impl of rust-call ABI");
Ok(val) => collect_const(tcx, val, instance.substs, &mut neighbors),
Err(err) => {
let span = tcx.def_span(def_id);
- err.report(tcx, span, "static");
+ err.report_as_error(
+ tcx.at(span),
+ "could not evaluate static initializer",
+ );
}
}
}
let param_env = ty::ParamEnv::reveal_all();
for i in 0..mir.promoted.len() {
use rustc_data_structures::indexed_vec::Idx;
+ let i = Promoted::new(i);
let cid = GlobalId {
instance,
- promoted: Some(Promoted::new(i)),
+ promoted: Some(i),
};
match tcx.const_eval(param_env.and(cid)) {
Ok(val) => collect_const(tcx, val, instance.substs, output),
- Err(_) => {},
+ Err(err) => {
+ use rustc::middle::const_val::ErrKind;
+ use rustc::mir::interpret::EvalErrorKind;
+ if let ErrKind::Miri(ref miri, ..) = *err.kind {
+ if let EvalErrorKind::ReferencedConstant(_) = miri.kind {
+ err.report_as_error(
+ tcx.at(mir.promoted[i].span),
+ "erroneous constant used",
+ );
+ }
+ }
+ },
}
}
}
Ok(val) => val.val,
Err(err) => {
let span = tcx.def_span(def_id);
- err.report(tcx, span, "constant");
+ err.report_as_error(
+ tcx.at(span),
+ "constant evaluation error",
+ );
return;
}
}
use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind};
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
use rustc::mir::visit::{Visitor, PlaceContext};
-use rustc::middle::const_val::ConstVal;
+use rustc::middle::const_val::{ConstVal, ConstEvalErr, ErrKind};
use rustc::ty::{TyCtxt, self, Instance};
use rustc::mir::interpret::{Value, Scalar, GlobalId, EvalResult};
use interpret::EvalContext;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::ty::ParamEnv;
use rustc::ty::layout::{
- LayoutOf, TyLayout, LayoutError, LayoutCx,
+ LayoutOf, TyLayout, LayoutError,
HasTyCtxt, TargetDataLayout, HasDataLayout,
};
fn use_ecx<F, T>(
&mut self,
- span: Span,
+ source_info: SourceInfo,
f: F
) -> Option<T>
where
F: FnOnce(&mut Self) -> EvalResult<'tcx, T>,
{
- self.ecx.tcx.span = span;
+ self.ecx.tcx.span = source_info.span;
+ let lint_root = match self.mir.source_scope_local_data {
+ ClearCrossCrate::Set(ref ivs) => {
+ use rustc_data_structures::indexed_vec::Idx;
+ //FIXME(#51314): remove this check
+ if source_info.scope.index() >= ivs.len() {
+ return None;
+ }
+ ivs[source_info.scope].lint_root
+ },
+ ClearCrossCrate::Clear => return None,
+ };
let r = match f(self) {
Ok(val) => Some(val),
- Err(mut err) => {
- self.ecx.report(&mut err, false, Some(span));
+ Err(err) => {
+ let (frames, span) = self.ecx.generate_stacktrace(None);
+ let err = ConstEvalErr {
+ span,
+ kind: ErrKind::Miri(err, frames).into(),
+ };
+ err.report_as_lint(
+ self.ecx.tcx,
+ "this expression will panic at runtime",
+ lint_root,
+ );
None
},
};
r
}
- fn const_eval(&mut self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
+ fn const_eval(&mut self, cid: GlobalId<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
let value = match self.tcx.const_eval(self.param_env.and(cid)) {
Ok(val) => val,
Err(err) => {
- err.report(self.tcx, err.span, "constant propagated");
+ err.report_as_error(
+ self.tcx.at(err.span),
+ "constant evaluation error",
+ );
return None;
},
};
let val = match value.val {
ConstVal::Value(v) => {
- self.use_ecx(span, |this| this.ecx.const_value_to_value(v, value.ty))?
+ self.use_ecx(source_info, |this| this.ecx.const_value_to_value(v, value.ty))?
},
_ => bug!("eval produced: {:?}", value),
};
- let val = (val, value.ty, span);
+ let val = (val, value.ty, source_info.span);
trace!("evaluated {:?} to {:?}", cid, val);
Some(val)
}
- fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
+ fn eval_constant(
+ &mut self,
+ c: &Constant<'tcx>,
+ source_info: SourceInfo,
+ ) -> Option<Const<'tcx>> {
match c.literal {
Literal::Value { value } => match value.val {
ConstVal::Value(v) => {
- let v = self.use_ecx(c.span, |this| {
+ let v = self.use_ecx(source_info, |this| {
this.ecx.const_value_to_value(v, value.ty)
})?;
Some((v, value.ty, c.span))
instance,
promoted: None,
};
- self.const_eval(cid, c.span)
+ self.const_eval(cid, source_info)
},
},
// evaluate the promoted and replace the constant with the evaluated result
};
// cannot use `const_eval` here, because that would require having the MIR
// for the current function available, but we're producing said MIR right now
- let span = self.mir.span;
- let (value, _, ty) = self.use_ecx(span, |this| {
- Ok(eval_promoted(&mut this.ecx, cid, this.mir, this.param_env))
- })??;
+ let (value, _, ty) = self.use_ecx(source_info, |this| {
+ eval_promoted(&mut this.ecx, cid, this.mir, this.param_env)
+ })?;
let val = (value, ty, c.span);
trace!("evaluated {:?} to {:?}", c, val);
Some(val)
}
}
- fn eval_place(&mut self, place: &Place<'tcx>) -> Option<Const<'tcx>> {
+ fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
match *place {
Place::Local(loc) => self.places[loc].clone(),
Place::Projection(ref proj) => match proj.elem {
ProjectionElem::Field(field, _) => {
trace!("field proj on {:?}", proj.base);
- let (base, ty, span) = self.eval_place(&proj.base)?;
- match base {
- Value::ScalarPair(a, b) => {
- trace!("by val pair: {:?}, {:?}", a, b);
- let base_layout = self.tcx.layout_of(self.param_env.and(ty)).ok()?;
- trace!("layout computed");
- use rustc_data_structures::indexed_vec::Idx;
- let field_index = field.index();
- let val = [a, b][field_index];
- let cx = LayoutCx {
- tcx: self.tcx,
- param_env: self.param_env,
- };
- let field = base_layout.field(cx, field_index).ok()?;
- trace!("projection resulted in: {:?}", val);
- Some((Value::Scalar(val), field.ty, span))
- },
- _ => None,
- }
+ let (base, ty, span) = self.eval_place(&proj.base, source_info)?;
+ let valty = self.use_ecx(source_info, |this| {
+ this.ecx.read_field(base, None, field, ty)
+ })?;
+ Some((valty.value, valty.ty, span))
},
_ => None,
},
}
}
- fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option<Const<'tcx>> {
+ fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
match *op {
- Operand::Constant(ref c) => self.eval_constant(c),
- Operand::Move(ref place) | Operand::Copy(ref place) => self.eval_place(place),
+ Operand::Constant(ref c) => self.eval_constant(c, source_info),
+ | Operand::Move(ref place)
+ | Operand::Copy(ref place) => self.eval_place(place, source_info),
}
}
) -> Option<Const<'tcx>> {
let span = source_info.span;
match *rvalue {
- // No need to overwrite an already evaluated constant
- Rvalue::Use(Operand::Constant(box Constant {
- literal: Literal::Value {
- value: &ty::Const {
- val: ConstVal::Value(_),
- ..
- },
- },
- ..
- })) => None,
// This branch exists for the sanity type check
Rvalue::Use(Operand::Constant(ref c)) => {
assert_eq!(c.ty, place_ty);
- self.eval_constant(c)
+ self.eval_constant(c, source_info)
},
Rvalue::Use(ref op) => {
- self.eval_operand(op)
+ self.eval_operand(op, source_info)
},
Rvalue::Repeat(..) |
Rvalue::Ref(..) |
return None;
}
- let val = self.eval_operand(arg)?;
- let prim = self.use_ecx(span, |this| {
+ let val = self.eval_operand(arg, source_info)?;
+ let prim = self.use_ecx(source_info, |this| {
this.ecx.value_to_scalar(ValTy { value: val.0, ty: val.1 })
})?;
- let val = self.use_ecx(span, |this| this.ecx.unary_op(op, prim, val.1))?;
+ let val = self.use_ecx(source_info, |this| this.ecx.unary_op(op, prim, val.1))?;
Some((Value::Scalar(val), place_ty, span))
}
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
Rvalue::BinaryOp(op, ref left, ref right) => {
trace!("rvalue binop {:?} for {:?} and {:?}", op, left, right);
- let right = self.eval_operand(right)?;
+ let right = self.eval_operand(right, source_info)?;
let def_id = if self.tcx.is_closure(self.source.def_id) {
self.tcx.closure_base_def_id(self.source.def_id)
} else {
return None;
}
- let r = self.use_ecx(span, |this| {
+ let r = self.use_ecx(source_info, |this| {
this.ecx.value_to_scalar(ValTy { value: right.0, ty: right.1 })
})?;
if op == BinOp::Shr || op == BinOp::Shl {
return None;
}
}
- let left = self.eval_operand(left)?;
- let l = self.use_ecx(span, |this| {
+ let left = self.eval_operand(left, source_info)?;
+ let l = self.use_ecx(source_info, |this| {
this.ecx.value_to_scalar(ValTy { value: left.0, ty: left.1 })
})?;
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
- let (val, overflow) = self.use_ecx(span, |this| {
+ let (val, overflow) = self.use_ecx(source_info, |this| {
this.ecx.binary_op(op, l, left.1, r, right.1)
})?;
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
} else {
if overflow {
use rustc::mir::interpret::EvalErrorKind;
- let mut err = EvalErrorKind::Overflow(op).into();
- self.use_ecx(span, |this| {
- this.ecx.report(&mut err, false, Some(span));
- Ok(())
- });
+ let err = EvalErrorKind::Overflow(op).into();
+ let _: Option<()> = self.use_ecx(source_info, |_| Err(err));
return None;
}
Value::Scalar(val)
) {
trace!("visit_constant: {:?}", constant);
self.super_constant(constant, location);
- self.eval_constant(constant);
+ let source_info = *self.mir.source_info(location);
+ self.eval_constant(constant, source_info);
}
fn visit_statement(
location: Location,
) {
self.super_terminator_kind(block, kind, location);
+ let source_info = *self.mir.source_info(location);
if let TerminatorKind::Assert { expected, msg, cond, .. } = kind {
- if let Some(value) = self.eval_operand(cond) {
+ 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 {
// poison all places this operand references so that further code
DivisionByZero |
RemainderByZero => msg.description().to_owned(),
BoundsCheck { ref len, ref index } => {
- let len = self.eval_operand(len).expect("len must be const");
+ let len = self
+ .eval_operand(len, source_info)
+ .expect("len must be const");
let len = match len.0 {
Value::Scalar(Scalar::Bits { bits, ..}) => bits,
_ => bug!("const len not primitive: {:?}", len),
};
let index = self
- .eval_operand(index)
+ .eval_operand(index, source_info)
.expect("index must be const");
let index = match index.0 {
Value::Scalar(Scalar::Bits { bits, .. }) => bits,
here due to private fields"));
}
} else {
- err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
- path_str));
+ // HACK(estebank): find a better way to figure out that this was a
+ // parser issue where a struct literal is being used on an expression
+ // where a brace being opened means a block is being started. Look
+ // ahead for the next text to see if `span` is followed by a `{`.
+ let cm = this.session.codemap();
+ let mut sp = span;
+ loop {
+ sp = cm.next_point(sp);
+ match cm.span_to_snippet(sp) {
+ Ok(ref snippet) => {
+ if snippet.chars().any(|c| { !c.is_whitespace() }) {
+ break;
+ }
+ }
+ _ => break,
+ }
+ }
+ let followed_by_brace = match cm.span_to_snippet(sp) {
+ Ok(ref snippet) if snippet == "{" => true,
+ _ => false,
+ };
+ if let (PathSource::Expr(None), true) = (source, followed_by_brace) {
+ err.span_label(
+ span,
+ format!("did you mean `({} {{ /* fields */ }})`?", path_str),
+ );
+ } else {
+ err.span_label(
+ span,
+ format!("did you mean `{} {{ /* fields */ }}`?", path_str),
+ );
+ }
}
return (err, candidates);
}
use {resolve_error, ResolutionError};
use rustc::ty;
-use rustc::lint::builtin::PUB_USE_OF_PRIVATE_EXTERN_CRATE;
+use rustc::lint::builtin::BuiltinLintDiagnostics;
+use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE};
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::hir::def::*;
use rustc::session::DiagnosticMessageId;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use syntax::ast::{Ident, Name, NodeId};
+use syntax::ast::{Ident, Name, NodeId, CRATE_NODE_ID};
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::hygiene::Mark;
use syntax::symbol::keywords;
if module as *const _ == self.graph_root as *const _ {
let macro_exports = mem::replace(&mut self.macro_exports, Vec::new());
for export in macro_exports.into_iter().rev() {
- if exported_macro_names.insert(export.ident.modern(), export.span).is_none() {
+ if let Some(later_span) = exported_macro_names.insert(export.ident.modern(),
+ export.span) {
+ self.session.buffer_lint_with_diagnostic(
+ DUPLICATE_MACRO_EXPORTS,
+ CRATE_NODE_ID,
+ later_span,
+ &format!("a macro named `{}` has already been exported", export.ident),
+ BuiltinLintDiagnostics::DuplicatedMacroExports(
+ export.ident, export.span, later_span));
+ } else {
reexports.push(export);
}
}
log = "0.4"
syntax = { path = "../libsyntax" }
arena = { path = "../libarena" }
-fmt_macros = { path = "../libfmt_macros" }
rustc = { path = "../librustc" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
use util::nodemap::{FxHashSet, FxHashMap};
use errors::FatalError;
+// use std::cmp::Ordering;
use std::iter;
use syntax::ast;
use syntax::feature_gate::{GateIssue, emit_feature_err};
&mut vec![]);
}
- let (auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]);
+ let (mut auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]);
if !trait_bounds.is_empty() {
let b = &trait_bounds[0];
.emit();
}
+ // Dedup auto traits so that `dyn Trait + Send + Send` is the same as `dyn Trait + Send`.
+ auto_traits.sort();
+ auto_traits.dedup();
+
// skip_binder is okay, because the predicates are re-bound.
let mut v =
iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder()))
}
}
-/// Divides a list of general trait bounds into two groups: builtin bounds (Sync/Send) and the
+/// Divides a list of general trait bounds into two groups: auto traits (e.g. Sync and Send) and the
/// remaining general trait bounds.
fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
trait_bounds: &'b [hir::PolyTraitRef])
// Check that a function marked as `#[panic_implementation]` has signature `fn(&PanicInfo) -> !`
if let Some(panic_impl_did) = fcx.tcx.lang_items().panic_impl() {
- if panic_impl_did == fn_hir_id.owner_def_id() {
+ if panic_impl_did == fcx.tcx.hir.local_def_id(fn_id) {
if let Some(panic_info_did) = fcx.tcx.lang_items().panic_info() {
if declared_ret_ty.sty != ty::TyNever {
fcx.tcx.sess.span_err(
let count = tcx.const_eval(param_env.and(global_id));
if let Err(ref err) = count {
- err.report(tcx, tcx.def_span(count_def_id), "constant expression");
+ err.report_as_error(
+ tcx.at(tcx.def_span(count_def_id)),
+ "could not evaluate repeat length",
+ );
}
let uty = match expected {
use syntax::codemap::{dummy_spanned, Spanned};
use syntax::feature_gate::UnstableFeatures;
use syntax::ptr::P;
-use syntax::symbol::keywords;
+use syntax::symbol::keywords::{self, Keyword};
use syntax::symbol::{Symbol, InternedString};
use syntax_pos::{self, DUMMY_SP, Pos, FileName};
use std::iter::{FromIterator, once};
use rustc_data_structures::sync::Lrc;
use std::rc::Rc;
+use std::str::FromStr;
use std::cell::RefCell;
use std::sync::Arc;
use std::u32;
_ => unreachable!(),
}
- let ExternalCrate { name, src, primitives, .. } = LOCAL_CRATE.clean(cx);
+ let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx);
{
let m = match module.inner {
ModuleItem(ref mut m) => m,
inner: PrimitiveItem(prim),
}
}));
+ m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| {
+ Item {
+ source: Span::empty(),
+ name: Some(kw.clone()),
+ attrs: attrs,
+ visibility: Some(Public),
+ stability: get_stability(cx, def_id),
+ deprecation: get_deprecation(cx, def_id),
+ def_id,
+ inner: KeywordItem(kw),
+ }
+ }));
}
let mut access_levels = cx.access_levels.borrow_mut();
pub src: FileName,
pub attrs: Attributes,
pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
+ pub keywords: Vec<(DefId, String, Attributes)>,
}
impl Clean<ExternalCrate> for CrateNum {
.filter_map(as_primitive).collect()
};
+ let as_keyword = |def: Def| {
+ if let Def::Mod(def_id) = def {
+ let attrs = cx.tcx.get_attrs(def_id).clean(cx);
+ let mut keyword = None;
+ for attr in attrs.lists("doc") {
+ if let Some(v) = attr.value_str() {
+ if attr.check_name("keyword") {
+ keyword = Keyword::from_str(&v.as_str()).ok()
+ .map(|x| x.name().to_string());
+ if keyword.is_some() {
+ break
+ }
+ // FIXME: should warn on unknown keywords?
+ }
+ }
+ }
+ return keyword.map(|p| (def_id, p, attrs));
+ }
+ None
+ };
+ let keywords = if root.is_local() {
+ cx.tcx.hir.krate().module.item_ids.iter().filter_map(|&id| {
+ let item = cx.tcx.hir.expect_item(id.id);
+ match item.node {
+ hir::ItemMod(_) => {
+ as_keyword(Def::Mod(cx.tcx.hir.local_def_id(id.id)))
+ }
+ hir::ItemUse(ref path, hir::UseKind::Single)
+ if item.vis == hir::Visibility::Public => {
+ as_keyword(path.def).map(|(_, prim, attrs)| {
+ (cx.tcx.hir.local_def_id(id.id), prim, attrs)
+ })
+ }
+ _ => None
+ }
+ }).collect()
+ } else {
+ cx.tcx.item_children(root).iter().map(|item| item.def)
+ .filter_map(as_keyword).collect()
+ };
+
ExternalCrate {
name: cx.tcx.crate_name(*self).to_string(),
src: krate_src,
attrs: cx.tcx.get_attrs(root).clean(cx),
primitives,
+ keywords,
}
}
}
pub fn is_extern_crate(&self) -> bool {
self.type_() == ItemType::ExternCrate
}
+ pub fn is_keyword(&self) -> bool {
+ self.type_() == ItemType::Keyword
+ }
pub fn is_stripped(&self) -> bool {
match self.inner { StrippedItem(..) => true, _ => false }
AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
/// An item that has been stripped by a rustdoc pass
StrippedItem(Box<ItemEnum>),
+ KeywordItem(String),
}
impl ItemEnum {
link_range: Option<Range<usize>>,
) {
let sp = span_of_attrs(attrs);
- let mut diag = cx.sess()
- .struct_span_warn(sp, &format!("[{}] cannot be resolved, ignoring it...", path_str));
+ let msg = format!("`[{}]` cannot be resolved, ignoring it...", path_str);
+
+ let code_dox = sp.to_src(cx);
- if let Some(link_range) = link_range {
+ 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 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(),
- ));
- } else {
+ 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.sess().struct_span_warn(sp, &msg);
+ diag.span_label(sp, "cannot be resolved, ignoring");
+ } else {
+ diag = cx.sess().struct_span_warn(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.sess().struct_span_warn(sp, &msg)
+ };
diag.emit();
}
let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
- let name = ::rustc_codegen_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
+ let name = match crate_name {
+ Some(ref crate_name) => crate_name.clone(),
+ None => ::rustc_codegen_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input),
+ };
let mut crate_loader = CrateLoader::new(&sess, &cstore, &name);
AssociatedConst = 18,
Union = 19,
ForeignType = 20,
+ Keyword = 21,
}
Type,
Value,
Macro,
+ Keyword,
}
impl<'a> From<&'a clean::Item> for ItemType {
clean::AssociatedConstItem(..) => ItemType::AssociatedConst,
clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
clean::ForeignTypeItem => ItemType::ForeignType,
+ clean::KeywordItem(..) => ItemType::Keyword,
clean::StrippedItem(..) => unreachable!(),
}
}
ItemType::Constant => "constant",
ItemType::AssociatedConst => "associatedconstant",
ItemType::ForeignType => "foreigntype",
+ ItemType::Keyword => "keyword",
}
}
ItemType::AssociatedConst => NameSpace::Value,
ItemType::Macro => NameSpace::Macro,
+
+ ItemType::Keyword => NameSpace::Keyword,
}
}
}
pub const NAMESPACE_TYPE: &'static str = "t";
pub const NAMESPACE_VALUE: &'static str = "v";
pub const NAMESPACE_MACRO: &'static str = "m";
+pub const NAMESPACE_KEYWORD: &'static str = "k";
impl NameSpace {
pub fn to_static_str(&self) -> &'static str {
NameSpace::Type => NAMESPACE_TYPE,
NameSpace::Value => NAMESPACE_VALUE,
NameSpace::Macro => NAMESPACE_MACRO,
+ NameSpace::Keyword => NAMESPACE_KEYWORD,
}
}
}
typedefs: HashSet<ItemEntry>,
statics: HashSet<ItemEntry>,
constants: HashSet<ItemEntry>,
+ keywords: HashSet<ItemEntry>,
}
impl AllTypes {
typedefs: HashSet::with_capacity(100),
statics: HashSet::with_capacity(100),
constants: HashSet::with_capacity(100),
+ keywords: HashSet::with_capacity(100),
}
}
clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?,
clean::ConstantItem(..) => write!(fmt, "Constant ")?,
clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?,
+ clean::KeywordItem(..) => write!(fmt, "Keyword ")?,
_ => {
// We don't generate pages for any other type.
unreachable!();
}
}
- if !self.item.is_primitive() {
+ if !self.item.is_primitive() && !self.item.is_keyword() {
let cur = &self.cx.current;
let amt = if self.item.is_mod() { cur.len() - 1 } else { cur.len() };
for (i, component) in cur.iter().enumerate().take(amt) {
item_static(fmt, self.cx, self.item, i),
clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c),
clean::ForeignTypeItem => item_foreign_type(fmt, self.cx, self.item),
+ clean::KeywordItem(ref k) => item_keyword(fmt, self.cx, self.item, k),
_ => {
// We don't generate pages for any other type.
unreachable!();
write!(w, "</table>")?;
}
curty = myty;
- let (short, name) = match myty.unwrap() {
- ItemType::ExternCrate |
- ItemType::Import => ("reexports", "Re-exports"),
- ItemType::Module => ("modules", "Modules"),
- ItemType::Struct => ("structs", "Structs"),
- ItemType::Union => ("unions", "Unions"),
- ItemType::Enum => ("enums", "Enums"),
- ItemType::Function => ("functions", "Functions"),
- ItemType::Typedef => ("types", "Type Definitions"),
- ItemType::Static => ("statics", "Statics"),
- ItemType::Constant => ("constants", "Constants"),
- ItemType::Trait => ("traits", "Traits"),
- ItemType::Impl => ("impls", "Implementations"),
- ItemType::TyMethod => ("tymethods", "Type Methods"),
- ItemType::Method => ("methods", "Methods"),
- ItemType::StructField => ("fields", "Struct Fields"),
- ItemType::Variant => ("variants", "Variants"),
- ItemType::Macro => ("macros", "Macros"),
- ItemType::Primitive => ("primitives", "Primitive Types"),
- ItemType::AssociatedType => ("associated-types", "Associated Types"),
- ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
- ItemType::ForeignType => ("foreign-types", "Foreign Types"),
- };
+ 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)?;
Ok(())
}
+fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
+ match *ty {
+ ItemType::ExternCrate |
+ ItemType::Import => ("reexports", "Re-exports"),
+ ItemType::Module => ("modules", "Modules"),
+ ItemType::Struct => ("structs", "Structs"),
+ ItemType::Union => ("unions", "Unions"),
+ ItemType::Enum => ("enums", "Enums"),
+ ItemType::Function => ("functions", "Functions"),
+ ItemType::Typedef => ("types", "Type Definitions"),
+ ItemType::Static => ("statics", "Statics"),
+ ItemType::Constant => ("constants", "Constants"),
+ ItemType::Trait => ("traits", "Traits"),
+ ItemType::Impl => ("impls", "Implementations"),
+ ItemType::TyMethod => ("tymethods", "Type Methods"),
+ ItemType::Method => ("methods", "Methods"),
+ ItemType::StructField => ("fields", "Struct Fields"),
+ ItemType::Variant => ("variants", "Variants"),
+ ItemType::Macro => ("macros", "Macros"),
+ ItemType::Primitive => ("primitives", "Primitive Types"),
+ ItemType::AssociatedType => ("associated-types", "Associated Types"),
+ ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
+ ItemType::ForeignType => ("foreign-types", "Foreign Types"),
+ ItemType::Keyword => ("keywords", "Keywords"),
+ }
+}
+
fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
items: &[clean::Item]) -> fmt::Result {
let mut sidebar = String::new();
ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant,
ItemType::AssociatedType, ItemType::AssociatedConst, ItemType::ForeignType] {
if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) {
- let (short, name) = match myty {
- ItemType::ExternCrate |
- ItemType::Import => ("reexports", "Re-exports"),
- ItemType::Module => ("modules", "Modules"),
- ItemType::Struct => ("structs", "Structs"),
- ItemType::Union => ("unions", "Unions"),
- ItemType::Enum => ("enums", "Enums"),
- ItemType::Function => ("functions", "Functions"),
- ItemType::Typedef => ("types", "Type Definitions"),
- ItemType::Static => ("statics", "Statics"),
- ItemType::Constant => ("constants", "Constants"),
- ItemType::Trait => ("traits", "Traits"),
- ItemType::Impl => ("impls", "Implementations"),
- ItemType::TyMethod => ("tymethods", "Type Methods"),
- ItemType::Method => ("methods", "Methods"),
- ItemType::StructField => ("fields", "Struct Fields"),
- ItemType::Variant => ("variants", "Variants"),
- ItemType::Macro => ("macros", "Macros"),
- ItemType::Primitive => ("primitives", "Primitive Types"),
- ItemType::AssociatedType => ("associated-types", "Associated Types"),
- ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
- ItemType::ForeignType => ("foreign-types", "Foreign Types"),
- };
+ let (short, name) = item_ty_to_strs(&myty);
sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
id = short,
name = name));
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}
+fn item_keyword(w: &mut fmt::Formatter, cx: &Context,
+ it: &clean::Item,
+ _p: &str) -> fmt::Result {
+ document(w, cx, it)
+}
+
const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang";
fn make_item_keywords(it: &clean::Item) -> String {
"constant",
"associatedconstant",
"union",
- "foreigntype"];
+ "foreigntype",
+ "keyword"];
var search_input = document.getElementsByClassName('search-input')[0];
// used for special search precedence
var TY_PRIMITIVE = itemTypes.indexOf("primitive");
+ var TY_KEYWORD = itemTypes.indexOf("keyword");
onEach(document.getElementsByClassName('js-only'), function(e) {
removeClass(e, 'js-only');
b = bbb.index;
if (a !== b) { return a - b; }
- // special precedence for primitive pages
- if ((aaa.item.ty === TY_PRIMITIVE) && (bbb.item.ty !== TY_PRIMITIVE)) {
+ // special precedence for primitive and keyword pages
+ if ((aaa.item.ty === TY_PRIMITIVE && bbb.item.ty !== TY_KEYWORD) ||
+ (aaa.item.ty === TY_KEYWORD && bbb.item.ty !== TY_PRIMITIVE)) {
return -1;
}
- if ((bbb.item.ty === TY_PRIMITIVE) && (aaa.item.ty !== TY_PRIMITIVE)) {
+ if ((bbb.item.ty === TY_PRIMITIVE && aaa.item.ty !== TY_PRIMITIVE) ||
+ (bbb.item.ty === TY_KEYWORD && aaa.item.ty !== TY_KEYWORD)) {
return 1;
}
displayPath = item.path + '::';
href = rootPath + item.path.replace(/::/g, '/') + '/' +
name + '/index.html';
- } else if (type === "primitive") {
+ } else if (type === "primitive" || type === "keyword") {
displayPath = "";
href = rootPath + item.path.replace(/::/g, '/') +
'/' + type + '.' + name + '.html';
block("fn", "Functions");
block("type", "Type Definitions");
block("foreigntype", "Foreign Types");
+ block("keyword", "Keywords");
}
window.initSidebarItems = initSidebarItems;
font-style: italic;
}
+tr.result span.keyword::after {
+ content: ' (keyword)';
+ font-style: italic;
+}
+
body.blur > :not(#help) {
filter: blur(8px);
-webkit-filter: blur(8px);
.content .highlighted.constant,
.content .highlighted.static { background-color: #0063cc; }
.content .highlighted.primitive { background-color: #00708a; }
+.content .highlighted.keyword { background-color: #884719; }
.content span.enum, .content a.enum, .block a.current.enum { color: #82b089; }
.content span.struct, .content a.struct, .block a.current.struct { color: #2dbfb8; }
.content span.method, .content a.method, .block a.current.method,
.content span.tymethod, .content a.tymethod, .block a.current.tymethod,
.content .fnname{ color: #2BAB63; }
+.content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; }
pre.rust .comment { color: #8d8d8b; }
pre.rust .doccomment { color: #8ca375; }
color: grey;
}
-tr.result span.primitive::after {
+tr.result span.primitive::after, tr.result span.keyword::after {
color: #ddd;
}
.content .highlighted.constant,
.content .highlighted.static { background-color: #c3e0ff; }
.content .highlighted.primitive { background-color: #9aecff; }
+.content .highlighted.keyword { background-color: #f99650; }
.content span.enum, .content a.enum, .block a.current.enum { color: #508157; }
.content span.struct, .content a.struct, .block a.current.struct { color: #ad448e; }
.content span.method, .content a.method, .block a.current.method,
.content span.tymethod, .content a.tymethod, .block a.current.tymethod,
.content .fnname { color: #9a6e31; }
+.content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; }
pre.rust .comment { color: #8E908C; }
pre.rust .doccomment { color: #4D4D4C; }
color: grey;
}
-tr.result span.primitive::after {
+tr.result span.primitive::after, tr.result span.keyword::after {
color: black;
}
// Associated types are never stripped
clean::AssociatedTypeItem(..) => {}
+
+ // Keywords are never stripped
+ clean::KeywordItem(..) => {}
}
let fastreturn = match i.inner {
def_id,
attrs: def.attrs.clone().into(),
name: def.ident.name,
- whence: def.span,
+ whence: self.cx.tcx.def_span(def_id),
matchers,
- stab: self.stability(def.id),
- depr: self.deprecation(def.id),
+ stab: self.cx.tcx.lookup_stability(def_id).cloned(),
+ depr: self.cx.tcx.lookup_deprecation(def_id),
imported_from: Some(imported_from),
})
}
#![feature(float_from_str_radix)]
#![feature(fn_traits)]
#![feature(fnbox)]
+#![feature(futures_api)]
#![feature(hashmap_internals)]
#![feature(heap_api)]
#![feature(int_error_internals)]
#![feature(panic_internals)]
#![feature(panic_unwind)]
#![feature(peek)]
+#![feature(pin)]
#![feature(placement_new_protocol)]
#![feature(prelude_import)]
#![feature(ptr_internals)]
#![cfg_attr(test, feature(update_panic_count))]
#![cfg_attr(windows, feature(used))]
#![feature(doc_alias)]
+#![feature(doc_keyword)]
#![feature(float_internals)]
#![feature(panic_info_message)]
#![cfg_attr(not(stage0), feature(panic_implementation))]
#[stable(feature = "core_hint", since = "1.27.0")]
pub use core::hint;
+#[unstable(feature = "futures_api",
+ reason = "futures in libcore are unstable",
+ issue = "50547")]
+pub mod task {
+ //! Types and Traits for working with asynchronous tasks.
+ pub use core::task::*;
+ pub use alloc_crate::task::*;
+}
+
+#[unstable(feature = "futures_api",
+ reason = "futures in libcore are unstable",
+ issue = "50547")]
+pub use core::future;
+
pub mod f32;
pub mod f64;
pub fn sub_instant(&self, other: &Instant) -> Duration {
self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
- panic!("other was less than the current instant")
+ panic!("specified instant was later than self")
})
}
pub fn sub_instant(&self, other: &Instant) -> Duration {
self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
- panic!("other was less than the current instant")
+ panic!("specified instant was later than self")
})
}
use ast;
use ast::{AttrId, Attribute, Name, Ident, Path, PathSegment};
use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
-use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind};
+use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind, GenericParam};
use codemap::{BytePos, Spanned, respan, dummy_spanned};
use syntax_pos::Span;
use errors::{Applicability, Handler};
}
}
+impl HasAttrs for GenericParam {
+ fn attrs(&self) -> &[ast::Attribute] {
+ match self {
+ GenericParam::Lifetime(lifetime) => lifetime.attrs(),
+ GenericParam::Type(ty) => ty.attrs(),
+ }
+ }
+
+ fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self {
+ match self {
+ GenericParam::Lifetime(lifetime) => GenericParam::Lifetime(lifetime.map_attrs(f)),
+ GenericParam::Type(ty) => GenericParam::Type(ty.map_attrs(f)),
+ }
+ }
+}
+
macro_rules! derive_has_attrs {
($($ty:path),*) => { $(
impl HasAttrs for $ty {
derive_has_attrs! {
Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm,
- ast::Field, ast::FieldPat, ast::Variant_
+ ast::Field, ast::FieldPat, ast::Variant_, ast::LifetimeDef, ast::TyParam
}
pattern
})
}
+
+ // deny #[cfg] on generic parameters until we decide what to do with it.
+ // see issue #51279.
+ pub fn disallow_cfg_on_generic_param(&mut self, param: &ast::GenericParam) {
+ for attr in param.attrs() {
+ let offending_attr = if attr.check_name("cfg") {
+ "cfg"
+ } else if attr.check_name("cfg_attr") {
+ "cfg_attr"
+ } else {
+ continue;
+ };
+ let msg = format!("#[{}] cannot be applied on a generic parameter", offending_attr);
+ self.sess.span_diagnostic.span_err(attr.span, &msg);
+ }
+ }
}
impl<'a> fold::Folder for StripUnconfigured<'a> {
}
}
+ fn fold_generic_param(&mut self, param: ast::GenericParam) -> ast::GenericParam {
+ self.cfg.disallow_cfg_on_generic_param(¶m);
+ noop_fold_generic_param(param, self)
+ }
+
fn fold_attribute(&mut self, at: ast::Attribute) -> Option<ast::Attribute> {
// turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
// contents="file contents")]` attributes
{
// We basically look at two token trees here, denoted as #1 and #2 below
let span = match parse_kleene_op(input, span) {
- // #1 is any KleeneOp (`?`)
- Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => {
- if !features.macro_at_most_once_rep
- && !attr::contains_name(attrs, "allow_internal_unstable")
- {
- let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
- emit_feature_err(
- sess,
- "macro_at_most_once_rep",
- span,
- GateIssue::Language,
- explain,
- );
+ // #1 is a `+` or `*` KleeneOp
+ //
+ // `?` is ambiguous: it could be a separator or a Kleene::ZeroOrOne, so we need to look
+ // ahead one more token to be sure.
+ Ok(Ok(op)) if op != KleeneOp::ZeroOrOne => return (None, op),
+
+ // #1 is `?` token, but it could be a Kleene::ZeroOrOne without a separator or it could
+ // be a `?` separator followed by any Kleene operator. We need to look ahead 1 token to
+ // find out which.
+ Ok(Ok(op)) => {
+ assert_eq!(op, KleeneOp::ZeroOrOne);
+
+ // Lookahead at #2. If it is a KleenOp, then #1 is a separator.
+ let is_1_sep = if let Some(&tokenstream::TokenTree::Token(_, ref tok2)) = input.peek() {
+ kleene_op(tok2).is_some()
+ } else {
+ false
+ };
+
+ if is_1_sep {
+ // #1 is a separator and #2 should be a KleepeOp::*
+ // (N.B. We need to advance the input iterator.)
+ match parse_kleene_op(input, span) {
+ // #2 is a KleeneOp (this is the only valid option) :)
+ Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => {
+ if !features.macro_at_most_once_rep
+ && !attr::contains_name(attrs, "allow_internal_unstable")
+ {
+ let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
+ emit_feature_err(
+ sess,
+ "macro_at_most_once_rep",
+ span,
+ GateIssue::Language,
+ explain,
+ );
+ }
+ return (Some(token::Question), op);
+ }
+ Ok(Ok(op)) => return (Some(token::Question), op),
+
+ // #2 is a random token (this is an error) :(
+ Ok(Err((_, span))) => span,
+
+ // #2 is not even a token at all :(
+ Err(span) => span,
+ }
+ } else {
+ if !features.macro_at_most_once_rep
+ && !attr::contains_name(attrs, "allow_internal_unstable")
+ {
+ let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
+ emit_feature_err(
+ sess,
+ "macro_at_most_once_rep",
+ span,
+ GateIssue::Language,
+ explain,
+ );
+ }
+
+ // #2 is a random tree and #1 is KleeneOp::ZeroOrOne
+ return (None, op);
}
- return (None, op);
}
- // #1 is any KleeneOp (`+`, `*`)
- Ok(Ok(op)) => return (None, op),
-
// #1 is a separator followed by #2, a KleeneOp
Ok(Err((tok, span))) => match parse_kleene_op(input, span) {
// #2 is a KleeneOp :D
GateIssue::Language,
explain,
);
- } else {
- sess.span_diagnostic
- .span_err(span, "`?` macro repetition does not allow a separator");
}
- return (None, op);
+ return (Some(tok), op);
}
Ok(Ok(op)) => return (Some(tok), op),
Err(span) => span,
};
- if !features.macro_at_most_once_rep && !attr::contains_name(attrs, "allow_internal_unstable") {
+ if !features.macro_at_most_once_rep
+ && !attr::contains_name(attrs, "allow_internal_unstable")
+ {
sess.span_diagnostic
.span_err(span, "expected one of: `*`, `+`, or `?`");
} else {
// `foo.rs` as an alternative to `foo/mod.rs`
(active, non_modrs_mods, "1.24.0", Some(44660), Some(Edition::Edition2018)),
- // Termination trait in tests (RFC 1937)
- (active, termination_trait_test, "1.24.0", Some(48854), Some(Edition::Edition2018)),
-
// `extern` in paths
(active, extern_in_paths, "1.23.0", Some(44660), None),
// 'a: { break 'a; }
(active, label_break_value, "1.28.0", Some(48594), None),
+
// #[panic_implementation]
(active, panic_implementation, "1.28.0", Some(44489), None),
+
+ // #[doc(keyword = "...")]
+ (active, doc_keyword, "1.28.0", Some(51315), None),
);
declare_features! (
// allow `'_` placeholder lifetimes
(accepted, underscore_lifetimes, "1.26.0", Some(44524), None),
// Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
- (accepted, generic_param_attrs, "1.26.0", Some(48848), None),
+ (accepted, generic_param_attrs, "1.27.0", Some(48848), None),
// Allows cfg(target_feature = "...").
(accepted, cfg_target_feature, "1.27.0", Some(29717), None),
// Allows #[target_feature(...)]
(accepted, fn_must_use, "1.27.0", Some(43302), None),
// Allows use of the :lifetime macro fragment specifier
(accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
+ // Termination trait in tests (RFC 1937)
+ (accepted, termination_trait_test, "1.27.0", Some(48854), None),
);
// If you change this, please modify src/doc/unstable-book as well. You must
gate_feature_post!(&self, doc_alias, attr.span,
"#[doc(alias = \"...\")] is experimental"
);
+ } else if content.iter().any(|c| c.check_name("keyword")) {
+ gate_feature_post!(&self, doc_keyword, attr.span,
+ "#[doc(keyword = \"...\")] is experimental"
+ );
}
}
}
Err(err)
}
} else {
- self.expect_one_of(unsafe { slice::from_raw_parts(t, 1) }, &[])
+ self.expect_one_of(slice::from_ref(t), &[])
}
}
{
let mut first: bool = true;
let mut v = vec![];
- while !kets.contains(&&self.token) {
+ while !kets.iter().any(|k| {
+ match expect {
+ TokenExpectType::Expect => self.check(k),
+ TokenExpectType::NoExpect => self.token == **k,
+ }
+ }) {
match self.token {
token::CloseDelim(..) | token::Eof => break,
_ => {}
Ok((before, slice, after))
}
+ fn parse_pat_field(
+ &mut self,
+ lo: Span,
+ attrs: Vec<Attribute>
+ ) -> PResult<'a, codemap::Spanned<ast::FieldPat>> {
+ // Check if a colon exists one ahead. This means we're parsing a fieldname.
+ let hi;
+ let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
+ // Parsing a pattern of the form "fieldname: pat"
+ let fieldname = self.parse_field_name()?;
+ self.bump();
+ let pat = self.parse_pat()?;
+ hi = pat.span;
+ (pat, fieldname, false)
+ } else {
+ // Parsing a pattern of the form "(box) (ref) (mut) fieldname"
+ let is_box = self.eat_keyword(keywords::Box);
+ let boxed_span = self.span;
+ let is_ref = self.eat_keyword(keywords::Ref);
+ let is_mut = self.eat_keyword(keywords::Mut);
+ let fieldname = self.parse_ident()?;
+ hi = self.prev_span;
+
+ let bind_type = match (is_ref, is_mut) {
+ (true, true) => BindingMode::ByRef(Mutability::Mutable),
+ (true, false) => BindingMode::ByRef(Mutability::Immutable),
+ (false, true) => BindingMode::ByValue(Mutability::Mutable),
+ (false, false) => BindingMode::ByValue(Mutability::Immutable),
+ };
+ let fieldpat = P(Pat {
+ id: ast::DUMMY_NODE_ID,
+ node: PatKind::Ident(bind_type, fieldname, None),
+ span: boxed_span.to(hi),
+ });
+
+ let subpat = if is_box {
+ P(Pat {
+ id: ast::DUMMY_NODE_ID,
+ node: PatKind::Box(fieldpat),
+ span: lo.to(hi),
+ })
+ } else {
+ fieldpat
+ };
+ (subpat, fieldname, true)
+ };
+
+ Ok(codemap::Spanned {
+ span: lo.to(hi),
+ node: ast::FieldPat {
+ ident: fieldname,
+ pat: subpat,
+ is_shorthand,
+ attrs: attrs.into(),
+ }
+ })
+ }
+
/// Parse the fields of a struct-like pattern
fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<codemap::Spanned<ast::FieldPat>>, bool)> {
let mut fields = Vec::new();
let mut etc = false;
- let mut first = true;
- while self.token != token::CloseDelim(token::Brace) {
- if first {
- first = false;
- } else {
- self.expect(&token::Comma)?;
- // accept trailing commas
- if self.check(&token::CloseDelim(token::Brace)) { break }
- }
+ let mut ate_comma = true;
+ let mut delayed_err: Option<DiagnosticBuilder<'a>> = None;
+ let mut etc_span = None;
+ while self.token != token::CloseDelim(token::Brace) {
let attrs = self.parse_outer_attributes()?;
let lo = self.span;
- let hi;
+
+ // check that a comma comes after every field
+ if !ate_comma {
+ let err = self.struct_span_err(self.prev_span, "expected `,`");
+ return Err(err);
+ }
+ ate_comma = false;
if self.check(&token::DotDot) || self.token == token::DotDotDot {
+ etc = true;
+ let mut etc_sp = self.span;
+
if self.token == token::DotDotDot { // Issue #46718
+ // Accept `...` as if it were `..` to avoid further errors
let mut err = self.struct_span_err(self.span,
"expected field pattern, found `...`");
err.span_suggestion_with_applicability(
);
err.emit();
}
+ self.bump(); // `..` || `...`:w
- self.bump();
- if self.token != token::CloseDelim(token::Brace) {
- let token_str = self.this_token_to_string();
- let mut err = self.fatal(&format!("expected `{}`, found `{}`", "}", token_str));
- if self.token == token::Comma { // Issue #49257
- err.span_label(self.span,
- "`..` must be in the last position, \
- and cannot have a trailing comma");
+ if self.token == token::CloseDelim(token::Brace) {
+ etc_span = Some(etc_sp);
+ break;
+ }
+ let token_str = self.this_token_to_string();
+ let mut err = self.fatal(&format!("expected `}}`, found `{}`", token_str));
+
+ err.span_label(self.span, "expected `}`");
+ let mut comma_sp = None;
+ if self.token == token::Comma { // Issue #49257
+ etc_sp = etc_sp.to(self.sess.codemap().span_until_non_whitespace(self.span));
+ err.span_label(etc_sp,
+ "`..` must be at the end and cannot have a trailing comma");
+ comma_sp = Some(self.span);
+ self.bump();
+ ate_comma = true;
+ }
+
+ etc_span = Some(etc_sp);
+ if self.token == token::CloseDelim(token::Brace) {
+ // If the struct looks otherwise well formed, recover and continue.
+ if let Some(sp) = comma_sp {
+ err.span_suggestion_short(sp, "remove this comma", "".into());
+ }
+ err.emit();
+ break;
+ } else if self.token.is_ident() && ate_comma {
+ // Accept fields coming after `..,`.
+ // This way we avoid "pattern missing fields" errors afterwards.
+ // We delay this error until the end in order to have a span for a
+ // suggested fix.
+ if let Some(mut delayed_err) = delayed_err {
+ delayed_err.emit();
+ return Err(err);
} else {
- err.span_label(self.span, "expected `}`");
+ delayed_err = Some(err);
+ }
+ } else {
+ if let Some(mut err) = delayed_err {
+ err.emit();
}
return Err(err);
}
- etc = true;
- break;
}
- // Check if a colon exists one ahead. This means we're parsing a fieldname.
- let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
- // Parsing a pattern of the form "fieldname: pat"
- let fieldname = self.parse_field_name()?;
- self.bump();
- let pat = self.parse_pat()?;
- hi = pat.span;
- (pat, fieldname, false)
- } else {
- // Parsing a pattern of the form "(box) (ref) (mut) fieldname"
- let is_box = self.eat_keyword(keywords::Box);
- let boxed_span = self.span;
- let is_ref = self.eat_keyword(keywords::Ref);
- let is_mut = self.eat_keyword(keywords::Mut);
- let fieldname = self.parse_ident()?;
- hi = self.prev_span;
-
- let bind_type = match (is_ref, is_mut) {
- (true, true) => BindingMode::ByRef(Mutability::Mutable),
- (true, false) => BindingMode::ByRef(Mutability::Immutable),
- (false, true) => BindingMode::ByValue(Mutability::Mutable),
- (false, false) => BindingMode::ByValue(Mutability::Immutable),
- };
- let fieldpat = P(Pat {
- id: ast::DUMMY_NODE_ID,
- node: PatKind::Ident(bind_type, fieldname, None),
- span: boxed_span.to(hi),
- });
-
- let subpat = if is_box {
- P(Pat {
- id: ast::DUMMY_NODE_ID,
- node: PatKind::Box(fieldpat),
- span: lo.to(hi),
- })
- } else {
- fieldpat
- };
- (subpat, fieldname, true)
- };
-
- fields.push(codemap::Spanned { span: lo.to(hi),
- node: ast::FieldPat {
- ident: fieldname,
- pat: subpat,
- is_shorthand,
- attrs: attrs.into(),
- }
+ fields.push(match self.parse_pat_field(lo, attrs) {
+ Ok(field) => field,
+ Err(err) => {
+ if let Some(mut delayed_err) = delayed_err {
+ delayed_err.emit();
+ }
+ return Err(err);
+ }
});
+ ate_comma = self.eat(&token::Comma);
+ }
+
+ if let Some(mut err) = delayed_err {
+ if let Some(etc_span) = etc_span {
+ err.multipart_suggestion(
+ "move the `..` to the end of the field list",
+ vec![
+ (etc_span, "".into()),
+ (self.span, format!("{}.. }}", if ate_comma { "" } else { ", " })),
+ ],
+ );
+ }
+ err.emit();
}
return Ok((fields, etc));
}
// Only a limited set of initial token sequences is considered self parameters, anything
// else is parsed as a normal function parameter list, so some lookahead is required.
let eself_lo = self.span;
- let (eself, eself_ident) = match self.token {
+ let (eself, eself_ident, eself_hi) = match self.token {
token::BinOp(token::And) => {
// &self
// &mut self
// &'lt self
// &'lt mut self
// ¬_self
- if isolated_self(self, 1) {
+ (if isolated_self(self, 1) {
self.bump();
- (SelfKind::Region(None, Mutability::Immutable), expect_ident(self))
+ SelfKind::Region(None, Mutability::Immutable)
} else if self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
isolated_self(self, 2) {
self.bump();
self.bump();
- (SelfKind::Region(None, Mutability::Mutable), expect_ident(self))
+ SelfKind::Region(None, Mutability::Mutable)
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
isolated_self(self, 2) {
self.bump();
let lt = self.expect_lifetime();
- (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self))
+ SelfKind::Region(Some(lt), Mutability::Immutable)
} else if self.look_ahead(1, |t| t.is_lifetime()) &&
self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) &&
isolated_self(self, 3) {
self.bump();
let lt = self.expect_lifetime();
self.bump();
- (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self))
+ SelfKind::Region(Some(lt), Mutability::Mutable)
} else {
return Ok(None);
- }
+ }, expect_ident(self), self.prev_span)
}
token::BinOp(token::Star) => {
// *self
// *mut self
// *not_self
// Emit special error for `self` cases.
- if isolated_self(self, 1) {
+ (if isolated_self(self, 1) {
self.bump();
self.span_err(self.span, "cannot pass `self` by raw pointer");
- (SelfKind::Value(Mutability::Immutable), expect_ident(self))
+ SelfKind::Value(Mutability::Immutable)
} else if self.look_ahead(1, |t| t.is_mutability()) &&
isolated_self(self, 2) {
self.bump();
self.bump();
self.span_err(self.span, "cannot pass `self` by raw pointer");
- (SelfKind::Value(Mutability::Immutable), expect_ident(self))
+ SelfKind::Value(Mutability::Immutable)
} else {
return Ok(None);
- }
+ }, expect_ident(self), self.prev_span)
}
token::Ident(..) => {
if isolated_self(self, 0) {
// self
// self: TYPE
let eself_ident = expect_ident(self);
- if self.eat(&token::Colon) {
+ let eself_hi = self.prev_span;
+ (if self.eat(&token::Colon) {
let ty = self.parse_ty()?;
- (SelfKind::Explicit(ty, Mutability::Immutable), eself_ident)
+ SelfKind::Explicit(ty, Mutability::Immutable)
} else {
- (SelfKind::Value(Mutability::Immutable), eself_ident)
- }
+ SelfKind::Value(Mutability::Immutable)
+ }, eself_ident, eself_hi)
} else if self.token.is_keyword(keywords::Mut) &&
isolated_self(self, 1) {
// mut self
// mut self: TYPE
self.bump();
let eself_ident = expect_ident(self);
- if self.eat(&token::Colon) {
+ let eself_hi = self.prev_span;
+ (if self.eat(&token::Colon) {
let ty = self.parse_ty()?;
- (SelfKind::Explicit(ty, Mutability::Mutable), eself_ident)
+ SelfKind::Explicit(ty, Mutability::Mutable)
} else {
- (SelfKind::Value(Mutability::Mutable), eself_ident)
- }
+ SelfKind::Value(Mutability::Mutable)
+ }, eself_ident, eself_hi)
} else {
return Ok(None);
}
_ => return Ok(None),
};
- let eself = codemap::respan(eself_lo.to(self.prev_span), eself);
+ let eself = codemap::respan(eself_lo.to(eself_hi), eself);
Ok(Some(Arg::from_self(eself, eself_ident)))
}
fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
let has_test_attr = attr::contains_name(&i.attrs, "test");
- fn has_test_signature(cx: &TestCtxt, i: &ast::Item) -> HasTestSignature {
+ fn has_test_signature(_cx: &TestCtxt, i: &ast::Item) -> HasTestSignature {
let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic");
match i.node {
ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
return No(BadTestSignature::NoArgumentsAllowed);
}
- match (has_output, cx.features.termination_trait_test, has_should_panic_attr) {
- (true, true, true) => No(BadTestSignature::ShouldPanicOnlyWithNoArgs),
- (true, true, false) => if generics.is_parameterized() {
+ match (has_output, has_should_panic_attr) {
+ (true, true) => No(BadTestSignature::ShouldPanicOnlyWithNoArgs),
+ (true, false) => if generics.is_parameterized() {
No(BadTestSignature::WrongTypeSignature)
} else {
Yes
},
- (true, false, _) => No(BadTestSignature::WrongTypeSignature),
- (false, _, _) => Yes
+ (false, _) => Yes
}
}
_ => No(BadTestSignature::NotEvenAFunction),
fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
let has_bench_attr = attr::contains_name(&i.attrs, "bench");
- fn has_bench_signature(cx: &TestCtxt, i: &ast::Item) -> bool {
+ fn has_bench_signature(_cx: &TestCtxt, i: &ast::Item) -> bool {
match i.node {
- ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
- let input_cnt = decl.inputs.len();
-
- // If the termination trait is active, the compiler will check that the output
- // type implements the `Termination` trait as `libtest` enforces that.
- let output_matches = if cx.features.termination_trait_test {
- true
- } else {
- let no_output = match decl.output {
- ast::FunctionRetTy::Default(..) => true,
- ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true,
- _ => false
- };
- let tparm_cnt = generics.params.iter()
- .filter(|param| param.is_type_param())
- .count();
-
- no_output && tparm_cnt == 0
- };
-
+ ast::ItemKind::Fn(ref decl, _, _, _, _, _) => {
// NB: inadequate check, but we're running
// well before resolve, can't get too deep.
- input_cnt == 1 && output_matches
+ decl.inputs.len() == 1
}
_ => false
}
if has_bench_attr && !has_bench_signature {
let diag = cx.span_diagnostic;
- if cx.features.termination_trait_test {
- diag.span_err(i.span, "functions used as benches must have signature \
+ diag.span_err(i.span, "functions used as benches must have signature \
`fn(&mut Bencher) -> impl Termination`");
- } else {
- diag.span_err(i.span, "functions used as benches must have signature \
- `fn(&mut Bencher) -> ()`");
- }
}
has_bench_attr && has_bench_signature
ident: Ident::with_empty_ctxt(super::Symbol($index))
};
)*
+
+ impl ::std::str::FromStr for Keyword {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<Self, ()> {
+ match s {
+ $($string => Ok($konst),)*
+ _ => Err(()),
+ }
+ }
+ }
}
impl Interner {
// ignore-powerpc64
// ignore-s390x
// ignore-sparc
+// ignore-sparc64
// ignore-wasm32
// ignore-x86
// ignore-x86_64
// ignore-r600
// ignore-amdgcn
// ignore-sparc
+// ignore-sparc64
// ignore-sparcv9
// ignore-sparcel
// ignore-s390x
// ignore-asmjs
// ignore-mips64
// ignore-s390x
+// ignore-sparc
+// ignore-sparc64
// ignore-wasm
// ignore-x86
// ignore-x86_64
// ignore-mips64
// ignore-powerpc
// ignore-s390x
+// ignore-sparc
+// ignore-sparc64
// ignore-wasm
// ignore-emscripten
// ignore-windows
// ignore-emscripten
// ignore-mips
// ignore-mips64
+// ignore-sparc
+// ignore-sparc64
// compile-flags: -O
#![feature(repr_simd)]
// ignore-emscripten
// ignore-powerpc
// ignore-sparc
+// ignore-sparc64
// ignore-mips
// ignore-mips64
// ignore-emscripten
// ignore-powerpc
// ignore-sparc
+// ignore-sparc64
// ignore-mips
// ignore-mips64
// ignore-emscripten
// ignore-powerpc
// ignore-sparc
+// ignore-sparc64
// ignore-mips
// ignore-mips64
// ignore-emscripten
// ignore-powerpc
// ignore-sparc
+// ignore-sparc64
// ignore-mips
// ignore-mips64
// ignore-emscripten
// ignore-powerpc
// ignore-sparc
+// ignore-sparc64
// ignore-mips
// ignore-mips64
// ignore-emscripten
// ignore-powerpc
// ignore-sparc
+// ignore-sparc64
// revisions: ast mir
//[mir]compile-flags: -Z borrowck=mir
const BAR: usize = FOO[5]; // no error, because the error below occurs before regular const eval
const BLUB: [u32; FOO[4]] = [5, 6];
-//~^ ERROR constant evaluation error [E0080]
+//~^ ERROR could not evaluate constant expression [E0080]
//~| index out of bounds: the len is 3 but the index is 4
fn main() {
pub const A: i8 = -std::i8::MIN; //~ ERROR const_err
//~^ ERROR this constant cannot be used
-//~| ERROR constant evaluation error
+//~| ERROR this expression will panic at runtime
pub const B: u8 = 200u8 + 200u8; //~ ERROR const_err
//~^ ERROR this constant cannot be used
pub const C: u8 = 200u8 * 4; //~ ERROR const_err
//~^ ERROR this constant cannot be used
pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR const_err
//~^ ERROR this constant cannot be used
-pub const E: u8 = [5u8][1];
-//~^ ERROR const_err
+pub const E: u8 = [5u8][1]; //~ ERROR const_err
+//~| ERROR this constant cannot be used
fn main() {
let _a = A;
pub const A: i8 = -std::i8::MIN;
//~^ ERROR E0080
//~| ERROR attempt to negate with overflow
-//~| ERROR constant evaluation error
+//~| ERROR this expression will panic at runtime
//~| ERROR this constant cannot be used
pub const B: i8 = A;
//~^ ERROR const_err
+//~| ERROR const_err
pub const C: u8 = A as u8;
//~^ ERROR const_err
+//~| ERROR const_err
pub const D: i8 = 50 - A;
//~^ ERROR const_err
+//~| ERROR const_err
fn main() {
let _ = (A, B, C, D);
// Make sure that the two uses get two errors.
const FOO: u8 = [5u8][1];
//~^ ERROR constant evaluation error
+//~| ERROR constant evaluation error
//~| index out of bounds: the len is 1 but the index is 1
fn main() {
let d = 42u8 - (42u8 + 1);
//~^ ERROR const_err
let _e = [5u8][1];
+ //~^ ERROR const_err
black_box(a);
black_box(b);
black_box(c);
let d = 42u8 - (42u8 + 1);
//~^ ERROR const_err
let _e = [5u8][1];
+ //~^ ERROR const_err
black_box(b);
black_box(c);
black_box(d);
//~| ERROR mismatched types
//~| expected usize, found bool
const ARR: [i32; X] = [99; 34];
-//~^ ERROR constant evaluation error
const X1: usize = 42 || 39;
//~^ ERROR mismatched types
//~| ERROR mismatched types
//~| expected usize, found bool
const ARR1: [i32; X1] = [99; 47];
-//~^ ERROR constant evaluation error
const X2: usize = -42 || -39;
//~^ ERROR mismatched types
//~| ERROR mismatched types
//~| expected usize, found bool
const ARR2: [i32; X2] = [99; 18446744073709551607];
-//~^ ERROR constant evaluation error
const X3: usize = -42 && -39;
//~^ ERROR mismatched types
//~| ERROR mismatched types
//~| expected usize, found bool
const ARR3: [i32; X3] = [99; 6];
-//~^ ERROR constant evaluation error
const Y: usize = 42.0 == 42.0;
//~^ ERROR mismatched types
//~| expected usize, found bool
const ARRR: [i32; Y] = [99; 1];
-//~^ ERROR constant evaluation error
const Y1: usize = 42.0 >= 42.0;
//~^ ERROR mismatched types
//~| expected usize, found bool
const ARRR1: [i32; Y1] = [99; 1];
-//~^ ERROR constant evaluation error
const Y2: usize = 42.0 <= 42.0;
//~^ ERROR mismatched types
//~| expected usize, found bool
const ARRR2: [i32; Y2] = [99; 1];
-//~^ ERROR constant evaluation error
const Y3: usize = 42.0 > 42.0;
//~^ ERROR mismatched types
//~| expected usize, found bool
const ARRR3: [i32; Y3] = [99; 0];
-//~^ ERROR constant evaluation error
const Y4: usize = 42.0 < 42.0;
//~^ ERROR mismatched types
//~| expected usize, found bool
const ARRR4: [i32; Y4] = [99; 0];
-//~^ ERROR constant evaluation error
const Y5: usize = 42.0 != 42.0;
//~^ ERROR mismatched types
//~| expected usize, found bool
const ARRR5: [i32; Y5] = [99; 0];
-//~^ ERROR constant evaluation error
fn main() {
let _ = ARR;
fn main() {
let a: [i8; ONE - TWO] = unimplemented!();
- //~^ ERROR constant evaluation error
+ //~^ ERROR could not evaluate constant expression
//~| attempt to subtract with overflow
}
#[cfg(eval2)]
let x: [i32; { let 0 = 0; 0 }] = [];
//[eval2]~^ ERROR refutable pattern in local binding
- //[eval2]~| ERROR constant evaluation error
}
//~^ ERROR mismatched types
//~| expected tuple, found usize
const ARR: [i32; TUP.0] = [];
-//~^ ERROR constant evaluation error
fn main() {
}
enum Test {
DivZero = 1/0,
//~^ attempt to divide by zero
- //~| ERROR constant evaluation error
- //~| ERROR constant evaluation error
+ //~| ERROR could not evaluate enum discriminant
+ //~| ERROR this expression will panic at runtime
RemZero = 1%0,
//~^ attempt to calculate the remainder with a divisor of zero
- //~| ERROR constant evaluation error
- //~| ERROR constant evaluation error
+ //~| ERROR could not evaluate enum discriminant
+ //~| ERROR this expression will panic at runtime
}
fn main() {}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: --test
-
-fn main() {}
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn it_works() -> Result<(), ()> {
- //~^ ERROR functions used as tests must have signature fn() -> ()
- Ok(())
- }
-}
// except according to those terms.
fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0`
-//~| ERROR expected one of `->`, `where`, or `{`, found `]`
+//~| ERROR expected one of `)`, `,`, `->`, `where`, or `{`, found `]`
// FIXME(jseyfried): avoid emitting the second error (preexisting)
fn main() {}
const NUM: u8 = xyz();
//~^ ERROR calls in constants are limited to constant functions, tuple structs and tuple variants
-//~| ERROR constant evaluation error
fn main() {
match 1 {
NUM => unimplemented!(),
+ //~^ ERROR could not evaluate constant pattern
_ => unimplemented!(),
}
}
fn main() {
assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
//~^ ERROR attempt to divide with overflow
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
//~^ ERROR attempt to divide with overflow
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
//~^ ERROR attempt to divide with overflow
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
//~^ ERROR attempt to divide with overflow
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
//~^ ERROR attempt to divide with overflow
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
//~^ ERROR attempt to divide by zero
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with overflow
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with overflow
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with overflow
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with overflow
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with overflow
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
//~^ ERROR attempt to calculate the remainder with a divisor of zero
- //~| ERROR constant evaluation error
+ //~| ERROR this expression will panic at runtime
}
--- /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
+
+#![crate_type = "rlib"]
+#![no_std]
+#![feature(panic_implementation)]
+
+#[panic_implementation]
+pub fn panic_fmt(_: &::core::panic::PanicInfo) -> ! {
+ |x: u8| x;
+ loop {}
+}
+++ /dev/null
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-mod foo {
- type T = ();
- struct S1(pub(in foo) (), pub(T), pub(crate) (), pub(((), T)));
- struct S2(pub((foo)) ());
- //~^ ERROR expected `,`, found `(`
- //~| ERROR cannot find type `foo` in this scope
-}
+++ /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.
-
-macro_rules! define_struct {
- ($t:ty) => {
- struct S1(pub $t);
- struct S2(pub (in foo) ());
- struct S3(pub $t ());
- //~^ ERROR expected `,`, found `(`
- }
-}
-
-mod foo {
- define_struct! { (foo) }
-}
+++ /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.
-
-macro_rules! define_struct {
- ($t:ty) => {
- struct S1(pub($t));
- struct S2(pub (in foo) ());
- struct S3(pub($t) ());
- //~^ ERROR expected `,`, found `(`
- }
-}
-
-mod foo {
- define_struct! { foo }
-}
fn main() {
struct Foo { x: isize }
match (Foo { x: 10 }) {
- Foo { ref x: ref x } => {}, //~ ERROR expected `,`, found `:`
+ Foo { ref x: ref x } => {}, //~ ERROR expected `,`
_ => {}
}
}
const C: [u32; 5] = [0; 5];
+#[allow(const_err)]
fn test() -> u32 {
C[10]
}
const C: &'static [u8; 5] = b"hello";
+#[allow(const_err)]
fn test() -> u8 {
C[10]
}
const C: &'static [u8; 5] = b"hello";
+#[allow(const_err)]
fn mir() -> u8 {
C[10]
}
extern crate syntax;
use rustc::session::{build_session, Session};
-use rustc::session::config::{basic_options, Input,
+use rustc::session::config::{basic_options, Input, Options,
OutputType, OutputTypes};
-use rustc_driver::driver::{compile_input, CompileController};
+use rustc_driver::driver::{self, compile_input, CompileController};
use rustc_metadata::cstore::CStore;
use rustc_errors::registry::Registry;
use syntax::codemap::FileName;
compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
}
-fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>, Box<CodegenBackend>) {
- let mut opts = basic_options();
- opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
- opts.maybe_sysroot = Some(sysroot);
- if let Ok(linker) = std::env::var("RUSTC_LINKER") {
- opts.cg.linker = Some(linker.into());
- }
-
+fn basic_sess(opts: Options) -> (Session, Rc<CStore>, Box<CodegenBackend>) {
let descriptions = Registry::new(&rustc::DIAGNOSTICS);
let sess = build_session(opts, None, descriptions);
let codegen_backend = rustc_driver::get_codegen_backend(&sess);
fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
syntax::with_globals(|| {
- let (sess, cstore, codegen_backend) = basic_sess(sysroot);
- let control = CompileController::basic();
- let input = Input::Str { name: FileName::Anon, input: code };
- let _ = compile_input(
- codegen_backend,
- &sess,
- &cstore,
- &None,
- &input,
- &None,
- &Some(output),
- None,
- &control
- );
+ let mut opts = basic_options();
+ opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
+ opts.maybe_sysroot = Some(sysroot);
+ if let Ok(linker) = std::env::var("RUSTC_LINKER") {
+ opts.cg.linker = Some(linker.into());
+ }
+ driver::spawn_thread_pool(opts, |opts| {
+ let (sess, cstore, codegen_backend) = basic_sess(opts);
+ let control = CompileController::basic();
+ let input = Input::Str { name: FileName::Anon, input: code };
+ let _ = compile_input(
+ codegen_backend,
+ &sess,
+ &cstore,
+ &None,
+ &input,
+ &None,
+ &Some(output),
+ None,
+ &control
+ );
+ });
});
}
use std::path::PathBuf;
-struct TestCalls {
- count: u32
+struct TestCalls<'a> {
+ count: &'a mut u32
}
-impl<'a> CompilerCalls<'a> for TestCalls {
+impl<'a> CompilerCalls<'a> for TestCalls<'a> {
fn early_callback(&mut self,
_: &getopts::Matches,
_: &config::Options,
_: &errors::registry::Registry,
_: config::ErrorOutputType)
-> Compilation {
- self.count *= 2;
+ *self.count *= 2;
Compilation::Continue
}
_: &Option<PathBuf>,
_: &Option<PathBuf>)
-> Compilation {
- self.count *= 3;
+ *self.count *= 3;
Compilation::Stop
}
fn some_input(&mut self, input: Input, input_path: Option<PathBuf>)
-> (Input, Option<PathBuf>) {
- self.count *= 5;
+ *self.count *= 5;
(input, input_path)
}
panic!("This shouldn't happen");
}
- fn build_controller(&mut self,
+ fn build_controller(self: Box<Self>,
_: &Session,
_: &getopts::Matches)
-> driver::CompileController<'a> {
fn main() {
- let mut tc = TestCalls { count: 1 };
- // we should never get use this filename, but lets make sure they are valid args.
- let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
- rustc_driver::run_compiler(&args, &mut tc, None, None);
- assert_eq!(tc.count, 30);
+ let mut count = 1;
+ {
+ let tc = TestCalls { count: &mut count };
+ // we should never get use this filename, but lets make sure they are valid args.
+ let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
+ rustc_driver::run_compiler(&args, Box::new(tc), None, None);
+ }
+ assert_eq!(count, 30);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(duplicate_macro_exports)]
+
#[macro_export]
macro_rules! foo { ($i:ident) => {} }
--- /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.
+
+macro_rules! macro_one { ($($t:tt)*) => ($($t)*) }
+
+macro_rules! macro_two { ($($t:tt)*) => ($($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.
+
+// Test case from #39963.
+
+#![feature(nll)]
+
+#[derive(Clone)]
+struct Foo(Option<Box<Foo>>, Option<Box<Foo>>);
+
+fn test(f: &mut Foo) {
+ match *f {
+ Foo(Some(ref mut left), Some(ref mut right)) => match **left {
+ Foo(Some(ref mut left), Some(ref mut right)) => panic!(),
+ _ => panic!(),
+ },
+ _ => panic!(),
+ }
+}
+
+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(arbitrary_self_types, futures_api, pin)]
+#![allow(unused)]
+
+use std::boxed::PinBox;
+use std::future::Future;
+use std::mem::PinMut;
+use std::rc::Rc;
+use std::sync::{
+ Arc,
+ atomic::{self, AtomicUsize},
+};
+use std::task::{
+ Context, Poll,
+ Wake, Waker, LocalWaker,
+ Executor, TaskObj, SpawnObjError,
+ local_waker, local_waker_from_nonlocal,
+};
+
+struct Counter {
+ local_wakes: AtomicUsize,
+ nonlocal_wakes: AtomicUsize,
+}
+
+impl Wake for Counter {
+ fn wake(this: &Arc<Self>) {
+ this.nonlocal_wakes.fetch_add(1, atomic::Ordering::SeqCst);
+ }
+
+ unsafe fn wake_local(this: &Arc<Self>) {
+ this.local_wakes.fetch_add(1, atomic::Ordering::SeqCst);
+ }
+}
+
+struct NoopExecutor;
+
+impl Executor for NoopExecutor {
+ fn spawn_obj(&mut self, _: TaskObj) -> Result<(), SpawnObjError> {
+ Ok(())
+ }
+}
+
+struct MyFuture;
+
+impl Future for MyFuture {
+ type Output = ();
+ fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
+ // Ensure all the methods work appropriately
+ cx.waker().wake();
+ cx.waker().wake();
+ cx.local_waker().wake();
+ cx.executor().spawn_obj(PinBox::new(MyFuture).into()).unwrap();
+ Poll::Ready(())
+ }
+}
+
+fn test_local_waker() {
+ let counter = Arc::new(Counter {
+ local_wakes: AtomicUsize::new(0),
+ nonlocal_wakes: AtomicUsize::new(0),
+ });
+ let waker = unsafe { local_waker(counter.clone()) };
+ let executor = &mut NoopExecutor;
+ let cx = &mut Context::new(&waker, executor);
+ assert_eq!(Poll::Ready(()), PinMut::new(&mut MyFuture).poll(cx));
+ assert_eq!(1, counter.local_wakes.load(atomic::Ordering::SeqCst));
+ assert_eq!(2, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst));
+}
+
+fn test_local_as_nonlocal_waker() {
+ let counter = Arc::new(Counter {
+ local_wakes: AtomicUsize::new(0),
+ nonlocal_wakes: AtomicUsize::new(0),
+ });
+ let waker: LocalWaker = local_waker_from_nonlocal(counter.clone());
+ let executor = &mut NoopExecutor;
+ let cx = &mut Context::new(&waker, executor);
+ assert_eq!(Poll::Ready(()), PinMut::new(&mut MyFuture).poll(cx));
+ assert_eq!(0, counter.local_wakes.load(atomic::Ordering::SeqCst));
+ assert_eq!(3, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst));
+}
+
+fn main() {
+ test_local_waker();
+ test_local_as_nonlocal_waker();
+}
} }
}
+macro_rules! baz {
+ ($($a:ident),? ; $num:expr) => { { // comma separator is meaningless for `?`
+ let mut x = 0;
+
+ $(
+ x += $a;
+ )?
+
+ assert_eq!(x, $num);
+ } }
+}
+
macro_rules! barplus {
($($a:ident)?+ ; $num:expr) => { {
let mut x = 0;
$(
x += $a;
- )?
+ )+
assert_eq!(x, $num);
} }
$(
x += $a;
- )?
+ )*
assert_eq!(x, $num);
} }
// accept 0 or 1 repetitions
foo!( ; 0);
foo!(a ; 1);
+ baz!( ; 0);
+ baz!(a ; 1);
// Make sure using ? as a separator works as before
- barplus!(+ ; 0);
- barplus!(a + ; 1);
- barstar!(* ; 0);
- barstar!(a * ; 1);
+ barplus!(a ; 1);
+ barplus!(a?a ; 2);
+ barplus!(a?a?a ; 3);
+ barstar!( ; 0);
+ barstar!(a ; 1);
+ barstar!(a?a ; 2);
+ barstar!(a?a?a ; 3);
}
#[path = "auxiliary"]
mod foo {
- mod two_macros;
+ mod two_macros_2;
}
#[path = "auxiliary"]
mod bar {
- macro_rules! m { () => { mod two_macros; } }
+ macro_rules! m { () => { mod two_macros_2; } }
m!();
}
}
// ignore-mips64
// ignore-powerpc
// ignore-s390x
+// ignore-sparc
+// ignore-sparc64
// ignore-wasm
// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-mips64
// ignore-powerpc
// ignore-s390x
+// ignore-sparc
+// ignore-sparc64
// ignore-wasm
// ignore-cloudabi no processes
// ignore-emscripten no processes
--- /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.
+
+// Test that duplicate auto trait bounds in trait objects don't create new types.
+#[allow(unused_assignments)]
+
+use std::marker::Send as SendAlias;
+
+// A dummy trait for the non-auto trait.
+trait Trait {}
+
+// A dummy struct to implement Trait, Send, and .
+struct Struct;
+
+impl Trait for Struct {}
+
+// These three functions should be equivalent.
+fn takes_dyn_trait_send(_: Box<dyn Trait + Send>) {}
+fn takes_dyn_trait_send_send(_: Box<dyn Trait + Send + Send>) {}
+fn takes_dyn_trait_send_sendalias(_: Box<dyn Trait + Send + SendAlias>) {}
+
+impl dyn Trait + Send + Send {
+ fn do_nothing(&self) {}
+}
+
+fn main() {
+ // 1. Moving into a variable with more Sends and back.
+ let mut dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
+ let dyn_trait_send_send: Box<dyn Trait + Send + Send> = dyn_trait_send;
+ dyn_trait_send = dyn_trait_send_send;
+
+ // 2. Calling methods with different number of Sends.
+ let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
+ takes_dyn_trait_send_send(dyn_trait_send);
+
+ let dyn_trait_send_send = Box::new(Struct) as Box<dyn Trait + Send + Send>;
+ takes_dyn_trait_send(dyn_trait_send_send);
+
+ // 3. Aliases to the trait are transparent.
+ let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
+ takes_dyn_trait_send_sendalias(dyn_trait_send);
+
+ // 4. Calling an impl that duplicates an auto trait.
+ let dyn_trait_send = Box::new(Struct) as Box<dyn Trait + Send>;
+ dyn_trait_send.do_nothing();
+}
// compile-pass
-//! Test with [Foo::baz], [Bar::foo], ...
-//!
-//! and [Uniooon::X].
+ //! Test with [Foo::baz], [Bar::foo], ...
+ //! , [Uniooon::X] and [Qux::Z].
+ //!
+ //! , [Uniooon::X] and [Qux::Z].
+ /// [Qux:Y]
pub struct Foo {
pub bar: usize,
}
+
+/// Foo
+/// bar [BarA] bar
+/// baz
+pub fn a() {}
+
+/**
+ * Foo
+ * bar [BarB] bar
+ * baz
+ */
+pub fn b() {}
+
+/** Foo
+
+bar [BarC] bar
+baz
+
+ let bar_c_1 = 0;
+ let bar_c_2 = 0;
+ let g = [bar_c_1];
+ let h = g[bar_c_2];
+
+*/
+pub fn c() {}
+
+#[doc = "Foo\nbar [BarD] bar\nbaz"]
+pub fn d() {}
+
+macro_rules! f {
+ ($f:expr) => {
+ #[doc = $f]
+ pub fn f() {}
+ }
+}
+f!("Foo\nbar [BarF] bar\nbaz");
-warning: [Foo::baz] cannot be resolved, ignoring it...
- --> $DIR/intra-links-warning.rs:13:1
+warning: `[Foo::baz]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:13:23
|
-13 | / //! Test with [Foo::baz], [Bar::foo], ...
-14 | | //!
-15 | | //! and [Uniooon::X].
- | |_____________________^
+13 | //! Test with [Foo::baz], [Bar::foo], ...
+ | ^^^^^^^^ cannot be resolved, ignoring
+
+warning: `[Bar::foo]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:13:35
+ |
+13 | //! Test with [Foo::baz], [Bar::foo], ...
+ | ^^^^^^^^ cannot be resolved, ignoring
+
+warning: `[Uniooon::X]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:14:13
+ |
+14 | //! , [Uniooon::X] and [Qux::Z].
+ | ^^^^^^^^^^ cannot be resolved, ignoring
+
+warning: `[Qux::Z]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:14:30
+ |
+14 | //! , [Uniooon::X] and [Qux::Z].
+ | ^^^^^^ cannot be resolved, ignoring
+
+warning: `[Uniooon::X]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:16:14
+ |
+16 | //! , [Uniooon::X] and [Qux::Z].
+ | ^^^^^^^^^^ cannot be resolved, ignoring
+
+warning: `[Qux::Z]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:16:31
+ |
+16 | //! , [Uniooon::X] and [Qux::Z].
+ | ^^^^^^ cannot be resolved, ignoring
+
+warning: `[Qux:Y]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:18:13
+ |
+18 | /// [Qux:Y]
+ | ^^^^^ cannot be resolved, ignoring
+
+warning: `[BarA]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:24:10
+ |
+24 | /// bar [BarA] bar
+ | ^^^^ cannot be resolved, ignoring
+
+warning: `[BarB]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:28:1
+ |
+28 | / /**
+29 | | * Foo
+30 | | * bar [BarB] bar
+31 | | * baz
+32 | | */
+ | |___^
+ |
+ = note: the link appears in this line:
+
+ bar [BarB] bar
+ ^^^^
+
+warning: `[BarC]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:35:1
+ |
+35 | / /** Foo
+36 | |
+37 | | bar [BarC] bar
+38 | | baz
+... |
+44 | |
+45 | | */
+ | |__^
|
= note: the link appears in this line:
- Test with [Foo::baz], [Bar::foo], ...
- ^^^^^^^^
+ bar [BarC] bar
+ ^^^^
-warning: [Bar::foo] cannot be resolved, ignoring it...
- --> $DIR/intra-links-warning.rs:13:1
+warning: `[BarD]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:48:1
|
-13 | / //! Test with [Foo::baz], [Bar::foo], ...
-14 | | //!
-15 | | //! and [Uniooon::X].
- | |_____________________^
+48 | #[doc = "Foo/nbar [BarD] bar/nbaz"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the link appears in this line:
- Test with [Foo::baz], [Bar::foo], ...
- ^^^^^^^^
+ bar [BarD] bar
+ ^^^^
-warning: [Uniooon::X] cannot be resolved, ignoring it...
- --> $DIR/intra-links-warning.rs:13:1
+warning: `[BarF]` cannot be resolved, ignoring it...
+ --> $DIR/intra-links-warning.rs:53:9
|
-13 | / //! Test with [Foo::baz], [Bar::foo], ...
-14 | | //!
-15 | | //! and [Uniooon::X].
- | |_____________________^
+53 | #[doc = $f]
+ | ^^^^^^^^^^^
+...
+57 | f!("Foo/nbar [BarF] bar/nbaz");
+ | ------------------------------- in this macro invocation
|
= note: the link appears in this line:
- and [Uniooon::X].
- ^^^^^^^^^^
+ bar [BarF] bar
+ ^^^^
--- /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(staged_api)]
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+/// docs for my_macro
+#[unstable(feature = "macro_test", issue = "0")]
+#[rustc_deprecated(since = "1.2.3", reason = "text")]
+#[macro_export]
+macro_rules! my_macro {
+ () => ()
+}
--- /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:macros.rs
+// build-aux-docs
+
+#![feature(macro_test)]
+#![feature(use_extern_macros)]
+
+#![crate_name = "foo"]
+
+extern crate macros;
+
+// @has foo/index.html '//*[@class="docblock-short"]' '[Deprecated] [Experimental]'
+
+// @has foo/macro.my_macro.html
+// @has - '//*[@class="docblock"]' 'docs for my_macro'
+// @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.2.3: text'
+// @has - '//*[@class="stab unstable"]' 'macro_test'
+// @has - '//a/@href' '../src/macros/macros.rs.html#19-21'
+pub use macros::my_macro;
--- /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: --crate-name foo
+
+pub 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.
+
+#![crate_name = "foo"]
+
+#![feature(doc_keyword)]
+
+// @has foo/index.html '//h2[@id="keywords"]' 'Keywords'
+// @has foo/index.html '//a[@href="keyword.match.html"]' 'match'
+// @has foo/keyword.match.html '//a[@class="keyword"]' 'match'
+// @has foo/keyword.match.html '//section[@id="main"]//div[@class="docblock"]//p' 'this is a test!'
+// @!has foo/index.html '//a/@href' 'foo/index.html'
+// @!has foo/foo/index.html
+// @!has-dir foo/foo
+#[doc(keyword = "match")]
+/// this is a test!
+mod foo{}
// ignore-emscripten
// ignore-powerpc
// ignore-sparc
+// ignore-sparc64
// ignore-mips
#![feature(asm)]
error[E0384]: cannot assign twice to immutable variable `x`
- --> $DIR/asm-out-assign-imm.rs:30:9
+ --> $DIR/asm-out-assign-imm.rs:31:9
|
LL | x = 1;
| ----- first assignment to `x`
--- /dev/null
+error[E0596]: cannot borrow immutable item `b` as mutable
+ --> $DIR/mut-borrow-of-mut-ref.rs:18:7
+ |
+LL | g(&mut b) //~ ERROR cannot borrow
+ | ^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
--- /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.
+
+// Suggest not mutably borrowing a mutable reference
+
+fn main() {
+ f(&mut 0)
+}
+
+fn f(b: &mut i32) {
+ g(&mut b) //~ ERROR cannot borrow
+}
+
+fn g(_: &mut i32) {}
--- /dev/null
+error[E0596]: cannot borrow immutable argument `b` as mutable
+ --> $DIR/mut-borrow-of-mut-ref.rs:18:12
+ |
+LL | g(&mut b) //~ ERROR cannot borrow
+ | ^ cannot borrow mutably
+help: consider removing the `&mut`, as it is an immutable binding to a mutable reference
+ |
+LL | g(b) //~ ERROR cannot borrow
+ | ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
const NEG_128: i8 = -128;
const NEG_NEG_128: i8 = -NEG_128;
-//~^ ERROR E0080
fn main() {
match -128i8 {
NEG_NEG_128 => println!("A"),
+ //~^ ERROR could not evaluate constant pattern
_ => println!("B"),
}
}
-error[E0080]: constant evaluation error
- --> $DIR/const-eval-overflow-2.rs:21:25
+error[E0080]: could not evaluate constant pattern
+ --> $DIR/const-eval-overflow-2.rs:25:9
|
LL | const NEG_NEG_128: i8 = -NEG_128;
- | ^^^^^^^^ attempt to negate with overflow
- |
-note: for pattern here
- --> $DIR/const-eval-overflow-2.rs:26:9
- |
+ | -------- attempt to negate with overflow
+...
LL | NEG_NEG_128 => println!("A"),
| ^^^^^^^^^^^
use std::{u8, u16, u32, u64, usize};
const A_I8_T
+ //~^ ERROR could not evaluate constant expression
: [u32; (i8::MAX as i8 + 1i8) as usize]
- //~^ ERROR E0080
- //~| ERROR attempt to add with overflow
+ //~^ ERROR attempt to add with overflow
= [0; (i8::MAX as usize) + 1];
fn main() {
error: attempt to add with overflow
- --> $DIR/const-eval-overflow-4.rs:23:13
+ --> $DIR/const-eval-overflow-4.rs:24:13
|
LL | : [u32; (i8::MAX as i8 + 1i8) as usize]
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: #[deny(const_err)] on by default
-error[E0080]: constant evaluation error
- --> $DIR/const-eval-overflow-4.rs:23:13
+error[E0080]: could not evaluate constant expression
+ --> $DIR/const-eval-overflow-4.rs:22:1
|
-LL | : [u32; (i8::MAX as i8 + 1i8) as usize]
- | ^^^^^^^^^^^^^^^^^^^^^ attempt to add with overflow
+LL | / const A_I8_T
+LL | | //~^ ERROR could not evaluate constant expression
+LL | | : [u32; (i8::MAX as i8 + 1i8) as usize]
+ | | --------------------- attempt to add with overflow
+LL | | //~^ ERROR attempt to add with overflow
+LL | | = [0; (i8::MAX as usize) + 1];
+ | |__________________________________^
error: aborting due to 2 previous errors
--- /dev/null
+warning: attempt to subtract with overflow
+ --> $DIR/conditional_array_execution.rs:15:19
+ |
+LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
+ | ^^^^^
+ |
+note: lint level defined here
+ --> $DIR/conditional_array_execution.rs:11:9
+ |
+LL | #![warn(const_err)]
+ | ^^^^^^^^^
+
+warning: this constant cannot be used
+ --> $DIR/conditional_array_execution.rs:15:1
+ |
+LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
+ | ^^^^^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | attempt to subtract with overflow
+
+warning: referenced constant
+ --> $DIR/conditional_array_execution.rs:20:20
+ |
+LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
+ | ----- attempt to subtract with overflow
+...
+LL | println!("{}", FOO);
+ | ^^^
+
+warning: this expression will panic at runtime
+ --> $DIR/conditional_array_execution.rs:20:20
+ |
+LL | println!("{}", FOO);
+ | ^^^ referenced constant has errors
+
+error[E0080]: referenced constant
+ --> $DIR/conditional_array_execution.rs:20:5
+ |
+LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
+ | ----- attempt to subtract with overflow
+...
+LL | println!("{}", FOO);
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = 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[E0080]: erroneous constant used
+ --> $DIR/conditional_array_execution.rs:20:5
+ |
+LL | println!("{}", FOO);
+ | ^^^^^^^^^^^^^^^---^^
+ | |
+ | referenced constant has errors
+ |
+ = 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[E0080]: referenced constant
+ --> $DIR/conditional_array_execution.rs:20:20
+ |
+LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
+ | ----- attempt to subtract with overflow
+...
+LL | println!("{}", FOO);
+ | ^^^
+
+error[E0080]: erroneous constant used
+ --> $DIR/conditional_array_execution.rs:20:20
+ |
+LL | println!("{}", FOO);
+ | ^^^ referenced constant has errors
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-pass
#![warn(const_err)]
const X: u32 = 5;
fn main() {
println!("{}", FOO);
- //~^ WARN constant evaluation error
+ //~^ WARN this expression will panic at runtime
+ //~| WARN referenced constant
+ //~| ERROR erroneous constant used
+ //~| E0080
}
warning: attempt to subtract with overflow
- --> $DIR/conditional_array_execution.rs:16:19
+ --> $DIR/conditional_array_execution.rs:15:19
|
LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
| ^^^^^
|
note: lint level defined here
- --> $DIR/conditional_array_execution.rs:12:9
+ --> $DIR/conditional_array_execution.rs:11:9
|
LL | #![warn(const_err)]
| ^^^^^^^^^
warning: this constant cannot be used
- --> $DIR/conditional_array_execution.rs:16:1
+ --> $DIR/conditional_array_execution.rs:15:1
|
LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | attempt to subtract with overflow
-warning: constant evaluation error
- --> $DIR/conditional_array_execution.rs:21:20
+warning: referenced constant
+ --> $DIR/conditional_array_execution.rs:20:20
+ |
+LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
+ | ----- attempt to subtract with overflow
+...
+LL | println!("{}", FOO);
+ | ^^^
+
+warning: this expression will panic at runtime
+ --> $DIR/conditional_array_execution.rs:20:20
|
LL | println!("{}", FOO);
| ^^^ referenced constant has errors
+error[E0080]: referenced constant
+ --> $DIR/conditional_array_execution.rs:20:20
+ |
+LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
+ | ----- attempt to subtract with overflow
+...
+LL | println!("{}", FOO);
+ | ^^^
+
+error[E0080]: erroneous constant used
+ --> $DIR/conditional_array_execution.rs:20:20
+ |
+LL | println!("{}", FOO);
+ | ^^^ referenced constant has errors
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
+++ /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.
-
-static FOO: i32 = [][0];
-//~^ ERROR E0080
-
-fn main() {}
+++ /dev/null
-error[E0080]: constant evaluation error
- --> $DIR/index_out_of_bound.rs:11:19
- |
-LL | static FOO: i32 = [][0];
- | ^^^^^ index out of bounds: the len is 0 but the index is 0
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0080`.
--- /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.
+
+static FOO: i32 = [][0];
+//~^ ERROR E0080
+//~| ERROR E0080
+
+fn main() {
+ let array = [std::env::args().len()];
+ array[1]; //~ ERROR index out of bounds
+}
--- /dev/null
+error[E0080]: could not evaluate static initializer
+ --> $DIR/index_out_of_bounds.rs:11:19
+ |
+LL | static FOO: i32 = [][0];
+ | ^^^^^ index out of bounds: the len is 0 but the index is 0
+
+error[E0080]: could not evaluate static initializer
+ --> $DIR/index_out_of_bounds.rs:11:1
+ |
+LL | static FOO: i32 = [][0];
+ | ^^^^^^^^^^^^^^^^^^-----^
+ | |
+ | index out of bounds: the len is 0 but the index is 0
+
+error: index out of bounds: the len is 1 but the index is 1
+ --> $DIR/index_out_of_bounds.rs:17:5
+ |
+LL | array[1]; //~ ERROR index out of bounds
+ | ^^^^^^^^
+ |
+ = note: #[deny(const_err)] on by default
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+warning: attempt to subtract with overflow
+ --> $DIR/issue-43197.rs:20:20
+ |
+LL | const X: u32 = 0-1;
+ | ^^^
+ |
+note: lint level defined here
+ --> $DIR/issue-43197.rs:11:9
+ |
+LL | #![warn(const_err)]
+ | ^^^^^^^^^
+
+warning: this constant cannot be used
+ --> $DIR/issue-43197.rs:20:5
+ |
+LL | const X: u32 = 0-1;
+ | ^^^^^^^^^^^^^^^---^
+ | |
+ | attempt to subtract with overflow
+
+warning: attempt to subtract with overflow
+ --> $DIR/issue-43197.rs:23:24
+ |
+LL | const Y: u32 = foo(0-1);
+ | ^^^
+
+warning: this constant cannot be used
+ --> $DIR/issue-43197.rs:23:5
+ |
+LL | const Y: u32 = foo(0-1);
+ | ^^^^^^^^^^^^^^^^^^^---^^
+ | |
+ | attempt to subtract with overflow
+
+warning: referenced constant
+ --> $DIR/issue-43197.rs:26:23
+ |
+LL | const X: u32 = 0-1;
+ | --- attempt to subtract with overflow
+...
+LL | println!("{} {}", X, Y);
+ | ^
+
+warning: this expression will panic at runtime
+ --> $DIR/issue-43197.rs:26:23
+ |
+LL | println!("{} {}", X, Y);
+ | ^ referenced constant has errors
+
+warning: referenced constant
+ --> $DIR/issue-43197.rs:26:26
+ |
+LL | const Y: u32 = foo(0-1);
+ | --- attempt to subtract with overflow
+...
+LL | println!("{} {}", X, Y);
+ | ^
+
+warning: this expression will panic at runtime
+ --> $DIR/issue-43197.rs:26:26
+ |
+LL | println!("{} {}", X, Y);
+ | ^ referenced constant has errors
+
+error[E0080]: referenced constant
+ --> $DIR/issue-43197.rs:26:5
+ |
+LL | const X: u32 = 0-1;
+ | --- attempt to subtract with overflow
+...
+LL | println!("{} {}", X, Y);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = 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[E0080]: erroneous constant used
+ --> $DIR/issue-43197.rs:26:5
+ |
+LL | println!("{} {}", X, Y);
+ | ^^^^^^^^^^^^^^^^^^-^^^^^
+ | |
+ | referenced constant has errors
+ |
+ = 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[E0080]: referenced constant
+ --> $DIR/issue-43197.rs:26:26
+ |
+LL | const Y: u32 = foo(0-1);
+ | --- attempt to subtract with overflow
+...
+LL | println!("{} {}", X, Y);
+ | ^
+
+error[E0080]: erroneous constant used
+ --> $DIR/issue-43197.rs:26:26
+ |
+LL | println!("{} {}", X, Y);
+ | ^ referenced constant has errors
+
+error[E0080]: referenced constant
+ --> $DIR/issue-43197.rs:26:23
+ |
+LL | const X: u32 = 0-1;
+ | --- attempt to subtract with overflow
+...
+LL | println!("{} {}", X, Y);
+ | ^
+
+error[E0080]: erroneous constant used
+ --> $DIR/issue-43197.rs:26:23
+ |
+LL | println!("{} {}", X, Y);
+ | ^ referenced constant has errors
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-pass
#![warn(const_err)]
#![feature(const_fn)]
//~^ WARN attempt to subtract with overflow
//~| WARN this constant cannot be used
println!("{} {}", X, Y);
- //~^ WARN constant evaluation error
- //~| WARN constant evaluation error
+ //~^ WARN this expression will panic at runtime
+ //~| WARN this expression will panic at runtime
+ //~| ERROR erroneous constant used
+ //~| ERROR erroneous constant used
+ //~| ERROR E0080
+ //~| ERROR E0080
+ //~| WARN referenced constant
+ //~| WARN referenced constant
}
warning: attempt to subtract with overflow
- --> $DIR/issue-43197.rs:21:20
+ --> $DIR/issue-43197.rs:20:20
|
LL | const X: u32 = 0-1;
| ^^^
|
note: lint level defined here
- --> $DIR/issue-43197.rs:12:9
+ --> $DIR/issue-43197.rs:11:9
|
LL | #![warn(const_err)]
| ^^^^^^^^^
warning: this constant cannot be used
- --> $DIR/issue-43197.rs:21:5
+ --> $DIR/issue-43197.rs:20:5
|
LL | const X: u32 = 0-1;
- | ^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^^^^^^^---^
+ | |
+ | attempt to subtract with overflow
warning: attempt to subtract with overflow
- --> $DIR/issue-43197.rs:24:24
+ --> $DIR/issue-43197.rs:23:24
|
LL | const Y: u32 = foo(0-1);
| ^^^
warning: this constant cannot be used
- --> $DIR/issue-43197.rs:24:5
+ --> $DIR/issue-43197.rs:23:5
|
LL | const Y: u32 = foo(0-1);
- | ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^^^^^^^^^^^---^^
+ | |
+ | attempt to subtract with overflow
-warning: constant evaluation error
- --> $DIR/issue-43197.rs:27:23
+warning: referenced constant
+ --> $DIR/issue-43197.rs:26:23
+ |
+LL | const X: u32 = 0-1;
+ | --- attempt to subtract with overflow
+...
+LL | println!("{} {}", X, Y);
+ | ^
+
+warning: this expression will panic at runtime
+ --> $DIR/issue-43197.rs:26:23
|
LL | println!("{} {}", X, Y);
| ^ referenced constant has errors
-warning: constant evaluation error
- --> $DIR/issue-43197.rs:27:26
+warning: referenced constant
+ --> $DIR/issue-43197.rs:26:26
+ |
+LL | const Y: u32 = foo(0-1);
+ | --- attempt to subtract with overflow
+...
+LL | println!("{} {}", X, Y);
+ | ^
+
+warning: this expression will panic at runtime
+ --> $DIR/issue-43197.rs:26:26
|
LL | println!("{} {}", X, Y);
| ^ referenced constant has errors
+error[E0080]: referenced constant
+ --> $DIR/issue-43197.rs:26:26
+ |
+LL | const Y: u32 = foo(0-1);
+ | --- attempt to subtract with overflow
+...
+LL | println!("{} {}", X, Y);
+ | ^
+
+error[E0080]: erroneous constant used
+ --> $DIR/issue-43197.rs:26:26
+ |
+LL | println!("{} {}", X, Y);
+ | ^ referenced constant has errors
+
+error[E0080]: referenced constant
+ --> $DIR/issue-43197.rs:26:23
+ |
+LL | const X: u32 = 0-1;
+ | --- attempt to subtract with overflow
+...
+LL | println!("{} {}", X, Y);
+ | ^
+
+error[E0080]: erroneous constant used
+ --> $DIR/issue-43197.rs:26:23
+ |
+LL | println!("{} {}", X, Y);
+ | ^ referenced constant has errors
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+error[E0080]: referenced constant
+ --> $DIR/issue-44578.rs:35:5
+ |
+LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
+ | ------------------------------------ index out of bounds: the len is 1 but the index is 1
+...
+LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = 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[E0080]: erroneous constant used
+ --> $DIR/issue-44578.rs:35:5
+ |
+LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
+ | ^^^^^^^^^^^^^^^--------------------------^^
+ | |
+ | referenced constant has errors
+ |
+ = 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[E0080]: referenced constant
+ --> $DIR/issue-44578.rs:35:20
+ |
+LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
+ | ------------------------------------ index out of bounds: the len is 1 but the index is 1
+...
+LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: erroneous constant used
+ --> $DIR/issue-44578.rs:35:20
+ |
+LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-pass
-#![warn(const_err)]
+#![allow(const_err)]
trait Foo {
const AMT: usize;
}
fn main() {
- println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
- //~^ WARN const_err
+ println!("{}", <Bar<u16, u8> as Foo>::AMT);
+ //~^ ERROR erroneous constant used
+ //~| ERROR E0080
}
-warning: constant evaluation error
- --> $DIR/issue-44578.rs:36:20
+error[E0080]: referenced constant
+ --> $DIR/issue-44578.rs:35:20
|
-LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
- |
-note: lint level defined here
- --> $DIR/issue-44578.rs:12:9
- |
-LL | #![warn(const_err)]
- | ^^^^^^^^^
+LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
+ | ------------------------------------ index out of bounds: the len is 1 but the index is 1
+...
+LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-warning: constant evaluation error
- --> $DIR/issue-44578.rs:36:20
+error[E0080]: erroneous constant used
+ --> $DIR/issue-44578.rs:35:20
|
-LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
+LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /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.
+
+trait C {
+ const BOO: usize;
+}
+
+trait Foo<T> {
+ const BAR: usize;
+}
+
+struct A<T>(T);
+
+impl<T: C> Foo<T> for A<T> {
+ const BAR: usize = [5, 6, 7][T::BOO];
+}
+
+fn foo<T: C>() -> &'static usize {
+ &<A<T> as Foo<T>>::BAR //~ ERROR erroneous constant used
+//~| ERROR E0080
+}
+
+impl C for () {
+ const BOO: usize = 42;
+}
+
+impl C for u32 {
+ const BOO: usize = 1;
+}
+
+fn main() {
+ println!("{:x}", foo::<()>() as *const usize as usize);
+ println!("{:x}", foo::<u32>() as *const usize as usize);
+ println!("{:x}", foo::<()>());
+ println!("{:x}", foo::<u32>());
+}
--- /dev/null
+error[E0080]: referenced constant
+ --> $DIR/issue-50814-2.rs:26:5
+ |
+LL | const BAR: usize = [5, 6, 7][T::BOO];
+ | ----------------- index out of bounds: the len is 3 but the index is 42
+...
+LL | &<A<T> as Foo<T>>::BAR //~ ERROR erroneous constant used
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: erroneous constant used
+ --> $DIR/issue-50814-2.rs:26:5
+ |
+LL | &<A<T> as Foo<T>>::BAR //~ ERROR erroneous constant used
+ | ^---------------------
+ | |
+ | referenced constant has errors
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /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.
+
+trait Unsigned {
+ const MAX: u8;
+}
+
+struct U8(u8);
+impl Unsigned for U8 {
+ const MAX: u8 = 0xff;
+}
+
+struct Sum<A,B>(A,B);
+
+impl<A: Unsigned, B: Unsigned> Unsigned for Sum<A,B> {
+ const MAX: u8 = A::MAX + B::MAX;
+}
+
+fn foo<T>(_: T) -> &'static u8 {
+ &Sum::<U8,U8>::MAX //~ ERROR erroneous constant used
+//~| ERROR E0080
+}
+
+fn main() {
+ foo(0);
+}
--- /dev/null
+error[E0080]: referenced constant
+ --> $DIR/issue-50814.rs:27:5
+ |
+LL | const MAX: u8 = A::MAX + B::MAX;
+ | --------------- attempt to add with overflow
+...
+LL | &Sum::<U8,U8>::MAX //~ ERROR erroneous constant used
+ | ^^^^^^^^^^^^^^^^^^
+
+error[E0080]: erroneous constant used
+ --> $DIR/issue-50814.rs:27:5
+ |
+LL | &Sum::<U8,U8>::MAX //~ ERROR erroneous constant used
+ | ^-----------------
+ | |
+ | referenced constant has errors
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /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
+// https://github.com/rust-lang/rust/issues/51300
+
+#[derive(PartialEq, Eq, Clone, Copy)]
+pub struct Stat {
+ pub id: u8,
+ pub index: usize,
+}
+
+impl Stat {
+ pub const STUDENT_HAPPINESS: Stat = Stat{
+ id: 0,
+ index: 0,
+ };
+ pub const STUDENT_HUNGER: Stat = Stat{
+ id: 0,
+ index: Self::STUDENT_HAPPINESS.index + 1,
+ };
+
+}
+
+pub fn from_index(id: u8, index: usize) -> Option<Stat> {
+ let stat = Stat{id, index};
+ match stat {
+ Stat::STUDENT_HAPPINESS => Some(Stat::STUDENT_HAPPINESS),
+ Stat::STUDENT_HUNGER => Some(Stat::STUDENT_HUNGER),
+ _ => None,
+ }
+}
+
+fn main() { }
// is run on a system whose pointers need more
// than 8 bits
Bar { a: &42 }.b as u8
- //~^ constant evaluation error
- //~| constant evaluation error
+ //~^ ERROR this expression will panic at runtime
+ //~| ERROR this expression will panic at runtime
}
}
-error: constant evaluation error
+error: this expression will panic at runtime
--> $DIR/promoted_const_fn_fail.rs:25:9
|
LL | Bar { a: &42 }.b as u8
|
LL | #![deny(const_err)]
| ^^^^^^^^^
-note: inside call to `bar`
- --> $DIR/promoted_const_fn_fail.rs:35:28
- |
-LL | let x: &'static u8 = &(bar() + 1);
- | ^^^^^
-error: constant evaluation error
+error: this expression will panic at runtime
--> $DIR/promoted_const_fn_fail.rs:25:9
|
LL | Bar { a: &42 }.b as u8
| ^^^^^^^^^^^^^^^^^^^^^^ a raw memory access tried to access part of a pointer value as raw bytes
- |
-note: inside call to `bar`
- --> $DIR/promoted_const_fn_fail.rs:35:28
- |
-LL | let x: &'static u8 = &(bar() + 1);
- | ^^^^^
error: aborting due to 2 previous errors
-warning: constant evaluation error
+warning: this expression will panic at runtime
--> $DIR/promoted_errors.rs:17:14
|
LL | let _x = 0u32 - 1;
LL | println!("{}", 1/(1-1));
| ^^^^^^^
-warning: constant evaluation error
+warning: this expression will panic at runtime
--> $DIR/promoted_errors.rs:19:20
|
LL | println!("{}", 1/(1-1));
LL | let _x = 1/(1-1);
| ^^^^^^^
-warning: constant evaluation error
+warning: this expression will panic at runtime
--> $DIR/promoted_errors.rs:22:14
|
LL | let _x = 1/(1-1);
| ^^^^^^^ attempt to divide by zero
-warning: constant evaluation error
+warning: this expression will panic at runtime
--> $DIR/promoted_errors.rs:25:20
|
LL | println!("{}", 1/(false as u32));
--> $DIR/pub_const_err.rs:16:1
|
LL | pub const Z: u32 = 0 - 1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^^^^^^^^^^^-----^
+ | |
+ | attempt to subtract with overflow
warning: attempt to subtract with overflow
--> $DIR/pub_const_err.rs:20:22
--> $DIR/pub_const_err_bin.rs:14:1
|
LL | pub const Z: u32 = 0 - 1;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ | ^^^^^^^^^^^^^^^^^^^-----^
+ | |
+ | attempt to subtract with overflow
warning: attempt to subtract with overflow
--> $DIR/pub_const_err_bin.rs:18:22
for i in 0..x {
//~^ ERROR E0015
//~| ERROR E0019
- //~| ERROR E0080
sum += i;
}
sum
#[allow(unused_variables)]
fn main() {
- let a : [i32; f(X)];
+ let a : [i32; f(X)]; //~ ERROR E0080
}
LL | for i in 0..x {
| ^^^^
-error[E0080]: constant evaluation error
- --> $DIR/const-fn-error.rs:19:14
+error[E0080]: could not evaluate constant expression
+ --> $DIR/const-fn-error.rs:29:13
|
LL | for i in 0..x {
- | ^^^^ calling non-const fn `<I as std::iter::IntoIterator><std::ops::Range<usize>>::into_iter`
+ | ---- calling non-const fn `<I as std::iter::IntoIterator><std::ops::Range<usize>>::into_iter`
...
-LL | let a : [i32; f(X)];
- | ---- inside call to `f`
- |
-note: for constant expression here
- --> $DIR/const-fn-error.rs:30:13
- |
-LL | let a : [i32; f(X)];
- | ^^^^^^^^^^^
+LL | let a : [i32; f(X)]; //~ ERROR E0080
+ | ^^^^^^----^
+ | |
+ | inside call to `f`
error: aborting due to 5 previous errors
fn main() {
let a: [i8; LEN] = unimplemented!();
//~^ ERROR E0080
+//~| ERROR E0080
}
LL | const LEN: usize = ONE - TWO;
| ^^^^^^^^^ attempt to subtract with overflow
-error[E0080]: constant evaluation error
- --> $DIR/const-len-underflow-separate-spans.rs:22:17
+error[E0080]: referenced constant
+ --> $DIR/const-len-underflow-separate-spans.rs:22:12
+ |
+LL | const LEN: usize = ONE - TWO;
+ | --------- attempt to subtract with overflow
+...
+LL | let a: [i8; LEN] = unimplemented!();
+ | ^^^^^^^^^
+
+error[E0080]: could not evaluate constant expression
+ --> $DIR/const-len-underflow-separate-spans.rs:22:12
|
LL | let a: [i8; LEN] = unimplemented!();
- | ^^^ referenced constant has errors
+ | ^^^^^---^
+ | |
+ | referenced constant has errors
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0080`.
error[E0596]: cannot borrow immutable argument `self` as mutable
--> $DIR/issue-31424.rs:23:15
|
-LL | fn bar(self: &mut Self) {
- | --------------- consider changing this to `mut self: &mut Self`
LL | (&mut self).bar(); //~ ERROR cannot borrow
| ^^^^ cannot borrow mutably
+help: consider removing the `&mut`, as it is an immutable binding to a mutable reference
+ |
+LL | self.bar(); //~ ERROR cannot borrow
+ | ^^^^
error: aborting due to 2 previous errors
|
= note: #[deny(exceeding_bitshifts)] on by default
-error[E0080]: constant evaluation error
+error[E0080]: could not evaluate enum discriminant
--> $DIR/E0080.rs:12:9
|
LL | X = (1 << 500), //~ ERROR E0080
|
= note: #[deny(const_err)] on by default
-error: constant evaluation error
+error: this expression will panic at runtime
--> $DIR/E0080.rs:14:9
|
LL | Y = (1 / 0) //~ ERROR E0080
| ^^^^^^^ attempt to divide by zero
-error[E0080]: constant evaluation error
+error[E0080]: could not evaluate enum discriminant
--> $DIR/E0080.rs:14:9
|
LL | Y = (1 / 0) //~ ERROR E0080
let f = Foo(); //~ ERROR E0423
}
+
+fn bar() {
+ struct S { x: i32, y: i32 }
+ #[derive(PartialEq)]
+ struct T {}
+
+ if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
+ //~^ ERROR E0423
+ //~| expected type, found `1`
+ if T {} == T {} { println!("Ok"); }
+ //~^ ERROR E0423
+ //~| ERROR expected expression, found `==`
+}
+
+fn foo() {
+ for _ in std::ops::Range { start: 0, end: 10 } {}
+ //~^ ERROR E0423
+ //~| ERROR expected type, found `0`
+}
+error: expected type, found `1`
+ --> $DIR/E0423.rs:22:39
+ |
+LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
+ | ^ expecting a type here because of type ascription
+
+error: expected expression, found `==`
+ --> $DIR/E0423.rs:25:13
+ |
+LL | if T {} == T {} { println!("Ok"); }
+ | ^^ expected expression
+
+error: expected type, found `0`
+ --> $DIR/E0423.rs:31:39
+ |
+LL | for _ in std::ops::Range { start: 0, end: 10 } {}
+ | ^ expecting a type here because of type ascription
+
error[E0423]: expected function, found struct `Foo`
--> $DIR/E0423.rs:14:13
|
LL | let f = Foo(); //~ ERROR E0423
- | ^^^ did you mean `Foo { /* fields */ }`?
+ | ^^^
+ | |
+ | did you mean `foo`?
+ | did you mean `Foo { /* fields */ }`?
+
+error[E0423]: expected value, found struct `S`
+ --> $DIR/E0423.rs:22:32
+ |
+LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); }
+ | ^ did you mean `(S { /* fields */ })`?
+
+error[E0423]: expected value, found struct `T`
+ --> $DIR/E0423.rs:25:8
+ |
+LL | if T {} == T {} { println!("Ok"); }
+ | ^ did you mean `(T { /* fields */ })`?
+
+error[E0423]: expected value, found struct `std::ops::Range`
+ --> $DIR/E0423.rs:31:14
+ |
+LL | for _ in std::ops::Range { start: 0, end: 10 } {}
+ | ^^^^^^^^^^^^^^^ did you mean `(std::ops::Range { /* fields */ })`?
-error: aborting due to previous error
+error: aborting due to 7 previous errors
For more information about this 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.
+
+#[doc(keyword = "match")] //~ ERROR: #[doc(keyword = "...")] is experimental
+/// wonderful
+mod foo{}
--- /dev/null
+error[E0658]: #[doc(keyword = "...")] is experimental (see issue #51315)
+ --> $DIR/feature-gate-doc_keyword.rs:11:1
+ |
+LL | #[doc(keyword = "match")] //~ ERROR: #[doc(keyword = "...")] is experimental
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(doc_keyword)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-error[E0626]: borrow may still be in use when generator yields
- --> $DIR/pattern-borrow.rs:19:24
- |
-LL | if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields
- | ^^^^^^
-LL | yield ();
- | -------- possible yield occurs here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0626`.
//https://github.com/rust-lang/rust/issues/31364
#![feature(const_fn)]
-const fn a() -> usize { b() } //~ ERROR constant evaluation error
+const fn a() -> usize { b() }
const fn b() -> usize { a() }
-const ARR: [i32; a()] = [5; 6];
+const ARR: [i32; a()] = [5; 6]; //~ ERROR could not evaluate constant expression
fn main(){}
-error[E0080]: constant evaluation error
- --> $DIR/infinite-recursion-const-fn.rs:14:25
+error[E0080]: could not evaluate constant expression
+ --> $DIR/infinite-recursion-const-fn.rs:16:1
|
-LL | const fn a() -> usize { b() } //~ ERROR constant evaluation error
- | ^^^
+LL | const fn a() -> usize { b() }
+ | ---
| |
| reached the configured maximum number of stack frames
| inside call to `b`
| inside call to `a`
| inside call to `a`
| inside call to `a`
-LL | const ARR: [i32; a()] = [5; 6];
- | --- inside call to `a`
- |
-note: for constant expression here
- --> $DIR/infinite-recursion-const-fn.rs:16:1
- |
-LL | const ARR: [i32; a()] = [5; 6];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const ARR: [i32; a()] = [5; 6]; //~ ERROR could not evaluate constant expression
+ | ^^^^^^^^^^^^^^^^^---^^^^^^^^^^^
+ | |
+ | inside call to `a`
error: aborting due to previous error
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[macro_export]
+macro_rules! foo { ($i:ident) => {} }
+
+#[macro_export]
+macro_rules! foo { () => {} } //~ ERROR a macro named `foo` has already been exported
+ //~| WARN this was previously accepted
--- /dev/null
+error: a macro named `foo` has already been exported
+ --> $DIR/issue-38715.rs:15:1
+ |
+LL | macro_rules! foo { () => {} } //~ ERROR a macro named `foo` has already been exported
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `foo` already exported
+ |
+ = note: #[deny(duplicate_macro_exports)] on by default
+ = 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 #35896 <https://github.com/rust-lang/rust/issues/35896>
+note: previous macro export is now shadowed
+ --> $DIR/issue-38715.rs:12:1
+ |
+LL | macro_rules! foo { ($i:ident) => {} }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0601]: `main` function not found in crate `issue_38715`
+ |
+ = note: consider adding a `main` function to `$DIR/issue-38715.rs`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
+++ /dev/null
-error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast)
- --> $DIR/issue-45697.rs:30:9
- |
-LL | let z = copy_borrowed_ptr(&mut y);
- | - borrow of `*y.pointer` occurs here
-LL | *y.pointer += 1;
- | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
-
-error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir)
- --> $DIR/issue-45697.rs:30:9
- |
-LL | let z = copy_borrowed_ptr(&mut y);
- | ------ borrow of `y` occurs here
-LL | *y.pointer += 1;
- | ^^^^^^^^^^^^^^^ use of borrowed `y`
-...
-LL | *z.pointer += 1;
- | --------------- borrow later used here
-
-error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir)
- --> $DIR/issue-45697.rs:30:9
- |
-LL | let z = copy_borrowed_ptr(&mut y);
- | ------ borrow of `*y.pointer` occurs here
-LL | *y.pointer += 1;
- | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
-...
-LL | *z.pointer += 1;
- | --------------- borrow later used here
-
-error: aborting due to 3 previous errors
-
-Some errors occurred: E0503, E0506.
-For more information about an error, try `rustc --explain E0503`.
fn main() {
let p = Point { x: 0, y: 0 };
+ let Point { .., y, } = p; //~ ERROR expected `}`, found `,`
let Point { .., y } = p; //~ ERROR expected `}`, found `,`
- //~| ERROR pattern does not mention fields `x`, `y`
+ let Point { .., } = p; //~ ERROR expected `}`, found `,`
+ let Point { .. } = p;
}
error: expected `}`, found `,`
--> $DIR/issue-49257.rs:20:19
|
-LL | let Point { .., y } = p; //~ ERROR expected `}`, found `,`
- | ^ `..` must be in the last position, and cannot have a trailing comma
+LL | let Point { .., y, } = p; //~ ERROR expected `}`, found `,`
+ | --^
+ | | |
+ | | expected `}`
+ | `..` must be at the end and cannot have a trailing comma
+help: move the `..` to the end of the field list
+ |
+LL | let Point { y, .. } = p; //~ ERROR expected `}`, found `,`
+ | -- ^^^^
-error[E0027]: pattern does not mention fields `x`, `y`
- --> $DIR/issue-49257.rs:20:9
+error: expected `}`, found `,`
+ --> $DIR/issue-49257.rs:21:19
|
LL | let Point { .., y } = p; //~ ERROR expected `}`, found `,`
- | ^^^^^^^^^^^^^^^ missing fields `x`, `y`
+ | --^
+ | | |
+ | | expected `}`
+ | `..` must be at the end and cannot have a trailing comma
+help: move the `..` to the end of the field list
+ |
+LL | let Point { y , .. } = p; //~ ERROR expected `}`, found `,`
+ | -- ^^^^^^
+
+error: expected `}`, found `,`
+ --> $DIR/issue-49257.rs:22:19
+ |
+LL | let Point { .., } = p; //~ ERROR expected `}`, found `,`
+ | --^
+ | | |
+ | | expected `}`
+ | | help: remove this comma
+ | `..` must be at the end and cannot have a trailing comma
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0027`.
--- /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.
+
+pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T);
+//~^ ERROR #[cfg] cannot be applied on a generic parameter
+//~^^ ERROR #[cfg] cannot be applied on a generic parameter
+
+impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {}
+//~^ ERROR #[cfg] cannot be applied on a generic parameter
+//~^^ ERROR #[cfg] cannot be applied on a generic parameter
+
+pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {}
+//~^ ERROR #[cfg] cannot be applied on a generic parameter
+//~^^ ERROR #[cfg] cannot be applied on a generic parameter
+
+#[cfg(none)]
+pub struct Y<#[cfg(none)] T>(T); // shouldn't care when the entire item is stripped out
+
+struct M<T>(*const T);
+
+unsafe impl<#[cfg_attr(none, may_dangle)] T> Drop for M<T> {
+ //~^ ERROR #[cfg_attr] cannot be applied on a generic parameter
+ fn drop(&mut self) {}
+}
+
+type Z<#[ignored] 'a, #[cfg(none)] T> = X<'a, T>;
+//~^ ERROR #[cfg] cannot be applied on a generic parameter
--- /dev/null
+error: #[cfg] cannot be applied on a generic parameter
+ --> $DIR/issue-51279.rs:11:14
+ |
+LL | pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T);
+ | ^^^^^^^^^^^^
+
+error: #[cfg] cannot be applied on a generic parameter
+ --> $DIR/issue-51279.rs:11:31
+ |
+LL | pub struct X<#[cfg(none)] 'a, #[cfg(none)] T>(&'a T);
+ | ^^^^^^^^^^^^
+
+error: #[cfg] cannot be applied on a generic parameter
+ --> $DIR/issue-51279.rs:15:6
+ |
+LL | impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {}
+ | ^^^^^^^^^^^^
+
+error: #[cfg] cannot be applied on a generic parameter
+ --> $DIR/issue-51279.rs:15:23
+ |
+LL | impl<#[cfg(none)] 'a, #[cfg(none)] T> X<'a, T> {}
+ | ^^^^^^^^^^^^
+
+error: #[cfg] cannot be applied on a generic parameter
+ --> $DIR/issue-51279.rs:19:10
+ |
+LL | pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {}
+ | ^^^^^^^^^^^^
+
+error: #[cfg] cannot be applied on a generic parameter
+ --> $DIR/issue-51279.rs:19:27
+ |
+LL | pub fn f<#[cfg(none)] 'a, #[cfg(none)] T>(_: &'a T) {}
+ | ^^^^^^^^^^^^
+
+error: #[cfg_attr] cannot be applied on a generic parameter
+ --> $DIR/issue-51279.rs:28:13
+ |
+LL | unsafe impl<#[cfg_attr(none, may_dangle)] T> Drop for M<T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: #[cfg] cannot be applied on a generic parameter
+ --> $DIR/issue-51279.rs:33:23
+ |
+LL | type Z<#[ignored] 'a, #[cfg(none)] T> = X<'a, T>;
+ | ^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Tests the behavior of various Kleene operators in macros with respect to `?` terminals. In
-// particular, `?` in the position of a separator and of a Kleene operator is tested.
+// The logic for parsing Kleene operators in macros has a special case to disambiguate `?`.
+// Specifically, `$(pat)?` is the ZeroOrOne operator whereas `$(pat)?+` or `$(pat)?*` are the
+// ZeroOrMore and OneOrMore operators using `?` as a separator. These tests are intended to
+// exercise that logic in the macro parser.
+//
+// Moreover, we also throw in some tests for using a separator with `?`, which is meaningless but
+// included for consistency with `+` and `*`.
+//
+// This test focuses on error cases.
#![feature(macro_at_most_once_rep)]
-// should match `` and `a`
macro_rules! foo {
($(a)?) => {}
}
macro_rules! baz {
- ($(a),?) => {} //~ ERROR `?` macro repetition does not allow a separator
+ ($(a),?) => {} // comma separator is meaningless for `?`
}
-// should match `+` and `a+`
macro_rules! barplus {
($(a)?+) => {}
}
-// should match `*` and `a*`
macro_rules! barstar {
($(a)?*) => {}
}
foo!(a?a?a); //~ ERROR no rules expected the token `?`
foo!(a?a); //~ ERROR no rules expected the token `?`
foo!(a?); //~ ERROR no rules expected the token `?`
+ baz!(a?a?a); //~ ERROR no rules expected the token `?`
+ baz!(a?a); //~ ERROR no rules expected the token `?`
+ baz!(a?); //~ ERROR no rules expected the token `?`
+ baz!(a,); //~ ERROR unexpected end of macro invocation
+ baz!(a?a?a,); //~ ERROR no rules expected the token `?`
+ baz!(a?a,); //~ ERROR no rules expected the token `?`
+ baz!(a?,); //~ ERROR no rules expected the token `?`
barplus!(); //~ ERROR unexpected end of macro invocation
- barstar!(); //~ ERROR unexpected end of macro invocation
- barplus!(a?); //~ ERROR no rules expected the token `?`
- barplus!(a); //~ ERROR unexpected end of macro invocation
- barstar!(a?); //~ ERROR no rules expected the token `?`
- barstar!(a); //~ ERROR unexpected end of macro invocation
- barplus!(+); // ok
- barstar!(*); // ok
- barplus!(a+); // ok
- barstar!(a*); // ok
+ barplus!(a?); //~ ERROR unexpected end of macro invocation
+ barstar!(a?); //~ ERROR unexpected end of macro invocation
}
-error: `?` macro repetition does not allow a separator
- --> $DIR/macro-at-most-once-rep-ambig.rs:22:10
- |
-LL | ($(a),?) => {} //~ ERROR `?` macro repetition does not allow a separator
- | ^
-
error: no rules expected the token `?`
- --> $DIR/macro-at-most-once-rep-ambig.rs:36:11
+ --> $DIR/macro-at-most-once-rep-ambig.rs:40:11
|
LL | foo!(a?a?a); //~ ERROR no rules expected the token `?`
| ^
error: no rules expected the token `?`
- --> $DIR/macro-at-most-once-rep-ambig.rs:37:11
+ --> $DIR/macro-at-most-once-rep-ambig.rs:41:11
|
LL | foo!(a?a); //~ ERROR no rules expected the token `?`
| ^
error: no rules expected the token `?`
- --> $DIR/macro-at-most-once-rep-ambig.rs:38:11
+ --> $DIR/macro-at-most-once-rep-ambig.rs:42:11
|
LL | foo!(a?); //~ ERROR no rules expected the token `?`
| ^
-error: unexpected end of macro invocation
- --> $DIR/macro-at-most-once-rep-ambig.rs:39:5
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:43:11
|
-LL | barplus!(); //~ ERROR unexpected end of macro invocation
- | ^^^^^^^^^^^
+LL | baz!(a?a?a); //~ ERROR no rules expected the token `?`
+ | ^
-error: unexpected end of macro invocation
- --> $DIR/macro-at-most-once-rep-ambig.rs:40:5
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:44:11
|
-LL | barstar!(); //~ ERROR unexpected end of macro invocation
- | ^^^^^^^^^^^
+LL | baz!(a?a); //~ ERROR no rules expected the token `?`
+ | ^
error: no rules expected the token `?`
- --> $DIR/macro-at-most-once-rep-ambig.rs:41:15
+ --> $DIR/macro-at-most-once-rep-ambig.rs:45:11
|
-LL | barplus!(a?); //~ ERROR no rules expected the token `?`
- | ^
+LL | baz!(a?); //~ ERROR no rules expected the token `?`
+ | ^
error: unexpected end of macro invocation
- --> $DIR/macro-at-most-once-rep-ambig.rs:42:14
+ --> $DIR/macro-at-most-once-rep-ambig.rs:46:11
+ |
+LL | baz!(a,); //~ ERROR unexpected end of macro invocation
+ | ^
+
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:47:11
+ |
+LL | baz!(a?a?a,); //~ ERROR no rules expected the token `?`
+ | ^
+
+error: no rules expected the token `?`
+ --> $DIR/macro-at-most-once-rep-ambig.rs:48:11
|
-LL | barplus!(a); //~ ERROR unexpected end of macro invocation
- | ^
+LL | baz!(a?a,); //~ ERROR no rules expected the token `?`
+ | ^
error: no rules expected the token `?`
- --> $DIR/macro-at-most-once-rep-ambig.rs:43:15
+ --> $DIR/macro-at-most-once-rep-ambig.rs:49:11
+ |
+LL | baz!(a?,); //~ ERROR no rules expected the token `?`
+ | ^
+
+error: unexpected end of macro invocation
+ --> $DIR/macro-at-most-once-rep-ambig.rs:50:5
+ |
+LL | barplus!(); //~ ERROR unexpected end of macro invocation
+ | ^^^^^^^^^^^
+
+error: unexpected end of macro invocation
+ --> $DIR/macro-at-most-once-rep-ambig.rs:51:15
|
-LL | barstar!(a?); //~ ERROR no rules expected the token `?`
+LL | barplus!(a?); //~ ERROR unexpected end of macro invocation
| ^
error: unexpected end of macro invocation
- --> $DIR/macro-at-most-once-rep-ambig.rs:44:14
+ --> $DIR/macro-at-most-once-rep-ambig.rs:52:15
|
-LL | barstar!(a); //~ ERROR unexpected end of macro invocation
- | ^
+LL | barstar!(a?); //~ ERROR unexpected end of macro invocation
+ | ^
-error: aborting due to 10 previous errors
+error: aborting due to 13 previous errors
LL | callback(path.as_ref(); //~ ERROR expected one of
| ^
-error: expected one of `,`, `.`, `?`, or an operator, found `;`
+error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;`
--> $DIR/token-error-correct-3.rs:24:35
|
LL | callback(path.as_ref(); //~ ERROR expected one of
- | ^ expected one of `,`, `.`, `?`, or an operator here
+ | ^ expected one of `)`, `,`, `.`, `?`, or an operator here
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
--> $DIR/token-error-correct-3.rs:30:9
// compile-flags: --test
-#![feature(termination_trait_test)]
#![feature(test)]
extern crate test;
error: functions using `#[should_panic]` must return `()`
- --> $DIR/termination-trait-in-test-should-panic.rs:22:1
+ --> $DIR/termination-trait-in-test-should-panic.rs:21:1
|
LL | / fn not_a_num() -> Result<(), ParseIntError> {
LL | | //~^ ERROR functions using `#[should_panic]` must return `()`
// compile-flags: --test
// run-pass
-#![feature(termination_trait_test)]
#![feature(test)]
extern crate test;
// compile-flags: --test
-#![feature(termination_trait_test)]
-
use std::num::ParseIntError;
#[test]
error[E0277]: `main` has invalid return type `std::result::Result<f32, std::num::ParseIntError>`
- --> $DIR/termination-trait-test-wrong-type.rs:18:1
+ --> $DIR/termination-trait-test-wrong-type.rs:16:1
|
LL | / fn can_parse_zero_as_f32() -> Result<f32, ParseIntError> { //~ ERROR
LL | | "0".parse()
}
// `.` is similar to `,` so list parsing should continue to closing `}`
-use x::{A. B}; //~ ERROR expected one of `,`, `::`, or `as`, found `.`
+use x::{A. B}; //~ ERROR expected one of `,`, `::`, `as`, or `}`, found `.`
fn main() {}
-error: expected one of `,`, `::`, or `as`, found `.`
+error: expected one of `,`, `::`, `as`, or `}`, found `.`
--> $DIR/similar-tokens.rs:17:10
|
-LL | use x::{A. B}; //~ ERROR expected one of `,`, `::`, or `as`, found `.`
- | ^ expected one of `,`, `::`, or `as` here
+LL | use x::{A. B}; //~ ERROR expected one of `,`, `::`, `as`, or `}`, found `.`
+ | ^ expected one of `,`, `::`, `as`, or `}` here
error: aborting due to previous error
// ignore-mips
// ignore-powerpc
// ignore-s390x
+// ignore-sparc
+// ignore-sparc64
#![feature(target_feature)]
error: #[target_feature] attribute must be of the form #[target_feature(..)]
- --> $DIR/target-feature-wrong.rs:21:1
+ --> $DIR/target-feature-wrong.rs:23:1
|
LL | #[target_feature = "+sse2"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the feature named `foo` is not valid for this target
- --> $DIR/target-feature-wrong.rs:23:18
+ --> $DIR/target-feature-wrong.rs:25:18
|
LL | #[target_feature(enable = "foo")]
| ^^^^^^^^^^^^^^
error: #[target_feature(..)] only accepts sub-keys of `enable` currently
- --> $DIR/target-feature-wrong.rs:25:18
+ --> $DIR/target-feature-wrong.rs:27:18
|
LL | #[target_feature(bar)]
| ^^^
error: #[target_feature(..)] only accepts sub-keys of `enable` currently
- --> $DIR/target-feature-wrong.rs:27:18
+ --> $DIR/target-feature-wrong.rs:29:18
|
LL | #[target_feature(disable = "baz")]
| ^^^^^^^^^^^^^^^
error: #[target_feature(..)] can only be applied to `unsafe` function
- --> $DIR/target-feature-wrong.rs:31:1
+ --> $DIR/target-feature-wrong.rs:33:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: attribute should be applied to a function
- --> $DIR/target-feature-wrong.rs:35:1
+ --> $DIR/target-feature-wrong.rs:37:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| -------------- not a function
error: cannot use #[inline(always)] with #[target_feature]
- --> $DIR/target-feature-wrong.rs:39:1
+ --> $DIR/target-feature-wrong.rs:41:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
LL | option.map(|some| 42;
| ^
-error: expected one of `,`, `.`, `?`, or an operator, found `;`
+error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;`
--> $DIR/issue-10636-2.rs:15:25
|
LL | option.map(|some| 42;
- | ^ expected one of `,`, `.`, `?`, or an operator here
+ | ^ expected one of `)`, `,`, `.`, `?`, or an operator here
error: expected expression, found `)`
--> $DIR/issue-10636-2.rs:18:1
--- /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.
+
+// Checks to make sure that `dyn Trait + Send` and `dyn Trait + Send + Send` are the same type.
+// Issue: #47010
+
+struct Struct;
+impl Trait for Struct {}
+trait Trait {}
+
+type Send1 = Trait + Send;
+type Send2 = Trait + Send + Send;
+
+fn main () {}
+
+impl Trait + Send {
+ fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test`
+}
+
+impl Trait + Send + Send {
+ fn test(&self) { println!("two"); }
+}
--- /dev/null
+error[E0592]: duplicate definitions with name `test`
+ --> $DIR/trait-object-auto-dedup-in-impl.rs:24:5
+ |
+LL | fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `test`
+...
+LL | fn test(&self) { println!("two"); }
+ | ----------------------------------- other definition for `test`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0592`.
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod foo {
+ type T = ();
+ struct S1(pub(in foo) (), pub(T), pub(crate) (), pub(((), T)));
+ struct S2(pub((foo)) ());
+ //~^ ERROR expected one of `)` or `,`, found `(`
+ //~| ERROR cannot find type `foo` in this scope
+}
--- /dev/null
+error: expected one of `)` or `,`, found `(`
+ --> $DIR/test.rs:14:26
+ |
+LL | struct S2(pub((foo)) ());
+ | ^ expected one of `)` or `,` here
+
+error[E0412]: cannot find type `foo` in this scope
+ --> $DIR/test.rs:14:20
+ |
+LL | struct S2(pub((foo)) ());
+ | ^^^ not found in this scope
+
+error[E0601]: `main` function not found in crate `test`
+ |
+ = note: consider adding a `main` function to `$DIR/test.rs`
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0412, E0601.
+For more information about an error, try `rustc --explain E0412`.
--- /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.
+
+macro_rules! define_struct {
+ ($t:ty) => {
+ struct S1(pub $t);
+ struct S2(pub (in foo) ());
+ struct S3(pub $t ());
+ //~^ ERROR expected one of `)` or `,`, found `(`
+ }
+}
+
+mod foo {
+ define_struct! { (foo) }
+}
--- /dev/null
+error: expected one of `)` or `,`, found `(`
+ --> $DIR/test2.rs:15:26
+ |
+LL | struct S3(pub $t ());
+ | ^ expected one of `)` or `,` here
+...
+LL | define_struct! { (foo) }
+ | ------------------------ in this macro invocation
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! define_struct {
+ ($t:ty) => {
+ struct S1(pub($t));
+ struct S2(pub (in foo) ());
+ struct S3(pub($t) ());
+ //~^ ERROR expected one of `)` or `,`, found `(`
+ }
+}
+
+mod foo {
+ define_struct! { foo }
+}
--- /dev/null
+error: expected one of `)` or `,`, found `(`
+ --> $DIR/test3.rs:15:27
+ |
+LL | struct S3(pub($t) ());
+ | ^ expected one of `)` or `,` here
+...
+LL | define_struct! { foo }
+ | ---------------------- in this macro invocation
+
+error: aborting due to previous error
+
fn main() {
let v = vec![0];
const l: usize = v.count(); //~ ERROR can't capture dynamic environment in a fn item
- let s: [u32; l] = v.into_iter().collect(); //~ ERROR constant evaluation error
+ let s: [u32; l] = v.into_iter().collect();
}
|
= help: use the `|| { ... }` closure form instead
-error[E0080]: constant evaluation error
- --> $DIR/type-dependent-def-issue-49241.rs:14:18
- |
-LL | let s: [u32; l] = v.into_iter().collect(); //~ ERROR constant evaluation error
- | ^ encountered constants with type errors, stopping evaluation
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors occurred: E0080, E0434.
-For more information about an error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0434`.
-Subproject commit c3b09c9680fce8ab70a49c8531fd8f84c2ccdff2
+Subproject commit e2348c2db296ce33428933c3ab8786d5f3c54a2e
-Subproject commit 453f5e4dec279167aed825b7ad043d06aa17c667
+Subproject commit 7d0bc550b0899a13a56c81eb2d5064abd0bcf385
finalJS = "";
var arraysToLoad = ["itemTypes"];
- var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", "TY_PRIMITIVE", "levenshtein_row2"];
+ var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS",
+ "TY_PRIMITIVE", "TY_KEYWORD",
+ "levenshtein_row2"];
// execQuery first parameter is built in getQuery (which takes in the search input).
// execQuery last parameter is built in buildIndex.
// buildIndex requires the hashmap from search-index.
-Subproject commit 173ae0d7b92227c7fec4bce67c944dce953256dc
+Subproject commit 08da30d72c9abfff4d41f6f081e31fd2929b820d