# Original downloaded here came from
# http://releases.llvm.org/7.0.0/LLVM-7.0.0-win64.exe
- script: |
- powershell -Command "iwr -outf %TEMP%\LLVM-7.0.0-win64.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/LLVM-7.0.0-win64.exe"
+ powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf %TEMP%\LLVM-7.0.0-win64.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/LLVM-7.0.0-win64.exe"
set CLANG_DIR=%CD%\citools\clang-rust
%TEMP%\LLVM-7.0.0-win64.exe /S /NCRC /D=%CLANG_DIR%
set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --set llvm.clang-cl=%CLANG_DIR%\bin\clang-cl.exe
- script: |
md sccache
- powershell -Command "iwr -outf sccache\sccache.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-26-sccache-x86_64-pc-windows-msvc"
+ powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf sccache\sccache.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-26-sccache-x86_64-pc-windows-msvc"
echo ##vso[task.prependpath]%CD%\sccache
displayName: Install sccache (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
# Note that we don't literally overwrite the gdb.exe binary because it appears
# to just use gdborig.exe, so that's the binary we deal with instead.
- script: |
- powershell -Command "iwr -outf %MINGW_ARCHIVE% %MINGW_URL%/%MINGW_ARCHIVE%"
+ powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf %MINGW_ARCHIVE% %MINGW_URL%/%MINGW_ARCHIVE%"
7z x -y %MINGW_ARCHIVE% > nul
- powershell -Command "iwr -outf 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_URL%/2017-04-20-%MSYS_BITS%bit-gdborig.exe"
+ powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_URL%/2017-04-20-%MSYS_BITS%bit-gdborig.exe"
mv 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_DIR%\bin\gdborig.exe
echo ##vso[task.prependpath]%CD%\%MINGW_DIR%\bin
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['MINGW_URL'],''))
# Note that this is originally from the github releases patch of Ninja
- script: |
md ninja
- powershell -Command "iwr -outf 2017-03-15-ninja-win.zip https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-03-15-ninja-win.zip"
+ powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-03-15-ninja-win.zip https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-03-15-ninja-win.zip"
7z x -oninja 2017-03-15-ninja-win.zip
del 2017-03-15-ninja-win.zip
set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --enable-ninja
[[package]]
name = "hashbrown"
-version = "0.3.0"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"compiler_builtins 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "indexmap"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "installer"
version = "0.0.0"
"env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-workspace-hack 1.0.0",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
+ "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
dependencies = [
"arena 0.0.0",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
name = "serialize"
version = "0.0.0"
dependencies = [
+ "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
"core 0.0.0",
"dlmalloc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fortanix-sgx-abi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "hashbrown 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hashbrown 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",
"checksum globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4feaabe24a0a658fd9cf4a9acf6ed284f045c77df0f49020ba3245cfb7b454"
"checksum handlebars 0.32.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d89ec99d1594f285d4590fc32bac5f75cdab383f1123d504d27862c644a807dd"
"checksum handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d82e5750d8027a97b9640e3fefa66bbaf852a35228e1c90790efd13c4b09c166"
-"checksum hashbrown 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "570178d5e4952010d138b0f1d581271ff3a02406d990f887d1e87e3d6e43b0ac"
+"checksum hashbrown 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9529213c67695ca2d146e6f263b7b72df8fa973368beadf767e8ed80c03f2f36"
"checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82"
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
"checksum home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "80dff82fb58cfbbc617fb9a9184b010be0529201553cda50ad04372bc2333aff"
"checksum if_chain 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d"
"checksum ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8dc57fa12805f367736a38541ac1a9fc6a52812a0ca959b1d4d4b640a89eb002"
"checksum im-rc 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0197597d095c0d11107975d3175173f810ee572c2501ff4de64f4f3f119806"
+"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053"
"checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
book!(
EditionGuide, "src/doc/edition-guide", "edition-guide", RustbookVersion::MdBook2;
EmbeddedBook, "src/doc/embedded-book", "embedded-book", RustbookVersion::MdBook2;
- Nomicon, "src/doc/nomicon", "nomicon", RustbookVersion::MdBook1;
+ Nomicon, "src/doc/nomicon", "nomicon", RustbookVersion::MdBook2;
Reference, "src/doc/reference", "reference", RustbookVersion::MdBook1;
RustByExample, "src/doc/rust-by-example", "rust-by-example", RustbookVersion::MdBook1;
RustcBook, "src/doc/rustc", "rustc", RustbookVersion::MdBook1;
- RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::MdBook1;
+ RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::MdBook2;
);
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
target: self.target,
name: INTERNER.intern_str("unstable-book"),
src: builder.md_doc_out(self.target),
- version: RustbookVersion::MdBook1,
+ version: RustbookVersion::MdBook2,
})
}
}
#
# Versions of the toolchain components are configurable in `musl-cross-make/Makefile` and
# musl unlike GLIBC is forward compatible so upgrading it shouldn't break old distributions.
-# Right now we have: Binutils 2.27, GCC 6.3.0, musl 1.1.18
+# Right now we have: Binutils 2.27, GCC 6.4.0, musl 1.1.22.
set -ex
hide_output() {
# Apparently applying `-fPIC` everywhere allows them to link successfully.
export CFLAGS="-fPIC $CFLAGS"
-git clone https://github.com/richfelker/musl-cross-make -b v0.9.7
+git clone https://github.com/richfelker/musl-cross-make -b v0.9.8
cd musl-cross-make
hide_output make -j$(nproc) TARGET=$TARGET
An argument of "list" will print a list of possible "rustdoc passes", and other
arguments will be the name of which passes to run in addition to the defaults.
-For more details on passes, see [the chapter on them](passes.html).
+For more details on passes, see [the chapter on them](passes.md).
See also `--no-defaults`.
removes those defaults, allowing you to use `--passes` to specify
exactly which passes you want.
-For more details on passes, see [the chapter on them](passes.html).
+For more details on passes, see [the chapter on them](passes.md).
See also `--passes`.
```
This flag will run your code examples as tests. For more, see [the chapter
-on documentation tests](documentation-tests.html).
+on documentation tests](documentation-tests.md).
See also `--test-args`.
```
This flag will pass options to the test runner when running documentation tests.
-For more, see [the chapter on documentation tests](documentation-tests.html).
+For more, see [the chapter on documentation tests](documentation-tests.md).
See also `--test`.
In addition to the passes below, check out the docs for these flags:
-* [`--passes`](command-line-arguments.html#a--passes-add-more-rustdoc-passes)
-* [`--no-defaults`](command-line-arguments.html#a--no-defaults-dont-run-default-passes)
+* [`--passes`](command-line-arguments.md#--passes-add-more-rustdoc-passes)
+* [`--no-defaults`](command-line-arguments.md#--no-defaults-dont-run-default-passes)
## Default passes
[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions
If you need more power and don't mind losing some of the niceties of
-`asm!`, check out [global_asm](language-features/global-asm.html).
+`asm!`, check out [global_asm](global-asm.md).
[#29641]: https://github.com/rust-lang/rust/issues/29641
-See also [`box_syntax`](language-features/box-syntax.html)
+See also [`box_syntax`](box-syntax.md)
------------------------
[#49733]: https://github.com/rust-lang/rust/issues/49733
-See also [`box_patterns`](language-features/box-patterns.html)
+See also [`box_patterns`](box-patterns.md)
------------------------
If you don't need quite as much power and flexibility as
`global_asm!` provides, and you don't mind restricting your inline
assembly to `fn` bodies only, you might try the
-[asm](language-features/asm.html) feature instead.
+[asm](asm.md) feature instead.
also requires enabling the library feature `compiler_builtins_lib`. You can read
more about this [here][compiler-builtins-lib].
-[compiler-builtins-lib]: library-features/compiler-builtins-lib.html
+[compiler-builtins-lib]: ../library-features/compiler-builtins-lib.md
## More about the language items
[`XID_start`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Start%3A%5D&abb=on&g=&i=
[`XID_continue`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Continue%3A%5D&abb=on&g=&i=
-[strict keywords]: ../reference/keywords.html#strict-keywords
+[strict keywords]: ../../reference/keywords.md#strict-keywords
[`plugin`] and `rustc_private` features as well. For more details, see
their docs.
-[`plugin`]: language-features/plugin.html
+[`plugin`]: plugin.md
------------------------
This feature is part of "compiler plugins." It will often be used with the
[`plugin_registrar`] and `rustc_private` features.
-[`plugin_registrar`]: language-features/plugin-registrar.html
+[`plugin_registrar`]: plugin-registrar.md
------------------------
Plugins can extend Rust's syntax in various ways. One kind of syntax extension
is the procedural macro. These are invoked the same way as [ordinary
-macros](../book/macros.html), but the expansion is performed by arbitrary Rust
+macros](../../book/macros.md), but the expansion is performed by arbitrary Rust
code that manipulates syntax trees at
compile time.
a way to define new literal syntax for any data type.
In addition to procedural macros, you can define new
-[`derive`](../reference/attributes/derive.html)-like attributes and other kinds
+[`derive`](../../reference/attributes/derive.md)-like attributes and other kinds
of extensions. See `Registry::register_syntax_extension` and the
`SyntaxExtension` enum. For a more involved macro example, see
[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
# Lint plugins
Plugins can extend [Rust's lint
-infrastructure](../reference/attributes/diagnostics.html#lint-check-attributes) with
+infrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with
additional checks for code style, safety, etc. Now let's write a plugin
[`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/lint_plugin_test.rs)
that warns about any item named `lintme`.
to access type information.
Lints defined by plugins are controlled by the usual [attributes and compiler
-flags](../reference/attributes/diagnostics.html#lint-check-attributes), e.g.
+flags](../../reference/attributes/diagnostics.md#lint-check-attributes), e.g.
`#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the
first argument to `declare_lint!`, with appropriate case and punctuation
conversion.
The tracking issue for this feature is [#29625]
-See Also: [`fn_traits`](library-features/fn-traits.html)
+See Also: [`fn_traits`](../library-features/fn-traits.md)
[#29625]: https://github.com/rust-lang/rust/issues/29625
The tracking issue for this feature is [#29625]
-See Also: [`unboxed_closures`](language-features/unboxed-closures.html)
+See Also: [`unboxed_closures`](../language-features/unboxed-closures.md)
[#29625]: https://github.com/rust-lang/rust/issues/29625
Before the introduction of [`unsized_locals`][unsized_locals], we had been unable to provide the former impls. That means, unlike `&dyn Fn()` or `&mut dyn FnMut()` we could not use `Box<dyn FnOnce()>` at that time.
-[unsized_locals]: language-features/unsized-locals.html
+[unsized_locals]: ../language-features/unsized-locals.md
`FnBox()` is an alternative approach to `Box<dyn FnBox()>` is delegated to `FnBox::call_box` which doesn't need unsized locals. As we now have `Box<dyn FnOnce()>` working, the `fnbox` feature is going to be removed.
The `box_syntax` feature [has a chapter][box] describing how to use it.
-[box]: language-features/box-syntax.html
+[box]: language-features/box-syntax.md
Because this documentation relates to unstable features, we make no guarantees
that what is contained here is accurate or up to date. It's developed on a
#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_array)]
#![feature(alloc_layout_extra)]
#![feature(try_trait)]
-#![feature(iter_nth_back)]
// Allow testing this library
/// # Examples
///
/// By using trait bounds we can accept arguments of different types as long as they can be
-/// converted a the specified type `T`.
+/// converted to the specified type `T`.
///
/// For example: By creating a generic function that takes an `AsRef<str>` we express that we
/// want to accept all references that can be converted to `&str` as an argument.
///
/// Using `AsMut` as trait bound for a generic function we can accept all mutable references
/// that can be converted to type `&mut T`. Because [`Box<T>`] implements `AsMut<T>` we can
-/// write a function `add_one`that takes all arguments that can be converted to `&mut u64`.
-/// Because [`Box<T>`] implements `AsMut<T>` `add_one` accepts arguments of type
+/// write a function `add_one` that takes all arguments that can be converted to `&mut u64`.
+/// Because [`Box<T>`] implements `AsMut<T>`, `add_one` accepts arguments of type
/// `&mut Box<u64>` as well:
///
/// ```
/// Basic usage:
///
/// ```
- /// #![feature(iter_nth_back)]
/// let a = [1, 2, 3];
/// assert_eq!(a.iter().nth_back(2), Some(&1));
/// ```
/// Calling `nth_back()` multiple times doesn't rewind the iterator:
///
/// ```
- /// #![feature(iter_nth_back)]
/// let a = [1, 2, 3];
///
/// let mut iter = a.iter();
/// Returning `None` if there are less than `n + 1` elements:
///
/// ```
- /// #![feature(iter_nth_back)]
/// let a = [1, 2, 3];
/// assert_eq!(a.iter().nth_back(10), None);
/// ```
#[inline]
- #[unstable(feature = "iter_nth_back", issue = "56995")]
+ #[stable(feature = "iter_nth_back", since = "1.37.0")]
fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
for x in self.rev() {
if n == 0 { return Some(x) }
#![feature(const_str_len)]
#![feature(const_int_conversion)]
#![feature(const_transmute)]
-#![feature(reverse_bits)]
#![feature(non_exhaustive)]
#![feature(structural_match)]
#![feature(abi_unadjusted)]
Basic usage:
```
-#![feature(reverse_bits)]
-
let n = ", $swap_op, stringify!($SelfT), ";
let m = n.reverse_bits();
assert_eq!(m, ", $reversed, ");
```"),
- #[unstable(feature = "reverse_bits", issue = "48763")]
- #[rustc_const_unstable(feature = "const_int_conversion")]
+ #[stable(feature = "reverse_bits", since = "1.37.0")]
#[inline]
#[must_use]
pub const fn reverse_bits(self) -> Self {
Basic usage:
```
-#![feature(reverse_bits)]
-
let n = ", $swap_op, stringify!($SelfT), ";
let m = n.reverse_bits();
assert_eq!(m, ", $reversed, ");
```"),
- #[unstable(feature = "reverse_bits", issue = "48763")]
+ #[stable(feature = "reverse_bits", since = "1.37.0")]
#[inline]
#[must_use]
pub const fn reverse_bits(self) -> Self {
/// Basic usage:
///
/// ```
- /// #![feature(reverse_bits)]
/// use std::num::Wrapping;
///
/// let n = Wrapping(0b0000000_01010101i16);
/// assert_eq!(m.0 as u16, 0b10101010_00000000);
/// assert_eq!(m, Wrapping(-22016));
/// ```
- #[unstable(feature = "reverse_bits", issue = "48763")]
+ #[stable(feature = "reverse_bits", since = "1.37.0")]
#[inline]
#[must_use]
pub const fn reverse_bits(self) -> Self {
/// * Values of type `&T` are coerced to values of type `&U`
/// * `T` implicitly implements all the (immutable) methods of the type `U`.
///
-/// For more details, visit [the chapter in *The Rust Programming Language*]
-/// [book] as well as the reference sections on [the dereference operator]
-/// [ref-deref-op], [method resolution] and [type coercions].
+/// For more details, visit [the chapter in *The Rust Programming Language*][book]
+/// as well as the reference sections on [the dereference operator][ref-deref-op],
+/// [method resolution] and [type coercions].
///
/// [book]: ../../book/ch15-02-deref.html
/// [`DerefMut`]: trait.DerefMut.html
/// * Values of type `&mut T` are coerced to values of type `&mut U`
/// * `T` implicitly implements all the (mutable) methods of the type `U`.
///
-/// For more details, visit [the chapter in *The Rust Programming Language*]
-/// [book] as well as the reference sections on [the dereference operator]
-/// [ref-deref-op], [method resolution] and [type coercions].
+/// For more details, visit [the chapter in *The Rust Programming Language*][book]
+/// as well as the reference sections on [the dereference operator][ref-deref-op],
+/// [method resolution] and [type coercions].
///
/// [book]: ../../book/ch15-02-deref.html
/// [`Deref`]: trait.Deref.html
#![feature(fmt_internals)]
#![feature(hashmap_internals)]
#![feature(is_sorted)]
-#![feature(iter_nth_back)]
#![feature(iter_once_with)]
#![feature(pattern)]
#![feature(range_is_empty)]
#![feature(test)]
#![feature(trusted_len)]
#![feature(try_trait)]
-#![feature(reverse_bits)]
#![feature(inner_deref)]
#![feature(slice_internals)]
#![feature(slice_partition_dedup)]
macro_rules! arena_types {
($macro:path, $args:tt, $tcx:lifetime) => (
$macro!($args, [
+ [] layouts: rustc::ty::layout::LayoutDetails,
+ [] generics: rustc::ty::Generics,
+ [] trait_def: rustc::ty::TraitDef,
+ [] adt_def: rustc::ty::AdtDef,
+ [] steal_mir: rustc::ty::steal::Steal<rustc::mir::Body<$tcx>>,
+ [] mir: rustc::mir::Body<$tcx>,
+ [] tables: rustc::ty::TypeckTables<$tcx>,
+ [] const_allocs: rustc::mir::interpret::Allocation,
[] vtable_method: Option<(
rustc::hir::def_id::DefId,
rustc::ty::subst::SubstsRef<$tcx>
>,
[few] crate_variances: rustc::ty::CrateVariancesMap<'tcx>,
[few] inferred_outlives_crate: rustc::ty::CratePredicatesMap<'tcx>,
+ [] upvars: rustc_data_structures::fx::FxIndexMap<rustc::hir::HirId, rustc::hir::Upvar>,
], $tcx);
)
}
// Value namespace
SelfCtor(DefId /* impl */), // `DefId` refers to the impl
Local(Id),
- Upvar(Id, // `HirId` of closed over local
- usize, // index in the `upvars` list of the closure
- ast::NodeId), // expr node that creates the closure
// Macro namespace
NonMacroAttr(NonMacroAttrKind), // e.g., `#[inline]` or `#[rustfmt::skip]`
Res::Def(_, id) => Some(id),
Res::Local(..) |
- Res::Upvar(..) |
Res::PrimTy(..) |
Res::SelfTy(..) |
Res::SelfCtor(..) |
Res::SelfCtor(..) => "self constructor",
Res::PrimTy(..) => "builtin type",
Res::Local(..) => "local variable",
- Res::Upvar(..) => "closure capture",
Res::SelfTy(..) => "self type",
Res::ToolMod => "tool module",
Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
Res::SelfCtor(id) => Res::SelfCtor(id),
Res::PrimTy(id) => Res::PrimTy(id),
Res::Local(id) => Res::Local(map(id)),
- Res::Upvar(id, index, closure) => Res::Upvar(
- map(id),
- index,
- closure
- ),
Res::SelfTy(a, b) => Res::SelfTy(a, b),
Res::ToolMod => Res::ToolMod,
Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
use std::io;
use std::result::Result::Err;
-use crate::ty::TyCtxt;
+use crate::ty::query::Providers;
pub mod blocks;
mod collector;
})
}
- pub fn get_generics_span(&self, id: DefId) -> Option<Span> {
- self.get_generics(id).map(|generics| generics.span).filter(|sp| *sp != DUMMY_SP)
- }
-
/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
pub fn find(&self, id: NodeId) -> Option<Node<'hir>> {
let hir_id = self.node_to_hir_id(id);
}
}
-pub fn def_kind(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option<DefKind> {
- if let Some(node_id) = tcx.hir().as_local_node_id(def_id) {
- tcx.hir().def_kind(node_id)
- } else {
- bug!("Calling local def_kind query provider for upstream DefId: {:?}",
- def_id)
- }
+pub fn provide(providers: &mut Providers<'_>) {
+ providers.def_kind = |tcx, def_id| {
+ if let Some(node_id) = tcx.hir().as_local_node_id(def_id) {
+ tcx.hir().def_kind(node_id)
+ } else {
+ bug!("Calling local def_kind query provider for upstream DefId: {:?}",
+ def_id)
+ }
+ };
}
use crate::mir::mono::Linkage;
use errors::FatalError;
-use syntax_pos::{Span, DUMMY_SP, symbol::InternedString};
+use syntax_pos::{Span, DUMMY_SP, symbol::InternedString, MultiSpan};
use syntax::source_map::Spanned;
use rustc_target::spec::abi::Abi;
use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect};
pub mod map;
pub mod pat_util;
pub mod print;
+pub mod upvars;
/// Uniquely identifies a node in the HIR of the current crate. It is
/// composed of the `owner`, which is the `DefIndex` of the directly enclosing
}
None
}
+
+ pub fn spans(&self) -> MultiSpan {
+ if self.params.is_empty() {
+ self.span.into()
+ } else {
+ self.params.iter().map(|p| p.span).collect::<Vec<Span>>().into()
+ }
+ }
}
/// Synthetic type parameters are converted to another form during lowering; this allows
ExprKind::Path(QPath::Resolved(_, ref path)) => {
match path.res {
Res::Local(..)
- | Res::Upvar(..)
| Res::Def(DefKind::Static, _)
| Res::Err => true,
_ => false,
/// A variable captured by a closure.
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
-pub struct Upvar<Id = HirId> {
- /// The variable being captured.
- pub res: Res<Id>,
-
+pub struct Upvar {
// First span where it is accessed (there can be multiple).
pub span: Span
}
-impl<Id: fmt::Debug + Copy> Upvar<Id> {
- pub fn map_id<R>(self, map: impl FnMut(Id) -> R) -> Upvar<R> {
- Upvar {
- res: self.res.map_id(map),
- span: self.span,
- }
- }
-
- pub fn var_id(&self) -> Id {
- match self.res {
- Res::Local(id) | Res::Upvar(id, ..) => id,
- _ => bug!("Upvar::var_id: bad res ({:?})", self.res)
- }
- }
-}
-
-pub type UpvarMap = NodeMap<Vec<Upvar<ast::NodeId>>>;
-
pub type CaptureModeMap = NodeMap<CaptureClause>;
// The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
// imported.
pub type GlobMap = NodeMap<FxHashSet<Name>>;
-
pub fn provide(providers: &mut Providers<'_>) {
check_attr::provide(providers);
- providers.def_kind = map::def_kind;
+ map::provide(providers);
+ upvars::provide(providers);
}
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
--- /dev/null
+//! Upvar (closure capture) collection from cross-body HIR uses of `Res::Local`s.
+
+use crate::hir::{self, HirId};
+use crate::hir::def::Res;
+use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
+use crate::ty::TyCtxt;
+use crate::ty::query::Providers;
+use syntax_pos::Span;
+use rustc_data_structures::fx::{FxIndexMap, FxHashSet};
+
+pub fn provide(providers: &mut Providers<'_>) {
+ providers.upvars = |tcx, def_id| {
+ if !tcx.is_closure(def_id) {
+ return None;
+ }
+
+ let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
+ let body = tcx.hir().body(tcx.hir().maybe_body_owned_by(node_id)?);
+
+ let mut local_collector = LocalCollector::default();
+ local_collector.visit_body(body);
+
+ let mut capture_collector = CaptureCollector {
+ tcx,
+ locals: &local_collector.locals,
+ upvars: FxIndexMap::default(),
+ };
+ capture_collector.visit_body(body);
+
+ if !capture_collector.upvars.is_empty() {
+ Some(tcx.arena.alloc(capture_collector.upvars))
+ } else {
+ None
+ }
+ };
+}
+
+#[derive(Default)]
+struct LocalCollector {
+ // FIXME(eddyb) perhaps use `ItemLocalId` instead?
+ locals: FxHashSet<HirId>,
+}
+
+impl Visitor<'tcx> for LocalCollector {
+ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
+ if let hir::PatKind::Binding(_, hir_id, ..) = pat.node {
+ self.locals.insert(hir_id);
+ }
+ intravisit::walk_pat(self, pat);
+ }
+}
+
+struct CaptureCollector<'a, 'tcx> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ locals: &'a FxHashSet<HirId>,
+ upvars: FxIndexMap<HirId, hir::Upvar>,
+}
+
+impl CaptureCollector<'_, '_> {
+ fn visit_local_use(&mut self, var_id: HirId, span: Span) {
+ if !self.locals.contains(&var_id) {
+ self.upvars.entry(var_id).or_insert(hir::Upvar { span });
+ }
+ }
+}
+
+impl Visitor<'tcx> for CaptureCollector<'a, 'tcx> {
+ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_path(&mut self, path: &'tcx hir::Path, _: hir::HirId) {
+ if let Res::Local(var_id) = path.res {
+ self.visit_local_use(var_id, path.span);
+ }
+
+ intravisit::walk_path(self, path);
+ }
+
+ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
+ if let hir::ExprKind::Closure(..) = expr.node {
+ let closure_def_id = self.tcx.hir().local_def_id_from_hir_id(expr.hir_id);
+ if let Some(upvars) = self.tcx.upvars(closure_def_id) {
+ // Every capture of a closure expression is a local in scope,
+ // that is moved/copied/borrowed into the closure value, and
+ // for this analysis they are like any other access to a local.
+ //
+ // E.g. in `|b| |c| (a, b, c)`, the upvars of the inner closure
+ // are `a` and `b`, and while `a` is not directly used in the
+ // outer closure, it needs to be an upvar there too, so that
+ // the inner closure can take it (from the outer closure's env).
+ for (&var_id, upvar) in upvars {
+ self.visit_local_use(var_id, upvar.span);
+ }
+ }
+ }
+
+ intravisit::walk_expr(self, expr);
+ }
+}
ty::ReClosureBound(vid) => {
vid.hash_stable(hcx, hasher);
}
- ty::ReLateBound(..) |
ty::ReVar(..) |
ty::RePlaceholder(..) => {
bug!("StableHasher: unexpected region {:?}", *self)
format!("the anonymous lifetime #{} defined on", idx + 1),
self.hir().span_by_hir_id(node),
),
- ty::BrFresh(_) => (
- "an anonymous lifetime defined on".to_owned(),
- self.hir().span_by_hir_id(node),
- ),
_ => (
format!("the lifetime {} as defined on", region),
cm.def_span(self.hir().span_by_hir_id(node)),
use rustc_data_structures::unify as ut;
use crate::ty::ReStatic;
use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::{BrFresh, ReLateBound, ReVar};
+use crate::ty::{ReLateBound, ReVar};
use crate::ty::{Region, RegionVid};
use std::collections::BTreeMap;
-use std::{cmp, fmt, mem, u32};
+use std::{cmp, fmt, mem};
use std::ops::Range;
mod leak_check;
/// exist). This prevents us from making many such regions.
glbs: CombineMap<'tcx>,
- /// Global counter used during the GLB algorithm to create unique
- /// names for fresh bound regions
- bound_count: u32,
-
/// The undo log records actions that might later be undone.
///
/// Note: `num_open_snapshots` is used to track if we are actively
data,
lubs,
glbs,
- bound_count: _,
undo_log: _,
num_open_snapshots: _,
unification_table,
}
}
- pub fn new_bound(
- &mut self,
- tcx: TyCtxt<'_, '_, 'tcx>,
- debruijn: ty::DebruijnIndex,
- ) -> Region<'tcx> {
- // Creates a fresh bound variable for use in GLB computations.
- // See discussion of GLB computation in the large comment at
- // the top of this file for more details.
- //
- // This computation is potentially wrong in the face of
- // rollover. It's conceivable, if unlikely, that one might
- // wind up with accidental capture for nested functions in
- // that case, if the outer function had bound regions created
- // a very long time before and the inner function somehow
- // wound up rolling over such that supposedly fresh
- // identifiers were in fact shadowed. For now, we just assert
- // that there is no rollover -- eventually we should try to be
- // robust against this possibility, either by checking the set
- // of bound identifiers that appear in a given expression and
- // ensure that we generate one that is distinct, or by
- // changing the representation of bound regions in a fn
- // declaration
-
- let sc = self.bound_count;
- self.bound_count = sc + 1;
-
- if sc >= self.bound_count {
- bug!("rollover in RegionInference new_bound()");
- }
-
- tcx.mk_region(ReLateBound(debruijn, BrFresh(sc)))
- }
-
fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
// cannot add constraints once regions are resolved
debug!(
}
_ if self.in_pat => {},
Res::PrimTy(..) | Res::SelfTy(..) | Res::SelfCtor(..) |
- Res::Local(..) | Res::Upvar(..) => {}
+ Res::Local(..) => {}
Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => {
let variant_id = self.tcx.parent(ctor_def_id).unwrap();
let enum_id = self.tcx.parent(variant_id).unwrap();
/// See also `with_infer`, which is used *during* typeck.
pub fn new(delegate: &'a mut (dyn Delegate<'tcx>+'a),
tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ body_owner: DefId,
param_env: ty::ParamEnv<'tcx>,
region_scope_tree: &'a region::ScopeTree,
tables: &'a ty::TypeckTables<'tcx>,
{
ExprUseVisitor {
mc: mc::MemCategorizationContext::new(tcx,
+ body_owner,
region_scope_tree,
tables,
rvalue_promotable_map),
impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
pub fn with_infer(delegate: &'a mut (dyn Delegate<'tcx>+'a),
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+ body_owner: DefId,
param_env: ty::ParamEnv<'tcx>,
region_scope_tree: &'a region::ScopeTree,
tables: &'a ty::TypeckTables<'tcx>)
-> Self
{
ExprUseVisitor {
- mc: mc::MemCategorizationContext::with_infer(infcx, region_scope_tree, tables),
+ mc: mc::MemCategorizationContext::with_infer(
+ infcx,
+ body_owner,
+ region_scope_tree,
+ tables,
+ ),
delegate,
param_env,
}
let closure_def_id = self.tcx().hir().local_def_id_from_hir_id(closure_expr.hir_id);
if let Some(upvars) = self.tcx().upvars(closure_def_id) {
- for upvar in upvars.iter() {
- let var_hir_id = upvar.var_id();
+ for (&var_id, upvar) in upvars.iter() {
let upvar_id = ty::UpvarId {
- var_path: ty::UpvarPath { hir_id: var_hir_id },
+ var_path: ty::UpvarPath { hir_id: var_id },
closure_expr_id: closure_def_id.to_local(),
};
let upvar_capture = self.mc.tables.upvar_capture(upvar_id);
let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.hir_id,
fn_decl_span,
- upvar));
+ var_id));
match upvar_capture {
ty::UpvarCapture::ByValue => {
let mode = copy_or_move(&self.mc,
fn cat_captured_var(&mut self,
closure_hir_id: hir::HirId,
closure_span: Span,
- upvar: &hir::Upvar)
+ var_id: hir::HirId)
-> mc::McResult<mc::cmt_<'tcx>> {
// Create the cmt for the variable being borrowed, from the
- // caller's perspective
- let var_hir_id = upvar.var_id();
- let var_ty = self.mc.node_ty(var_hir_id)?;
- self.mc.cat_res(closure_hir_id, closure_span, var_ty, upvar.res)
+ // perspective of the creator (parent) of the closure.
+ let var_ty = self.mc.node_ty(var_id)?;
+ self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id))
}
}
}
fn check_mod_liveness<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
- tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx).as_deep_visitor());
+ tcx.hir().visit_item_likes_in_module(
+ module_def_id,
+ &mut IrMaps::new(tcx, module_def_id).as_deep_visitor(),
+ );
}
pub fn provide(providers: &mut Providers<'_>) {
struct IrMaps<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ body_owner: DefId,
num_live_nodes: usize,
num_vars: usize,
live_node_map: HirIdMap<LiveNode>,
}
impl<'a, 'tcx> IrMaps<'a, 'tcx> {
- fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> IrMaps<'a, 'tcx> {
+ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_owner: DefId) -> IrMaps<'a, 'tcx> {
IrMaps {
tcx,
+ body_owner,
num_live_nodes: 0,
num_vars: 0,
live_node_map: HirIdMap::default(),
debug!("visit_fn");
// swap in a new set of IR maps for this function body:
- let mut fn_maps = IrMaps::new(ir.tcx);
+ let def_id = ir.tcx.hir().local_def_id_from_hir_id(id);
+ let mut fn_maps = IrMaps::new(ir.tcx, def_id);
// Don't run unused pass for #[derive()]
if let FnKind::Method(..) = fk {
// live nodes required for uses or definitions of variables:
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res);
- if let Res::Local(..) = path.res {
- ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+ if let Res::Local(var_hir_id) = path.res {
+ let upvars = ir.tcx.upvars(ir.body_owner);
+ if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hir_id)) {
+ ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+ }
}
intravisit::walk_expr(ir, expr);
}
let mut call_caps = Vec::new();
let closure_def_id = ir.tcx.hir().local_def_id_from_hir_id(expr.hir_id);
if let Some(upvars) = ir.tcx.upvars(closure_def_id) {
- call_caps.extend(upvars.iter().filter_map(|upvar| {
- if let Res::Local(rv) = upvar.res {
+ let parent_upvars = ir.tcx.upvars(ir.body_owner);
+ call_caps.extend(upvars.iter().filter_map(|(&var_id, upvar)| {
+ let has_parent = parent_upvars
+ .map_or(false, |upvars| upvars.contains_key(&var_id));
+ if !has_parent {
let upvar_ln = ir.add_live_node(UpvarNode(upvar.span));
- Some(CaptureInfo { ln: upvar_ln, var_hid: rv })
+ Some(CaptureInfo { ln: upvar_ln, var_hid: var_id })
} else {
None
}
}));
}
ir.set_captures(expr.hir_id, call_caps);
-
+ let old_body_owner = ir.body_owner;
+ ir.body_owner = closure_def_id;
intravisit::walk_expr(ir, expr);
+ ir.body_owner = old_body_owner;
}
// live nodes required for interesting control flow:
-> LiveNode {
match path.res {
Res::Local(hid) => {
- let nid = self.ir.tcx.hir().hir_to_node_id(hid);
- self.access_var(hir_id, nid, succ, acc, path.span)
+ let upvars = self.ir.tcx.upvars(self.ir.body_owner);
+ if !upvars.map_or(false, |upvars| upvars.contains_key(&hid)) {
+ let nid = self.ir.tcx.hir().hir_to_node_id(hid);
+ self.access_var(hir_id, nid, succ, acc, path.span)
+ } else {
+ succ
+ }
}
_ => succ
}
match expr.node {
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
if let Res::Local(var_hid) = path.res {
- // Assignment to an immutable variable or argument: only legal
- // if there is no later assignment. If this local is actually
- // mutable, then check for a reassignment to flag the mutability
- // as being used.
- let ln = self.live_node(expr.hir_id, expr.span);
- let var = self.variable(var_hid, expr.span);
- self.warn_about_dead_assign(expr.span, expr.hir_id, ln, var);
+ let upvars = self.ir.tcx.upvars(self.ir.body_owner);
+ if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hid)) {
+ // Assignment to an immutable variable or argument: only legal
+ // if there is no later assignment. If this local is actually
+ // mutable, then check for a reassignment to flag the mutability
+ // as being used.
+ let ln = self.live_node(expr.hir_id, expr.span);
+ let var = self.variable(var_hid, expr.span);
+ self.warn_about_dead_assign(expr.span, expr.hir_id, ln, var);
+ }
}
}
_ => {
use std::borrow::Cow;
use std::fmt;
use std::hash::{Hash, Hasher};
+use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::indexed_vec::Idx;
use std::rc::Rc;
use crate::util::nodemap::ItemLocalSet;
#[derive(Clone)]
pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ pub body_owner: DefId,
+ pub upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
pub region_scope_tree: &'a region::ScopeTree,
pub tables: &'a ty::TypeckTables<'tcx>,
rvalue_promotable_map: Option<&'tcx ItemLocalSet>,
impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ body_owner: DefId,
region_scope_tree: &'a region::ScopeTree,
tables: &'a ty::TypeckTables<'tcx>,
rvalue_promotable_map: Option<&'tcx ItemLocalSet>)
-> MemCategorizationContext<'a, 'tcx, 'tcx> {
MemCategorizationContext {
tcx,
+ body_owner,
+ upvars: tcx.upvars(body_owner),
region_scope_tree,
tables,
rvalue_promotable_map,
/// - similarly, as the results of upvar analysis are not yet
/// known, the results around upvar accesses may be incorrect.
pub fn with_infer(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+ body_owner: DefId,
region_scope_tree: &'a region::ScopeTree,
tables: &'a ty::TypeckTables<'tcx>)
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
MemCategorizationContext {
tcx,
+ body_owner,
+ upvars: tcx.upvars(body_owner),
region_scope_tree,
tables,
rvalue_promotable_map,
})
}
- Res::Upvar(var_id, _, fn_node_id) => {
+ Res::Local(var_id) => {
let var_nid = self.tcx.hir().hir_to_node_id(var_id);
- self.cat_upvar(hir_id, span, var_nid, fn_node_id)
- }
-
- Res::Local(vid) => {
- let vnid = self.tcx.hir().hir_to_node_id(vid);
- Ok(cmt_ {
- hir_id,
- span,
- cat: Categorization::Local(vid),
- mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vnid),
- ty: expr_ty,
- note: NoteNone
- })
+ if self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) {
+ self.cat_upvar(hir_id, span, var_nid)
+ } else {
+ Ok(cmt_ {
+ hir_id,
+ span,
+ cat: Categorization::Local(var_id),
+ mutbl: MutabilityCategory::from_local(self.tcx, self.tables, var_nid),
+ ty: expr_ty,
+ note: NoteNone
+ })
+ }
}
def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def)
// Categorize an upvar, complete with invisible derefs of closure
// environment and upvar reference as appropriate.
- fn cat_upvar(&self,
- hir_id: hir::HirId,
- span: Span,
- var_id: ast::NodeId,
- fn_node_id: ast::NodeId)
- -> McResult<cmt_<'tcx>>
- {
- let fn_hir_id = self.tcx.hir().node_to_hir_id(fn_node_id);
-
+ fn cat_upvar(
+ &self,
+ hir_id: hir::HirId,
+ span: Span,
+ var_id: ast::NodeId,
+ ) -> McResult<cmt_<'tcx>> {
// An upvar can have up to 3 components. We translate first to a
// `Categorization::Upvar`, which is itself a fiction -- it represents the reference to the
// field from the environment.
// FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
// FnOnce | copied | upvar -> &'up bk
+ let closure_expr_def_id = self.body_owner;
+ let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id(
+ LocalDefId::from_def_id(closure_expr_def_id),
+ );
let ty = self.node_ty(fn_hir_id)?;
let kind = match ty.sty {
ty::Generator(..) => ty::ClosureKind::FnOnce,
_ => span_bug!(span, "unexpected type for fn in mem_categorization: {:?}", ty),
};
- let closure_expr_def_id = self.tcx.hir().local_def_id(fn_node_id);
let var_hir_id = self.tcx.hir().node_to_hir_id(var_id);
let upvar_id = ty::UpvarId {
var_path: ty::UpvarPath { hir_id: var_hir_id },
};
match res {
- Some(Res::Local(hir_id)) | Some(Res::Upvar(hir_id, ..)) => {
+ Some(Res::Local(hir_id)) => {
self.reachable_symbols.insert(hir_id);
}
Some(res) => {
// For Tag=() and no extra state, we have is a trivial implementation.
impl AllocationExtra<()> for () { }
-impl<Tag, Extra> Allocation<Tag, Extra> {
+// The constructors are all without extra; the extra gets added by a machine hook later.
+impl<Tag> Allocation<Tag> {
/// Creates a read-only allocation initialized by the given bytes
- pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align, extra: Extra) -> Self {
+ pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
let bytes = slice.into().into_owned();
let undef_mask = UndefMask::new(Size::from_bytes(bytes.len() as u64), true);
Self {
undef_mask,
align,
mutability: Mutability::Immutable,
- extra,
+ extra: (),
}
}
- pub fn from_byte_aligned_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, extra: Extra) -> Self {
- Allocation::from_bytes(slice, Align::from_bytes(1).unwrap(), extra)
+ pub fn from_byte_aligned_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self {
+ Allocation::from_bytes(slice, Align::from_bytes(1).unwrap())
}
- pub fn undef(size: Size, align: Align, extra: Extra) -> Self {
+ pub fn undef(size: Size, align: Align) -> Self {
assert_eq!(size.bytes() as usize as u64, size.bytes());
Allocation {
bytes: vec![0; size.bytes() as usize],
undef_mask: UndefMask::new(size, false),
align,
mutability: Mutability::Mutable,
- extra,
+ extra: (),
}
}
}
tcx: TyCtxt<'a, 'tcx, 'tcx>,
alloc_id: AllocId,
) -> Result<(), E::Error> {
- let alloc_kind: AllocKind<'tcx> =
+ let alloc: GlobalAlloc<'tcx> =
tcx.alloc_map.lock().get(alloc_id).expect("no value for AllocId");
- match alloc_kind {
- AllocKind::Memory(alloc) => {
+ match alloc {
+ GlobalAlloc::Memory(alloc) => {
trace!("encoding {:?} with {:#?}", alloc_id, alloc);
AllocDiscriminant::Alloc.encode(encoder)?;
alloc.encode(encoder)?;
}
- AllocKind::Function(fn_instance) => {
+ GlobalAlloc::Function(fn_instance) => {
trace!("encoding {:?} with {:#?}", alloc_id, fn_instance);
AllocDiscriminant::Fn.encode(encoder)?;
fn_instance.encode(encoder)?;
}
- AllocKind::Static(did) => {
+ GlobalAlloc::Static(did) => {
// referring to statics doesn't need to know about their allocations,
// just about its DefId
AllocDiscriminant::Static.encode(encoder)?;
assert!(alloc_id.is_none());
trace!("creating extern static alloc id at");
let did = DefId::decode(decoder)?;
- let alloc_id = decoder.tcx().alloc_map.lock().intern_static(did);
+ let alloc_id = decoder.tcx().alloc_map.lock().create_static_alloc(did);
Ok(alloc_id)
}
}
}
}
+/// An allocation in the global (tcx-managed) memory can be either a function pointer,
+/// a static, or a "real" allocation with some data in it.
#[derive(Debug, Clone, Eq, PartialEq, Hash, RustcDecodable, RustcEncodable, HashStable)]
-pub enum AllocKind<'tcx> {
+pub enum GlobalAlloc<'tcx> {
/// The alloc ID is used as a function pointer
Function(Instance<'tcx>),
/// The alloc ID points to a "lazy" static variable that did not get computed (yet).
pub struct AllocMap<'tcx> {
/// Lets you know what an `AllocId` refers to.
- id_to_kind: FxHashMap<AllocId, AllocKind<'tcx>>,
+ alloc_map: FxHashMap<AllocId, GlobalAlloc<'tcx>>,
- /// Used to ensure that statics only get one associated `AllocId`.
- type_interner: FxHashMap<AllocKind<'tcx>, AllocId>,
+ /// Used to ensure that statics and functions only get one associated `AllocId`.
+ /// Should never contain a `GlobalAlloc::Memory`!
+ /// FIXME: Should we just have two separate dedup maps for statics and functions each?
+ dedup: FxHashMap<GlobalAlloc<'tcx>, AllocId>,
/// The `AllocId` to assign to the next requested ID.
/// Always incremented, never gets smaller.
impl<'tcx> AllocMap<'tcx> {
pub fn new() -> Self {
AllocMap {
- id_to_kind: Default::default(),
- type_interner: Default::default(),
+ alloc_map: Default::default(),
+ dedup: Default::default(),
next_id: AllocId(0),
}
}
next
}
- fn intern(&mut self, alloc_kind: AllocKind<'tcx>) -> AllocId {
- if let Some(&alloc_id) = self.type_interner.get(&alloc_kind) {
+ /// Reserve a new ID *if* this allocation has not been dedup-reserved before.
+ /// Should only be used for function pointers and statics, we don't want
+ /// to dedup IDs for "real" memory!
+ fn reserve_and_set_dedup(&mut self, alloc: GlobalAlloc<'tcx>) -> AllocId {
+ match alloc {
+ GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {},
+ GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"),
+ }
+ if let Some(&alloc_id) = self.dedup.get(&alloc) {
return alloc_id;
}
let id = self.reserve();
- debug!("creating alloc_kind {:?} with id {}", alloc_kind, id);
- self.id_to_kind.insert(id, alloc_kind.clone());
- self.type_interner.insert(alloc_kind, id);
+ debug!("creating alloc {:?} with id {}", alloc, id);
+ self.alloc_map.insert(id, alloc.clone());
+ self.dedup.insert(alloc, id);
id
}
+ /// Generates an `AllocId` for a static or return a cached one in case this function has been
+ /// called on the same static before.
+ pub fn create_static_alloc(&mut self, static_id: DefId) -> AllocId {
+ self.reserve_and_set_dedup(GlobalAlloc::Static(static_id))
+ }
+
+ /// Generates an `AllocId` for a function. Depending on the function type,
+ /// this might get deduplicated or assigned a new ID each time.
pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> AllocId {
// Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
// by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
if is_generic {
// Get a fresh ID
let id = self.reserve();
- self.id_to_kind.insert(id, AllocKind::Function(instance));
+ self.alloc_map.insert(id, GlobalAlloc::Function(instance));
id
} else {
// Deduplicate
- self.intern(AllocKind::Function(instance))
+ self.reserve_and_set_dedup(GlobalAlloc::Function(instance))
}
}
+ /// Intern the `Allocation` and return a new `AllocId`, even if there's already an identical
+ /// `Allocation` with a different `AllocId`.
+ /// Statics with identical content will still point to the same `Allocation`, i.e.,
+ /// their data will be deduplicated through `Allocation` interning -- but they
+ /// are different places in memory and as such need different IDs.
+ pub fn create_memory_alloc(&mut self, mem: &'tcx Allocation) -> AllocId {
+ let id = self.reserve();
+ self.set_alloc_id_memory(id, mem);
+ id
+ }
+
/// Returns `None` in case the `AllocId` is dangling. An `InterpretCx` can still have a
/// local `Allocation` for that `AllocId`, but having such an `AllocId` in a constant is
/// illegal and will likely ICE.
/// This function exists to allow const eval to detect the difference between evaluation-
/// local dangling pointers and allocations in constants/statics.
#[inline]
- pub fn get(&self, id: AllocId) -> Option<AllocKind<'tcx>> {
- self.id_to_kind.get(&id).cloned()
+ pub fn get(&self, id: AllocId) -> Option<GlobalAlloc<'tcx>> {
+ self.alloc_map.get(&id).cloned()
}
/// Panics if the `AllocId` does not refer to an `Allocation`
pub fn unwrap_memory(&self, id: AllocId) -> &'tcx Allocation {
match self.get(id) {
- Some(AllocKind::Memory(mem)) => mem,
+ Some(GlobalAlloc::Memory(mem)) => mem,
_ => bug!("expected allocation id {} to point to memory", id),
}
}
- /// Generates an `AllocId` for a static or return a cached one in case this function has been
- /// called on the same static before.
- pub fn intern_static(&mut self, static_id: DefId) -> AllocId {
- self.intern(AllocKind::Static(static_id))
- }
-
- /// Intern the `Allocation` and return a new `AllocId`, even if there's already an identical
- /// `Allocation` with a different `AllocId`.
- // FIXME: is this really necessary? Can we ensure `FOO` and `BAR` being different after codegen
- // in `static FOO: u32 = 42; static BAR: u32 = 42;` even if they reuse the same allocation
- // inside rustc?
- pub fn allocate(&mut self, mem: &'tcx Allocation) -> AllocId {
- let id = self.reserve();
- self.set_alloc_id_memory(id, mem);
- id
- }
-
/// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to
/// call this function twice, even with the same `Allocation` will ICE the compiler.
pub fn set_alloc_id_memory(&mut self, id: AllocId, mem: &'tcx Allocation) {
- if let Some(old) = self.id_to_kind.insert(id, AllocKind::Memory(mem)) {
+ if let Some(old) = self.alloc_map.insert(id, GlobalAlloc::Memory(mem)) {
bug!("tried to set allocation id {}, but it was already existing as {:#?}", id, old);
}
}
/// Freeze an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called
/// twice for the same `(AllocId, Allocation)` pair.
fn set_alloc_id_same_memory(&mut self, id: AllocId, mem: &'tcx Allocation) {
- self.id_to_kind.insert_same(id, AllocKind::Memory(mem));
+ self.alloc_map.insert_same(id, GlobalAlloc::Memory(mem));
}
}
{
Pointer::new_with_tag(self.alloc_id, self.offset, tag)
}
-
- #[inline(always)]
- pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
- where Tag: Default
- {
- self.with_tag(Tag::default())
- }
}
impl<'tcx, Tag> Pointer<Tag> {
"Scalar value {:#x} exceeds size of {} bytes", data, size);
}
+ /// Tag this scalar with `new_tag` if it is a pointer, leave it unchanged otherwise.
+ ///
+ /// Used by `MemPlace::replace_tag`.
#[inline]
pub fn with_tag<Tag>(self, new_tag: Tag) -> Scalar<Tag> {
match self {
Scalar::Raw { data, size } => Scalar::Raw { data, size },
}
}
-
- #[inline(always)]
- pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
- where Tag: Default
- {
- self.with_tag(Tag::default())
- }
}
impl<'tcx, Tag> Scalar<Tag> {
+ /// Erase the tag from the scalar, if any.
+ ///
+ /// Used by error reporting code to avoid having the error type depend on `Tag`.
#[inline]
pub fn erase_tag(self) -> Scalar {
match self {
}
}
-impl<'tcx> ScalarMaybeUndef<()> {
- #[inline]
- pub fn with_tag<Tag>(self, new_tag: Tag) -> ScalarMaybeUndef<Tag> {
- match self {
- ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.with_tag(new_tag)),
- ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
- }
- }
-
- #[inline(always)]
- pub fn with_default_tag<Tag>(self) -> ScalarMaybeUndef<Tag>
- where Tag: Default
- {
- self.with_tag(Tag::default())
- }
-}
-
impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
+ /// Erase the tag from the scalar, if any.
+ ///
+ /// Used by error reporting code to avoid having the error type depend on `Tag`.
#[inline]
pub fn erase_tag(self) -> ScalarMaybeUndef
{
let mut struct_fmt = fmt.debug_struct(&name);
if let Some(upvars) = tcx.upvars(def_id) {
- for (upvar, place) in upvars.iter().zip(places) {
- let var_name = tcx.hir().name_by_hir_id(upvar.var_id());
+ for (&var_id, place) in upvars.keys().zip(places) {
+ let var_name = tcx.hir().name_by_hir_id(var_id);
struct_fmt.field(&var_name.as_str(), place);
}
}
let mut struct_fmt = fmt.debug_struct(&name);
if let Some(upvars) = tcx.upvars(def_id) {
- for (upvar, place) in upvars.iter().zip(places) {
- let var_name = tcx.hir().name_by_hir_id(upvar.var_id());
+ for (&var_id, place) in upvars.keys().zip(places) {
+ let var_name = tcx.hir().name_by_hir_id(var_id);
struct_fmt.field(&var_name.as_str(), place);
}
}
load_cached(tcx, id) {
let generics: Option<ty::Generics> = tcx.queries.on_disk_cache
.try_load_query_result(tcx, id);
- generics.map(|x| tcx.alloc_generics(x))
+ generics.map(|x| &*tcx.arena.alloc(x))
}
}
load_cached(tcx, id) {
let mir: Option<crate::mir::Body<'tcx>> = tcx.queries.on_disk_cache
.try_load_query_result(tcx, id);
- mir.map(|x| tcx.alloc_mir(x))
+ mir.map(|x| &*tcx.arena.alloc(x))
}
}
}
.queries.on_disk_cache
.try_load_query_result(tcx, id);
- typeck_tables.map(|tables| tcx.alloc_tables(tables))
+ typeck_tables.map(|tables| &*tcx.arena.alloc(tables))
}
}
}
desc { "generating a postorder list of CrateNums" }
}
- query upvars(_: DefId) -> Option<&'tcx [hir::Upvar]> {
+ query upvars(_: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
eval_always
}
query maybe_unused_trait_import(_: DefId) -> bool {
}
// already reported in the query
- ConstEvalFailure(_) => {
- self.tcx.sess.delay_span_bug(span, "constant in type had an ignored error");
+ ConstEvalFailure(err) => {
+ self.tcx.sess.delay_span_bug(
+ span,
+ &format!("constant in type had an ignored error: {:?}", err),
+ );
return;
}
use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
StableHasher, StableHasherResult,
StableVec};
-use arena::{TypedArena, SyncDroplessArena};
+use arena::SyncDroplessArena;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal};
use std::any::Any;
use crate::hir;
-pub struct AllArenas<'tcx> {
- pub global: WorkerLocal<GlobalArenas<'tcx>>,
+pub struct AllArenas {
pub interner: SyncDroplessArena,
}
-impl<'tcx> AllArenas<'tcx> {
+impl AllArenas {
pub fn new() -> Self {
AllArenas {
- global: WorkerLocal::new(|_| GlobalArenas::default()),
interner: SyncDroplessArena::default(),
}
}
}
-/// Internal storage
-#[derive(Default)]
-pub struct GlobalArenas<'tcx> {
- // internings
- layout: TypedArena<LayoutDetails>,
-
- // references
- generics: TypedArena<ty::Generics>,
- trait_def: TypedArena<ty::TraitDef>,
- adt_def: TypedArena<ty::AdtDef>,
- steal_mir: TypedArena<Steal<Body<'tcx>>>,
- mir: TypedArena<Body<'tcx>>,
- tables: TypedArena<ty::TypeckTables<'tcx>>,
- /// miri allocations
- const_allocs: TypedArena<interpret::Allocation>,
-}
-
type InternedSet<'tcx, T> = Lock<FxHashMap<Interned<'tcx, T>, ()>>;
pub struct CtxtInterners<'tcx> {
pub struct GlobalCtxt<'tcx> {
pub arena: WorkerLocal<Arena<'tcx>>,
- global_arenas: &'tcx WorkerLocal<GlobalArenas<'tcx>>,
+
global_interners: CtxtInterners<'tcx>,
cstore: &'tcx CrateStoreDyn,
pub queries: query::Queries<'tcx>,
- // Records the captured variables referenced by every closure
- // expression. Do not track deps for this, just recompute it from
- // scratch every time.
- upvars: FxHashMap<DefId, Vec<hir::Upvar>>,
-
maybe_unused_trait_imports: FxHashSet<DefId>,
maybe_unused_extern_crates: Vec<(DefId, Span)>,
/// A map of glob use to a set of names it actually imports. Currently only
&self.hir_map
}
- pub fn alloc_generics(self, generics: ty::Generics) -> &'gcx ty::Generics {
- self.global_arenas.generics.alloc(generics)
- }
-
pub fn alloc_steal_mir(self, mir: Body<'gcx>) -> &'gcx Steal<Body<'gcx>> {
- self.global_arenas.steal_mir.alloc(Steal::new(mir))
- }
-
- pub fn alloc_mir(self, mir: Body<'gcx>) -> &'gcx Body<'gcx> {
- self.global_arenas.mir.alloc(mir)
- }
-
- pub fn alloc_tables(self, tables: ty::TypeckTables<'gcx>) -> &'gcx ty::TypeckTables<'gcx> {
- self.global_arenas.tables.alloc(tables)
- }
-
- pub fn alloc_trait_def(self, def: ty::TraitDef) -> &'gcx ty::TraitDef {
- self.global_arenas.trait_def.alloc(def)
+ self.arena.alloc(Steal::new(mir))
}
pub fn alloc_adt_def(self,
repr: ReprOptions)
-> &'gcx ty::AdtDef {
let def = ty::AdtDef::new(self, did, kind, variants, repr);
- self.global_arenas.adt_def.alloc(def)
+ self.arena.alloc(def)
}
pub fn intern_const_alloc(self, alloc: Allocation) -> &'gcx Allocation {
self.allocation_interner.borrow_mut().intern(alloc, |alloc| {
- self.global_arenas.const_allocs.alloc(alloc)
+ self.arena.alloc(alloc)
})
}
/// Allocates a byte or string literal for `mir::interpret`, read-only
pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
// create an allocation that just contains these bytes
- let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes, ());
+ let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
let alloc = self.intern_const_alloc(alloc);
- self.alloc_map.lock().allocate(alloc)
+ self.alloc_map.lock().create_memory_alloc(alloc)
}
pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability {
self.stability_interner.borrow_mut().intern(stab, |stab| {
- self.global_interners.arena.alloc(stab)
+ self.arena.alloc(stab)
})
}
pub fn intern_layout(self, layout: LayoutDetails) -> &'gcx LayoutDetails {
self.layout_interner.borrow_mut().intern(layout, |layout| {
- self.global_arenas.layout.alloc(layout)
+ self.arena.alloc(layout)
})
}
cstore: &'tcx CrateStoreDyn,
local_providers: ty::query::Providers<'tcx>,
extern_providers: ty::query::Providers<'tcx>,
- arenas: &'tcx AllArenas<'tcx>,
+ arenas: &'tcx AllArenas,
resolutions: ty::Resolutions,
hir: hir_map::Map<'tcx>,
on_disk_query_result_cache: query::OnDiskCache<'tcx>,
sess: s,
cstore,
arena: WorkerLocal::new(|_| Arena::default()),
- global_arenas: &arenas.global,
global_interners: interners,
dep_graph,
common,
}).collect();
(k, exports)
}).collect(),
- upvars: resolutions.upvars.into_iter().map(|(k, v)| {
- let vars: Vec<_> = v.into_iter().map(|e| {
- e.map_id(|id| hir.node_to_hir_id(id))
- }).collect();
- (hir.local_def_id(k), vars)
- }).collect(),
maybe_unused_trait_imports:
resolutions.maybe_unused_trait_imports
.into_iter()
assert_eq!(id, LOCAL_CRATE);
tcx.arena.alloc(middle::lang_items::collect(tcx))
};
- providers.upvars = |tcx, id| tcx.gcx.upvars.get(&id).map(|v| &v[..]);
providers.maybe_unused_trait_import = |tcx, id| {
tcx.maybe_unused_trait_imports.contains(&id)
};
}
}
+ let count = count.assert_usize(tcx).ok_or(LayoutError::Unknown(ty))?;
let element = self.layout_of(element)?;
- let count = count.unwrap_usize(tcx);
let size = element.size.checked_mul(count, dl)
.ok_or(LayoutError::SizeOverflow(ty))?;
pub use self::IntVarValue::*;
pub use self::fold::TypeFoldable;
-use crate::hir::{map as hir_map, UpvarMap, GlobMap, TraitMap};
+use crate::hir::{map as hir_map, GlobMap, TraitMap};
use crate::hir::Node;
use crate::hir::def::{Res, DefKind, CtorOf, CtorKind, ExportMap};
use crate::hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use syntax_pos::Span;
use smallvec;
+use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
HashStable};
pub use self::binding::BindingMode;
pub use self::binding::BindingMode::*;
-pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, keep_local};
+pub use self::context::{TyCtxt, FreeRegionInfo, AllArenas, tls, keep_local};
pub use self::context::{Lift, TypeckTables, CtxtInterners, GlobalCtxt};
pub use self::context::{
UserTypeAnnotationIndex, UserType, CanonicalUserType,
#[derive(Clone)]
pub struct Resolutions {
- pub upvars: UpvarMap,
pub trait_map: TraitMap,
pub maybe_unused_trait_imports: NodeSet,
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
pub region: ty::Region<'tcx>,
}
-pub type UpvarListMap = FxHashMap<DefId, Vec<UpvarId>>;
+pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
#[derive(Copy, Clone)]
if let Some(hir_id) = self.tcx().hir().as_local_hir_id(did) {
p!(write("@{:?}", self.tcx().hir().span_by_hir_id(hir_id)));
let mut sep = " ";
- for (upvar, upvar_ty) in self.tcx().upvars(did)
+ for (&var_id, upvar_ty) in self.tcx().upvars(did)
.as_ref()
- .map_or(&[][..], |v| &v[..])
.iter()
+ .flat_map(|v| v.keys())
.zip(upvar_tys)
{
p!(
write("{}{}:",
sep,
- self.tcx().hir().name_by_hir_id(upvar.var_id())),
+ self.tcx().hir().name_by_hir_id(var_id)),
print(upvar_ty));
sep = ", ";
}
p!(write("@{:?}", self.tcx().hir().span_by_hir_id(hir_id)));
}
let mut sep = " ";
- for (upvar, upvar_ty) in self.tcx().upvars(did)
+ for (&var_id, upvar_ty) in self.tcx().upvars(did)
.as_ref()
- .map_or(&[][..], |v| &v[..])
.iter()
+ .flat_map(|v| v.keys())
.zip(upvar_tys)
{
p!(
write("{}{}:",
sep,
- self.tcx().hir().name_by_hir_id(upvar.var_id())),
+ self.tcx().hir().name_by_hir_id(var_id)),
print(upvar_ty));
sep = ", ";
}
br
}
ty::BrAnon(_) |
- ty::BrFresh(_) |
ty::BrEnv => {
let name = loop {
let name = name_by_region_index(region_index);
use rustc_data_structures::svh::Svh;
use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::indexed_vec::IndexVec;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::StableVec;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::fingerprint::Fingerprint;
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
- ty::BrFresh(n) => write!(f, "BrFresh({:?})", n),
ty::BrNamed(did, name) => {
write!(f, "BrNamed({:?}:{:?}, {})",
did.krate, did.index, name)
/// the event of shadowing.
BrNamed(DefId, InternedString),
- /// Fresh bound identifiers created during GLB computations.
- BrFresh(u32),
-
/// Anonymous region for the implicit env pointer parameter
/// to a closure
BrEnv,
let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
euv::ExprUseVisitor::new(&mut clcx,
bccx.tcx,
+ def_id,
param_env,
&bccx.region_scope_tree,
bccx.tables,
let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
euv::ExprUseVisitor::new(&mut glcx,
bccx.tcx,
+ def_id,
param_env,
&bccx.region_scope_tree,
bccx.tables,
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_target::spec::{HasTargetSpec, Target};
use std::borrow::Cow;
+use std::ffi::CStr;
use std::ops::{Deref, Range};
use std::ptr;
use std::iter::TrustedLen;
}
}
-// This is a really awful way to get a zero-length c-string, but better (and a
-// lot more efficient) than doing str::as_c_str("", ...) every time.
-fn noname() -> *const c_char {
- static CNULL: c_char = 0;
- &CNULL
-}
+// FIXME(eddyb) use a checked constructor when they become `const fn`.
+const EMPTY_C_STR: &CStr = unsafe {
+ CStr::from_bytes_with_nul_unchecked(b"\0")
+};
+
+/// Empty string, to be used where LLVM expects an instruction name, indicating
+/// that the instruction is to be left unnamed (i.e. numbered, in textual IR).
+// FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer.
+const UNNAMED: *const c_char = EMPTY_C_STR.as_ptr();
impl BackendTypes for Builder<'_, 'll, 'tcx> {
type Value = <CodegenCx<'ll, 'tcx> as BackendTypes>::Value;
type CodegenCx = CodegenCx<'ll, 'tcx>;
}
+macro_rules! builder_methods_for_value_instructions {
+ ($($name:ident($($arg:ident),*) => $llvm_capi:ident),+ $(,)?) => {
+ $(fn $name(&mut self, $($arg: &'ll Value),*) -> &'ll Value {
+ unsafe {
+ llvm::$llvm_capi(self.llbuilder, $($arg,)* UNNAMED)
+ }
+ })*
+ }
+}
+
impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn new_block<'b>(
cx: &'a CodegenCx<'ll, 'tcx>,
then,
catch,
bundle,
- noname())
+ UNNAMED)
}
}
}
}
- /* Arithmetic */
- fn add(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildAdd(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn fadd(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname())
- }
+ builder_methods_for_value_instructions! {
+ add(a, b) => LLVMBuildAdd,
+ fadd(a, b) => LLVMBuildFAdd,
+ sub(a, b) => LLVMBuildSub,
+ fsub(a, b) => LLVMBuildFSub,
+ mul(a, b) => LLVMBuildMul,
+ fmul(a, b) => LLVMBuildFMul,
+ udiv(a, b) => LLVMBuildUDiv,
+ exactudiv(a, b) => LLVMBuildExactUDiv,
+ sdiv(a, b) => LLVMBuildSDiv,
+ exactsdiv(a, b) => LLVMBuildExactSDiv,
+ fdiv(a, b) => LLVMBuildFDiv,
+ urem(a, b) => LLVMBuildURem,
+ srem(a, b) => LLVMBuildSRem,
+ frem(a, b) => LLVMBuildFRem,
+ shl(a, b) => LLVMBuildShl,
+ lshr(a, b) => LLVMBuildLShr,
+ ashr(a, b) => LLVMBuildAShr,
+ and(a, b) => LLVMBuildAnd,
+ or(a, b) => LLVMBuildOr,
+ xor(a, b) => LLVMBuildXor,
+ neg(x) => LLVMBuildNeg,
+ fneg(x) => LLVMBuildFNeg,
+ not(x) => LLVMBuildNot,
}
fn fadd_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
unsafe {
- let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname());
+ let instr = llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, UNNAMED);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
- fn sub(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildSub(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn fsub(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname())
- }
- }
-
fn fsub_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
unsafe {
- let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname());
+ let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, UNNAMED);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
- fn mul(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildMul(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn fmul(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname())
- }
- }
-
fn fmul_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
unsafe {
- let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname());
+ let instr = llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, UNNAMED);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
-
- fn udiv(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildUDiv(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn exactudiv(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildExactUDiv(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn sdiv(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildSDiv(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn exactsdiv(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildExactSDiv(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn fdiv(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname())
- }
- }
-
fn fdiv_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
unsafe {
- let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname());
+ let instr = llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, UNNAMED);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
- fn urem(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildURem(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn srem(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildSRem(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn frem(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname())
- }
- }
-
fn frem_fast(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
unsafe {
- let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname());
+ let instr = llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, UNNAMED);
llvm::LLVMRustSetHasUnsafeAlgebra(instr);
instr
}
}
- fn shl(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildShl(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn lshr(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildLShr(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn ashr(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildAShr(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn and(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildAnd(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn or(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildOr(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn xor(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildXor(self.llbuilder, lhs, rhs, noname())
- }
- }
-
- fn neg(&mut self, v: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildNeg(self.llbuilder, v, noname())
- }
- }
-
- fn fneg(&mut self, v: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildFNeg(self.llbuilder, v, noname())
- }
- }
-
- fn not(&mut self, v: &'ll Value) -> &'ll Value {
- unsafe {
- llvm::LLVMBuildNot(self.llbuilder, v, noname())
- }
- }
-
fn checked_binop(
&mut self,
oop: OverflowOp,
fn dynamic_alloca(&mut self, ty: &'ll Type, name: &str, align: Align) -> &'ll Value {
unsafe {
let alloca = if name.is_empty() {
- llvm::LLVMBuildAlloca(self.llbuilder, ty, noname())
+ llvm::LLVMBuildAlloca(self.llbuilder, ty, UNNAMED)
} else {
let name = SmallCStr::new(name);
llvm::LLVMBuildAlloca(self.llbuilder, ty,
align: Align) -> &'ll Value {
unsafe {
let alloca = if name.is_empty() {
- llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, noname())
+ llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, UNNAMED)
} else {
let name = SmallCStr::new(name);
llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len,
fn load(&mut self, ptr: &'ll Value, align: Align) -> &'ll Value {
unsafe {
- let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname());
+ let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, UNNAMED);
llvm::LLVMSetAlignment(load, align.bytes() as c_uint);
load
}
fn volatile_load(&mut self, ptr: &'ll Value) -> &'ll Value {
unsafe {
- let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, noname());
+ let load = llvm::LLVMBuildLoad(self.llbuilder, ptr, UNNAMED);
llvm::LLVMSetVolatile(load, llvm::True);
load
}
let load = llvm::LLVMRustBuildAtomicLoad(
self.llbuilder,
ptr,
- noname(),
+ UNNAMED,
AtomicOrdering::from_generic(order),
);
// LLVM requires the alignment of atomic loads to be at least the size of the type.
fn gep(&mut self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
unsafe {
llvm::LLVMBuildGEP(self.llbuilder, ptr, indices.as_ptr(),
- indices.len() as c_uint, noname())
+ indices.len() as c_uint, UNNAMED)
}
}
fn inbounds_gep(&mut self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
unsafe {
llvm::LLVMBuildInBoundsGEP(
- self.llbuilder, ptr, indices.as_ptr(), indices.len() as c_uint, noname())
+ self.llbuilder, ptr, indices.as_ptr(), indices.len() as c_uint, UNNAMED)
}
}
fn struct_gep(&mut self, ptr: &'ll Value, idx: u64) -> &'ll Value {
assert_eq!(idx as c_uint as u64, idx);
unsafe {
- llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, noname())
+ llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, UNNAMED)
}
}
/* Casts */
fn trunc(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty, UNNAMED)
}
}
fn sext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty, UNNAMED)
}
}
fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty, UNNAMED)
}
}
fn fptosi(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty,noname())
+ llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty,UNNAMED)
}
}
fn uitofp(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty, UNNAMED)
}
}
fn sitofp(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty, UNNAMED)
}
}
fn fptrunc(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty, UNNAMED)
}
}
fn fpext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty, UNNAMED)
}
}
fn ptrtoint(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty, UNNAMED)
}
}
fn inttoptr(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty, UNNAMED)
}
}
fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED)
}
}
fn pointercast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty, UNNAMED)
}
}
fn icmp(&mut self, op: IntPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
let op = llvm::IntPredicate::from_generic(op);
unsafe {
- llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
+ llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, UNNAMED)
}
}
fn fcmp(&mut self, op: RealPredicate, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value {
unsafe {
- llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
+ llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, UNNAMED)
}
}
else_val: &'ll Value,
) -> &'ll Value {
unsafe {
- llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, noname())
+ llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, UNNAMED)
}
}
#[allow(dead_code)]
fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildVAArg(self.llbuilder, list, ty, noname())
+ llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED)
}
}
fn extract_element(&mut self, vec: &'ll Value, idx: &'ll Value) -> &'ll Value {
unsafe {
- llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, noname())
+ llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, UNNAMED)
}
}
fn extract_value(&mut self, agg_val: &'ll Value, idx: u64) -> &'ll Value {
assert_eq!(idx as c_uint as u64, idx);
unsafe {
- llvm::LLVMBuildExtractValue(self.llbuilder, agg_val, idx as c_uint, noname())
+ llvm::LLVMBuildExtractValue(self.llbuilder, agg_val, idx as c_uint, UNNAMED)
}
}
assert_eq!(idx as c_uint as u64, idx);
unsafe {
llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint,
- noname())
+ UNNAMED)
}
}
num_clauses: usize) -> &'ll Value {
unsafe {
llvm::LLVMBuildLandingPad(self.llbuilder, ty, pers_fn,
- num_clauses as c_uint, noname())
+ num_clauses as c_uint, UNNAMED)
}
}
llfn,
args.as_ptr() as *const &llvm::Value,
args.len() as c_uint,
- bundle, noname()
+ bundle, UNNAMED
)
}
}
fn zext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty, noname())
+ llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty, UNNAMED)
}
}
idx: &'ll Value,
) -> &'ll Value {
unsafe {
- llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, noname())
+ llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, UNNAMED)
}
}
mask: &'ll Value,
) -> &'ll Value {
unsafe {
- llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, noname())
+ llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, UNNAMED)
}
}
pub fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value {
unsafe {
- llvm::LLVMBuildVAArg(self.llbuilder, list, ty, noname())
+ llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED)
}
}
fn phi(&mut self, ty: &'ll Type, vals: &[&'ll Value], bbs: &[&'ll BasicBlock]) -> &'ll Value {
assert_eq!(vals.len(), bbs.len());
let phi = unsafe {
- llvm::LLVMBuildPhi(self.llbuilder, ty, noname())
+ llvm::LLVMBuildPhi(self.llbuilder, ty, UNNAMED)
};
unsafe {
llvm::LLVMAddIncoming(phi, vals.as_ptr(),
use crate::consts::const_alloc_to_llvm;
use rustc::ty::layout::{HasDataLayout, LayoutOf, self, TyLayout, Size};
-use rustc::mir::interpret::{Scalar, AllocKind, Allocation};
+use rustc::mir::interpret::{Scalar, GlobalAlloc, Allocation};
use rustc_codegen_ssa::mir::place::PlaceRef;
use libc::{c_uint, c_char};
Scalar::Ptr(ptr) => {
let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
let base_addr = match alloc_kind {
- Some(AllocKind::Memory(alloc)) => {
+ Some(GlobalAlloc::Memory(alloc)) => {
let init = const_alloc_to_llvm(self, alloc);
if alloc.mutability == Mutability::Mutable {
self.static_addr_of_mut(init, alloc.align, None)
self.static_addr_of(init, alloc.align, None)
}
}
- Some(AllocKind::Function(fn_instance)) => {
+ Some(GlobalAlloc::Function(fn_instance)) => {
self.get_fn(fn_instance)
}
- Some(AllocKind::Static(def_id)) => {
+ Some(GlobalAlloc::Static(def_id)) => {
assert!(self.tcx.is_static(def_id));
self.get_static(def_id)
}
let (size, align) = cx.size_and_align_of(array_or_slice_type);
let upper_bound = match array_or_slice_type.sty {
- ty::Array(_, len) => {
- len.unwrap_usize(cx.tcx) as c_longlong
- }
+ ty::Array(_, len) => len.unwrap_usize(cx.tcx) as c_longlong,
_ => -1
};
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(const_cstr_unchecked)]
#![feature(crate_visibility_modifier)]
#![feature(custom_attribute)]
#![feature(extern_types)]
@irinagpopa started to parametrize the types of `rustc_codegen_llvm` by a generic `Value` type, implemented in LLVM by a reference `&'ll Value`. This work has been extended to all structures inside the `mir` folder and elsewhere, as well as for LLVM's `BasicBlock` and `Type` types.
-The two most important structures for the LLVM codegen are `CodegenCx` and `Builder`. They are parametrized by multiple liftime parameters and the type for `Value`.
+The two most important structures for the LLVM codegen are `CodegenCx` and `Builder`. They are parametrized by multiple lifetime parameters and the type for `Value`.
```rust
struct CodegenCx<'ll, 'tcx: 'll> {
_ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout)
};
let a = Scalar::from(Pointer::new(
- bx.tcx().alloc_map.lock().allocate(data),
+ bx.tcx().alloc_map.lock().create_memory_alloc(data),
Size::from_bytes(start as u64),
)).into();
let a_llval = bx.scalar_to_backend(
'-' | ':' => self.path.temp_buf.push('.'),
// Avoid crashing LLVM in certain (LTO-related) situations, see #60925.
- 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$6d$"),
+ 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$u6d$"),
// These are legal symbols
'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c),
[dependencies]
ena = "0.13"
+indexmap = "1"
log = "0.4"
jobserver_crate = { version = "0.1.13", package = "jobserver" }
lazy_static = "1"
+use std::hash::BuildHasherDefault;
+
pub use rustc_hash::{FxHasher, FxHashMap, FxHashSet};
+
+pub type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
+pub type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
}
}
+impl<K, V, R, CTX> HashStable<CTX> for indexmap::IndexMap<K, V, R>
+ where K: HashStable<CTX> + Eq + Hash,
+ V: HashStable<CTX>,
+ R: BuildHasher,
+{
+ #[inline]
+ fn hash_stable<W: StableHasherResult>(&self,
+ ctx: &mut CTX,
+ hasher: &mut StableHasher<W>) {
+ self.len().hash_stable(ctx, hasher);
+ for kv in self {
+ kv.hash_stable(ctx, hasher);
+ }
+ }
+}
+
+impl<K, R, CTX> HashStable<CTX> for indexmap::IndexSet<K, R>
+ where K: HashStable<CTX> + Eq + Hash,
+ R: BuildHasher,
+{
+ #[inline]
+ fn hash_stable<W: StableHasherResult>(&self,
+ ctx: &mut CTX,
+ hasher: &mut StableHasher<W>) {
+ self.len().hash_stable(ctx, hasher);
+ for key in self {
+ key.hash_stable(ctx, hasher);
+ }
+ }
+}
+
impl<A, CTX> HashStable<CTX> for SmallVec<[A; 1]> where A: HashStable<CTX> {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
ExpansionResult {
defs: Steal::new(resolver.definitions),
resolutions: Steal::new(Resolutions {
- upvars: resolver.upvars,
export_map: resolver.export_map,
trait_map: resolver.trait_map,
glob_map: resolver.glob_map,
ExpansionResult {
defs: Steal::new(resolver.definitions.clone()),
resolutions: Steal::new(Resolutions {
- upvars: resolver.upvars.clone(),
export_map: resolver.export_map.clone(),
trait_map: resolver.trait_map.clone(),
glob_map: resolver.glob_map.clone(),
declare_lint! {
pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
- Allow,
+ Warn,
"`...` range patterns are deprecated"
}
provide! { <'tcx> tcx, def_id, other, cdata,
type_of => { cdata.get_type(def_id.index, tcx) }
generics_of => {
- tcx.alloc_generics(cdata.get_generics(def_id.index, tcx.sess))
+ tcx.arena.alloc(cdata.get_generics(def_id.index, tcx.sess))
}
predicates_of => { tcx.arena.alloc(cdata.get_predicates(def_id.index, tcx)) }
predicates_defined_on => {
}
super_predicates_of => { tcx.arena.alloc(cdata.get_super_predicates(def_id.index, tcx)) }
trait_def => {
- tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx.sess))
+ tcx.arena.alloc(cdata.get_trait_def(def_id.index, tcx.sess))
}
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
adt_destructor => {
bug!("get_optimized_mir: missing MIR for `{:?}`", def_id)
});
- let mir = tcx.alloc_mir(mir);
+ let mir = tcx.arena.alloc(mir);
mir
}
// `tcx.upvars(def_id)` returns an `Option`, which is `None` in case
// the closure comes from another crate. But in that case we wouldn't
// be borrowck'ing it, so we can just unwrap:
- let upvar = self.infcx.tcx.upvars(def_id).unwrap()[field.index()];
+ let (&var_id, _) = self.infcx.tcx.upvars(def_id).unwrap()
+ .get_index(field.index()).unwrap();
- self.infcx.tcx.hir().name_by_hir_id(upvar.var_id()).to_string()
+ self.infcx.tcx.hir().name_by_hir_id(var_id).to_string()
}
_ => {
// Might need a revision when the fields in trait RFC is implemented
if let hir::ExprKind::Closure(
.., args_span, _
) = expr {
- for (v, place) in self.infcx.tcx.upvars(def_id)?.iter().zip(places) {
+ for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) {
match place {
Operand::Copy(place) |
Operand::Move(place) if target_place == place => {
debug!("closure_span: found captured local {:?}", place);
- return Some((*args_span, v.span));
+ return Some((*args_span, upvar.span));
},
_ => {}
}
.upvar_list
.get(&def_id)
.into_iter()
- .flatten()
+ .flat_map(|v| v.values())
.map(|upvar_id| {
let var_hir_id = upvar_id.var_path.hir_id;
let var_node_id = tcx.hir().hir_to_node_id(var_hir_id);
}
}
- ty::BoundRegion::BrAnon(_) | ty::BoundRegion::BrFresh(_) => None,
+ ty::BoundRegion::BrAnon(_) => None,
},
ty::ReLateBound(..)
},
(StaticKind::Promoted(promoted_1), StaticKind::Promoted(promoted_2)) => {
if promoted_1 == promoted_2 {
- if let ty::Array(_, size) = s1.ty.sty {
- if size.unwrap_usize(tcx) == 0 {
+ if let ty::Array(_, len) = s1.ty.sty {
+ if let Some(0) = len.assert_usize(tcx) {
// Ignore conflicts with promoted [T; 0].
debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
return Overlap::Disjoint;
.get(&fn_def_id)
.into_iter()
.flatten()
- .map(|upvar_id| {
- let var_hir_id = upvar_id.var_path.hir_id;
+ .map(|(&var_hir_id, &upvar_id)| {
let var_node_id = tcx_hir.hir_to_node_id(var_hir_id);
- let capture = hir_tables.upvar_capture(*upvar_id);
+ let capture = hir_tables.upvar_capture(upvar_id);
let by_ref = match capture {
ty::UpvarCapture::ByValue => false,
ty::UpvarCapture::ByRef(..) => true,
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
use rustc::mir;
use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
-use rustc::ty::layout::{self, LayoutOf, VariantIdx, Size};
+use rustc::ty::layout::{self, LayoutOf, VariantIdx};
use rustc::ty::subst::Subst;
use rustc::traits::Reveal;
use rustc::util::common::ErrorReported;
),
Scalar::Raw { .. } => (
ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(
- b"" as &[u8], (),
+ b"" as &[u8],
)),
0,
),
fn find_foreign_static(
_def_id: DefId,
_tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
- _memory_extra: &(),
) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
err!(ReadForeignStatic)
}
#[inline(always)]
- fn adjust_static_allocation<'b>(
- alloc: &'b Allocation,
+ fn tag_allocation<'b>(
+ _id: AllocId,
+ alloc: Cow<'b, Allocation>,
+ _kind: Option<MemoryKind<!>>,
_memory_extra: &(),
- ) -> Cow<'b, Allocation<Self::PointerTag>> {
- // We do not use a tag so we can just cheaply forward the reference
- Cow::Borrowed(alloc)
+ ) -> (Cow<'b, Allocation<Self::PointerTag>>, Self::PointerTag) {
+ // We do not use a tag so we can just cheaply forward the allocation
+ (alloc, ())
}
#[inline(always)]
- fn new_allocation(
- _size: Size,
- _extra: &Self::MemoryExtra,
- _kind: MemoryKind<!>,
- ) -> (Self::AllocExtra, Self::PointerTag) {
- ((), ())
+ fn tag_static_base_pointer(
+ _id: AllocId,
+ _memory_extra: &(),
+ ) -> Self::PointerTag {
+ ()
}
fn box_alloc(
let lit = match *lit {
LitKind::Str(ref s, _) => {
let s = s.as_str();
- let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes(), ());
+ let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: s.len() }
},
LitKind::Err(ref s) => {
let s = s.as_str();
- let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes(), ());
+ let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
let allocation = tcx.intern_const_alloc(allocation);
return Ok(tcx.mk_const(ty::Const {
val: ConstValue::Slice{ data: allocation, start: 0, end: s.len() },
let upvars = cx.tcx.upvars(def_id).iter()
.flat_map(|upvars| upvars.iter())
.zip(substs.upvar_tys(def_id, cx.tcx))
- .map(|(upvar, ty)| capture_upvar(cx, expr, upvar, ty))
+ .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty))
.collect();
ExprKind::Closure {
closure_id: def_id,
Res::Def(DefKind::Static, id) => ExprKind::StaticRef { id },
- Res::Local(..) | Res::Upvar(..) => convert_var(cx, expr, res),
+ Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id),
_ => span_bug!(expr.span, "res `{:?}` not yet implemented", res),
}
}
-fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
- expr: &'tcx hir::Expr,
- res: Res)
- -> ExprKind<'tcx> {
+fn convert_var(
+ cx: &mut Cx<'_, '_, 'tcx>,
+ expr: &'tcx hir::Expr,
+ var_hir_id: hir::HirId,
+) -> ExprKind<'tcx> {
+ let upvar_index = cx.tables().upvar_list.get(&cx.body_owner)
+ .and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i));
+
+ debug!("convert_var({:?}): upvar_index={:?}, body_owner={:?}",
+ var_hir_id, upvar_index, cx.body_owner);
+
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
- match res {
- Res::Local(id) => ExprKind::VarRef { id },
+ match upvar_index {
+ None => ExprKind::VarRef { id: var_hir_id },
- Res::Upvar(var_hir_id, index, closure_expr_id) => {
- debug!("convert_var(upvar({:?}, {:?}, {:?}))",
- var_hir_id,
- index,
- closure_expr_id);
+ Some(upvar_index) => {
+ let closure_def_id = cx.body_owner;
+ let upvar_id = ty::UpvarId {
+ var_path: ty::UpvarPath {hir_id: var_hir_id},
+ closure_expr_id: LocalDefId::from_def_id(closure_def_id),
+ };
let var_ty = cx.tables().node_type(var_hir_id);
// FIXME free regions in closures are not right
- let closure_ty = cx.tables()
- .node_type(cx.tcx.hir().node_to_hir_id(closure_expr_id));
+ let closure_ty = cx.tables().node_type(
+ cx.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id),
+ );
// FIXME we're just hard-coding the idea that the
// signature will be &self or &mut self and hence will
// have a bound region with number 0
- let closure_def_id = cx.tcx.hir().local_def_id(closure_expr_id);
let region = ty::ReFree(ty::FreeRegion {
scope: closure_def_id,
bound_region: ty::BoundRegion::BrAnon(0),
// at this point we have `self.n`, which loads up the upvar
let field_kind = ExprKind::Field {
lhs: self_expr.to_ref(),
- name: Field::new(index),
+ name: Field::new(upvar_index),
};
// ...but the upvar might be an `&T` or `&mut T` capture, at which
// point we need an implicit deref
- let upvar_id = ty::UpvarId {
- var_path: ty::UpvarPath {hir_id: var_hir_id},
- closure_expr_id: LocalDefId::from_def_id(closure_def_id),
- };
match cx.tables().upvar_capture(upvar_id) {
ty::UpvarCapture::ByValue => field_kind,
ty::UpvarCapture::ByRef(borrow) => {
}
}
}
-
- _ => span_bug!(expr.span, "type of & not region"),
}
}
fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
closure_expr: &'tcx hir::Expr,
- upvar: &hir::Upvar,
+ var_hir_id: hir::HirId,
upvar_ty: Ty<'tcx>)
-> ExprRef<'tcx> {
- let var_hir_id = upvar.var_id();
let upvar_id = ty::UpvarId {
var_path: ty::UpvarPath { hir_id: var_hir_id },
closure_expr_id: cx.tcx.hir().local_def_id_from_hir_id(closure_expr.hir_id).to_local(),
temp_lifetime,
ty: var_ty,
span: closure_expr.span,
- kind: convert_var(cx, closure_expr, upvar.res),
+ kind: convert_var(cx, closure_expr, var_hir_id),
};
match upvar_capture {
ty::UpvarCapture::ByValue => captured_var.to_ref(),
/// `const`, or the body of a `const fn`.
constness: hir::Constness,
+ /// The `DefId` of the owner of this body.
+ body_owner: DefId,
+
/// What kind of body is being compiled.
pub body_owner_kind: hir::BodyOwnerKind,
src_id: hir::HirId) -> Cx<'a, 'gcx, 'tcx> {
let tcx = infcx.tcx;
let src_def_id = tcx.hir().local_def_id_from_hir_id(src_id);
+ let tables = tcx.typeck_tables_of(src_def_id);
let body_owner_kind = tcx.hir().body_owner_kind_by_hir_id(src_id);
let constness = match body_owner_kind {
param_env: tcx.param_env(src_def_id),
identity_substs: InternalSubsts::identity_for_item(tcx.global_tcx(), src_def_id),
region_scope_tree: tcx.region_scope_tree(src_def_id),
- tables: tcx.typeck_tables_of(src_def_id),
+ tables,
constness,
+ body_owner: src_def_id,
body_owner_kind,
check_overflow,
control_flow_destroyed: Vec::new(),
MatchVisitor {
tcx,
+ body_owner: def_id,
tables: tcx.body_tables(body_id),
region_scope_tree: &tcx.region_scope_tree(def_id),
param_env: tcx.param_env(def_id),
struct MatchVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ body_owner: DefId,
tables: &'a ty::TypeckTables<'tcx>,
param_env: ty::ParamEnv<'tcx>,
identity_substs: SubstsRef<'tcx>,
hir::Guard::If(expr) =>
ExprUseVisitor::new(&mut checker,
cx.tcx,
+ cx.body_owner,
cx.param_env,
cx.region_scope_tree,
cx.tables,
def_id,
substs,
).ok_or_else(|| InterpError::TooGeneric.into());
- let fn_ptr = self.memory.create_fn_alloc(instance?).with_default_tag();
+ let fn_ptr = self.memory.create_fn_alloc(instance?);
self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
}
_ => bug!("reify fn pointer on {:?}", src.layout.ty),
substs,
ty::ClosureKind::FnOnce,
);
- let fn_ptr = self.memory.create_fn_alloc(instance).with_default_tag();
+ let fn_ptr = self.memory.create_fn_alloc(instance);
let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
self.write_immediate(val, dest)?;
}
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::mir::interpret::{
ErrorHandled,
- GlobalId, Scalar, FrameInfo, AllocId,
+ GlobalId, Scalar, Pointer, FrameInfo, AllocId,
EvalResult, InterpError,
truncate, sign_extend,
};
pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>>,
/// A cache for deduplicating vtables
- pub(super) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), AllocId>,
+ pub(super) vtables: FxHashMap<
+ (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
+ Pointer<M::PointerTag>
+ >,
}
/// A stack frame.
&mut self.memory
}
+ #[inline(always)]
+ pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer<M::PointerTag> {
+ self.memory.tag_static_base_pointer(ptr)
+ }
+
#[inline(always)]
pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] {
&self.stack
}
}
- pub fn str_to_immediate(&mut self, s: &str) -> EvalResult<'tcx, Immediate<M::PointerTag>> {
- let ptr = self.memory.allocate_static_bytes(s.as_bytes()).with_default_tag();
- Ok(Immediate::new_slice(Scalar::Ptr(ptr), s.len() as u64, self))
- }
-
/// Returns the actual dynamic size and alignment of the place at the given type.
/// Only the "meta" (metadata) part of the place matters.
/// This can fail to provide an answer for extern types.
pub fn type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
let len = path.len();
- let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes(), ());
+ let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes());
let alloc = tcx.intern_const_alloc(alloc);
tcx.mk_const(ty::Const {
val: ConstValue::Slice {
use std::borrow::{Borrow, Cow};
use std::hash::Hash;
-use rustc::hir::{self, def_id::DefId};
+use rustc::hir::def_id::DefId;
use rustc::mir;
-use rustc::ty::{self, query::TyCtxtAt, layout::Size};
+use rustc::ty::{self, query::TyCtxtAt};
use super::{
Allocation, AllocId, EvalResult, Scalar, AllocationExtra,
- InterpretCx, PlaceTy, MPlaceTy, OpTy, ImmTy, MemoryKind,
+ InterpretCx, PlaceTy, OpTy, ImmTy, MemoryKind,
};
/// Whether this kind of memory is allowed to leak
/// Tag tracked alongside every pointer. This is used to implement "Stacked Borrows"
/// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
/// The `default()` is used for pointers to consts, statics, vtables and functions.
- type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static;
+ type PointerTag: ::std::fmt::Debug + Copy + Eq + Hash + 'static;
/// Extra data stored in every call frame.
type FrameExtra;
/// The memory kind to use for copied statics -- or None if statics should not be mutated
/// and thus any such attempt will cause a `ModifiedStatic` error to be raised.
/// Statics are copied under two circumstances: When they are mutated, and when
- /// `static_with_default_tag` or `find_foreign_static` (see below) returns an owned allocation
+ /// `tag_allocation` or `find_foreign_static` (see below) returns an owned allocation
/// that is added to the memory so that the work is not done twice.
const STATIC_KIND: Option<Self::MemoryKinds>;
/// This will only be called once per static and machine; the result is cached in
/// the machine memory. (This relies on `AllocMap::get_or` being able to add the
/// owned allocation to the map even when the map is shared.)
+ ///
+ /// This allocation will then be fed to `tag_allocation` to initialize the "extra" state.
fn find_foreign_static(
def_id: DefId,
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
- memory_extra: &Self::MemoryExtra,
- ) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag, Self::AllocExtra>>>;
+ ) -> EvalResult<'tcx, Cow<'tcx, Allocation>>;
/// Called for all binary operations on integer(-like) types when one operand is a pointer
/// value, and for the `Offset` operation that is inherently about pointers.
dest: PlaceTy<'tcx, Self::PointerTag>,
) -> EvalResult<'tcx>;
- /// Called to turn an allocation obtained from the `tcx` into one that has
- /// the right type for this machine.
+ /// Called to initialize the "extra" state of an allocation and make the pointers
+ /// it contains (in relocations) tagged. The way we construct allocations is
+ /// to always first construct it without extra and then add the extra.
+ /// This keeps uniform code paths for handling both allocations created by CTFE
+ /// for statics, and allocations ceated by Miri during evaluation.
+ ///
+ /// `kind` is the kind of the allocation being tagged; it can be `None` when
+ /// it's a static and `STATIC_KIND` is `None`.
///
/// This should avoid copying if no work has to be done! If this returns an owned
/// allocation (because a copy had to be done to add tags or metadata), machine memory will
/// cache the result. (This relies on `AllocMap::get_or` being able to add the
/// owned allocation to the map even when the map is shared.)
- fn adjust_static_allocation<'b>(
- alloc: &'b Allocation,
+ ///
+ /// For static allocations, the tag returned must be the same as the one returned by
+ /// `tag_static_base_pointer`.
+ fn tag_allocation<'b>(
+ id: AllocId,
+ alloc: Cow<'b, Allocation>,
+ kind: Option<MemoryKind<Self::MemoryKinds>>,
memory_extra: &Self::MemoryExtra,
- ) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>;
-
- /// Computes the extra state and the tag for a new allocation.
- fn new_allocation(
- size: Size,
- extra: &Self::MemoryExtra,
- kind: MemoryKind<Self::MemoryKinds>,
- ) -> (Self::AllocExtra, Self::PointerTag);
-
- /// Executed when evaluating the `*` operator: Following a reference.
- /// This has the chance to adjust the tag. It should not change anything else!
- /// `mutability` can be `None` in case a raw ptr is being dereferenced.
- #[inline]
- fn tag_dereference(
- _ecx: &InterpretCx<'a, 'mir, 'tcx, Self>,
- place: MPlaceTy<'tcx, Self::PointerTag>,
- _mutability: Option<hir::Mutability>,
- ) -> EvalResult<'tcx, Scalar<Self::PointerTag>> {
- Ok(place.ptr)
- }
+ ) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag);
+
+ /// Return the "base" tag for the given static allocation: the one that is used for direct
+ /// accesses to this static/const/fn allocation.
+ ///
+ /// Be aware that requesting the `Allocation` for that `id` will lead to cycles
+ /// for cyclic statics!
+ fn tag_static_base_pointer(
+ id: AllocId,
+ memory_extra: &Self::MemoryExtra,
+ ) -> Self::PointerTag;
/// Executes a retagging operation
#[inline]
use super::{
Pointer, AllocId, Allocation, GlobalId, AllocationExtra,
- EvalResult, Scalar, InterpError, AllocKind, PointerArithmetic,
+ EvalResult, Scalar, InterpError, GlobalAlloc, PointerArithmetic,
Machine, AllocMap, MayLeak, ErrorHandled, CheckInAllocMsg, InboundsCheck,
};
}
}
- pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer {
- Pointer::from(self.tcx.alloc_map.lock().create_fn_alloc(instance))
+ #[inline]
+ pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer<M::PointerTag> {
+ ptr.with_tag(M::tag_static_base_pointer(ptr.alloc_id, &self.extra))
}
- pub fn allocate_static_bytes(&mut self, bytes: &[u8]) -> Pointer {
- Pointer::from(self.tcx.allocate_bytes(bytes))
+ pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer<M::PointerTag> {
+ let id = self.tcx.alloc_map.lock().create_fn_alloc(instance);
+ self.tag_static_base_pointer(Pointer::from(id))
}
- pub fn allocate_with(
+ pub fn allocate(
&mut self,
- alloc: Allocation<M::PointerTag, M::AllocExtra>,
+ size: Size,
+ align: Align,
kind: MemoryKind<M::MemoryKinds>,
- ) -> AllocId {
- let id = self.tcx.alloc_map.lock().reserve();
- self.alloc_map.insert(id, (kind, alloc));
- id
+ ) -> Pointer<M::PointerTag> {
+ let alloc = Allocation::undef(size, align);
+ self.allocate_with(alloc, kind)
}
- pub fn allocate(
+ pub fn allocate_static_bytes(
&mut self,
- size: Size,
- align: Align,
+ bytes: &[u8],
kind: MemoryKind<M::MemoryKinds>,
) -> Pointer<M::PointerTag> {
- let (extra, tag) = M::new_allocation(size, &self.extra, kind);
- Pointer::from(self.allocate_with(Allocation::undef(size, align, extra), kind)).with_tag(tag)
+ let alloc = Allocation::from_byte_aligned_bytes(bytes);
+ self.allocate_with(alloc, kind)
+ }
+
+ pub fn allocate_with(
+ &mut self,
+ alloc: Allocation,
+ kind: MemoryKind<M::MemoryKinds>,
+ ) -> Pointer<M::PointerTag> {
+ let id = self.tcx.alloc_map.lock().reserve();
+ let (alloc, tag) = M::tag_allocation(id, Cow::Owned(alloc), Some(kind), &self.extra);
+ self.alloc_map.insert(id, (kind, alloc.into_owned()));
+ Pointer::from(id).with_tag(tag)
}
pub fn reallocate(
None => {
// Deallocating static memory -- always an error
return match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
- Some(AllocKind::Function(..)) => err!(DeallocatedWrongMemoryKind(
+ Some(GlobalAlloc::Function(..)) => err!(DeallocatedWrongMemoryKind(
"function".to_string(),
format!("{:?}", kind),
)),
- Some(AllocKind::Static(..)) |
- Some(AllocKind::Memory(..)) => err!(DeallocatedWrongMemoryKind(
+ Some(GlobalAlloc::Static(..)) |
+ Some(GlobalAlloc::Memory(..)) => err!(DeallocatedWrongMemoryKind(
"static".to_string(),
format!("{:?}", kind),
)),
/// This attempts to return a reference to an existing allocation if
/// one can be found in `tcx`. That, however, is only possible if `tcx` and
/// this machine use the same pointer tag, so it is indirected through
- /// `M::static_with_default_tag`.
+ /// `M::tag_allocation`.
+ ///
+ /// Notice that every static has two `AllocId` that will resolve to the same
+ /// thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID,
+ /// and the other one is maps to `GlobalAlloc::Memory`, this is returned by
+ /// `const_eval_raw` and it is the "resolved" ID.
+ /// The resolved ID is never used by the interpreted progrma, it is hidden.
+ /// The `GlobalAlloc::Memory` branch here is still reachable though; when a static
+ /// contains a reference to memory that was created during its evaluation (i.e., not to
+ /// another static), those inner references only exist in "resolved" form.
fn get_static_alloc(
id: AllocId,
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
memory_extra: &M::MemoryExtra,
) -> EvalResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> {
let alloc = tcx.alloc_map.lock().get(id);
- let def_id = match alloc {
- Some(AllocKind::Memory(mem)) => {
- // We got tcx memory. Let the machine figure out whether and how to
- // turn that into memory with the right pointer tag.
- return Ok(M::adjust_static_allocation(mem, memory_extra))
- }
- Some(AllocKind::Function(..)) => {
- return err!(DerefFunctionPointer)
- }
- Some(AllocKind::Static(did)) => {
- did
- }
+ let alloc = match alloc {
+ Some(GlobalAlloc::Memory(mem)) =>
+ Cow::Borrowed(mem),
+ Some(GlobalAlloc::Function(..)) =>
+ return err!(DerefFunctionPointer),
None =>
return err!(DanglingPointerDeref),
- };
- // We got a "lazy" static that has not been computed yet, do some work
- trace!("static_alloc: Need to compute {:?}", def_id);
- if tcx.is_foreign_item(def_id) {
- return M::find_foreign_static(def_id, tcx, memory_extra);
- }
- let instance = Instance::mono(tcx.tcx, def_id);
- let gid = GlobalId {
- instance,
- promoted: None,
- };
- // use the raw query here to break validation cycles. Later uses of the static will call the
- // full query anyway
- tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| {
- // no need to report anything, the const_eval call takes care of that for statics
- assert!(tcx.is_static(def_id));
- match err {
- ErrorHandled::Reported => InterpError::ReferencedConstant.into(),
- ErrorHandled::TooGeneric => InterpError::TooGeneric.into(),
+ Some(GlobalAlloc::Static(def_id)) => {
+ // We got a "lazy" static that has not been computed yet.
+ if tcx.is_foreign_item(def_id) {
+ trace!("static_alloc: foreign item {:?}", def_id);
+ M::find_foreign_static(def_id, tcx)?
+ } else {
+ trace!("static_alloc: Need to compute {:?}", def_id);
+ let instance = Instance::mono(tcx.tcx, def_id);
+ let gid = GlobalId {
+ instance,
+ promoted: None,
+ };
+ // use the raw query here to break validation cycles. Later uses of the static
+ // will call the full query anyway
+ let raw_const = tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid))
+ .map_err(|err| {
+ // no need to report anything, the const_eval call takes care of that
+ // for statics
+ assert!(tcx.is_static(def_id));
+ match err {
+ ErrorHandled::Reported => InterpError::ReferencedConstant,
+ ErrorHandled::TooGeneric => InterpError::TooGeneric,
+ }
+ })?;
+ // Make sure we use the ID of the resolved memory, not the lazy one!
+ let id = raw_const.alloc_id;
+ let allocation = tcx.alloc_map.lock().unwrap_memory(id);
+ Cow::Borrowed(allocation)
+ }
}
- }).map(|raw_const| {
- let allocation = tcx.alloc_map.lock().unwrap_memory(raw_const.alloc_id);
- // We got tcx memory. Let the machine figure out whether and how to
- // turn that into memory with the right pointer tag.
- M::adjust_static_allocation(allocation, memory_extra)
- })
+ };
+ // We got tcx memory. Let the machine figure out whether and how to
+ // turn that into memory with the right pointer tag.
+ Ok(M::tag_allocation(
+ id, // always use the ID we got as input, not the "hidden" one.
+ alloc,
+ M::STATIC_KIND.map(MemoryKind::Machine),
+ memory_extra
+ ).0)
}
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation<M::PointerTag, M::AllocExtra>> {
}
// Could also be a fn ptr or extern static
match self.tcx.alloc_map.lock().get(id) {
- Some(AllocKind::Function(..)) => Ok((Size::ZERO, Align::from_bytes(1).unwrap())),
- Some(AllocKind::Static(did)) => {
+ Some(GlobalAlloc::Function(..)) => Ok((Size::ZERO, Align::from_bytes(1).unwrap())),
+ Some(GlobalAlloc::Static(did)) => {
// The only way `get` couldn't have worked here is if this is an extern static
assert!(self.tcx.is_foreign_item(did));
// Use size and align of the type
}
trace!("reading fn ptr: {}", ptr.alloc_id);
match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
- Some(AllocKind::Function(instance)) => Ok(instance),
+ Some(GlobalAlloc::Function(instance)) => Ok(instance),
_ => Err(InterpError::ExecuteMemory.into()),
}
}
Err(()) => {
// static alloc?
match self.tcx.alloc_map.lock().get(id) {
- Some(AllocKind::Memory(alloc)) => {
+ Some(GlobalAlloc::Memory(alloc)) => {
self.dump_alloc_helper(
&mut allocs_seen, &mut allocs_to_print,
msg, alloc, " (immutable)".to_owned()
);
}
- Some(AllocKind::Function(func)) => {
+ Some(GlobalAlloc::Function(func)) => {
trace!("{} {}", msg, func);
}
- Some(AllocKind::Static(did)) => {
+ Some(GlobalAlloc::Static(did)) => {
trace!("{} {:?}", msg, did);
}
None => {
Immediate::Scalar(ScalarMaybeUndef::Scalar(val))
}
- #[inline]
- pub fn erase_tag(self) -> Immediate
- {
- match self {
- Immediate::Scalar(x) => Immediate::Scalar(x.erase_tag()),
- Immediate::ScalarPair(x, y) =>
- Immediate::ScalarPair(x.erase_tag(), y.erase_tag()),
- }
- }
-
pub fn new_slice(
val: Scalar<Tag>,
len: u64,
}
impl<Tag> Operand<Tag> {
- #[inline]
- pub fn erase_tag(self) -> Operand
- {
- match self {
- Operand::Immediate(x) => Operand::Immediate(x.erase_tag()),
- Operand::Indirect(x) => Operand::Indirect(x.erase_tag()),
- }
- }
-
#[inline]
pub fn to_mem_place(self) -> MemPlace<Tag>
where Tag: ::std::fmt::Debug
}
}
-impl<'tcx, Tag> OpTy<'tcx, Tag>
-{
- #[inline]
- pub fn erase_tag(self) -> OpTy<'tcx>
- {
- OpTy {
- op: self.op.erase_tag(),
- layout: self.layout,
- }
- }
-}
-
// Use the existing layout if given (but sanity check in debug mode),
// or compute the layout.
#[inline(always)]
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
- /// Try reading an immediate in memory; this is interesting particularly for ScalarPair.
+ /// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`.
/// Returns `None` if the layout does not permit loading this as a value.
fn try_read_immediate_from_mplace(
&self,
Ok(OpTy { op, layout })
}
- /// Every place can be read from, so we can turm them into an operand
+ /// Every place can be read from, so we can turn them into an operand
#[inline(always)]
pub fn place_to_op(
&self,
}
/// Evaluate the operand, returning a place where you can then find the data.
- /// if you already know the layout, you can save two some table lookups
+ /// If you already know the layout, you can save two table lookups
/// by passing it in here.
pub fn eval_operand(
&self,
val: &'tcx ty::Const<'tcx>,
layout: Option<TyLayout<'tcx>>,
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
- let op = match val.val {
- ConstValue::Param(_) => return err!(TooGeneric),
- ConstValue::Infer(_) | ConstValue::Placeholder(_) => bug!(),
- ConstValue::ByRef(ptr, alloc) => {
- // We rely on mutability being set correctly in that allocation to prevent writes
- // where none should happen -- and for `static mut`, we copy on demand anyway.
- Operand::Indirect(
- MemPlace::from_ptr(ptr.with_default_tag(), alloc.align)
- )
- },
- ConstValue::Slice { data, start, end } =>
- Operand::Immediate(Immediate::ScalarPair(
- Scalar::from(Pointer::new(
- self.tcx.alloc_map.lock().allocate(data),
- Size::from_bytes(start as u64),
- )).with_default_tag().into(),
- Scalar::from_uint(
- (end - start) as u64,
- self.tcx.data_layout.pointer_size,
- ).with_default_tag().into(),
- )),
- ConstValue::Scalar(x) =>
- Operand::Immediate(Immediate::Scalar(x.with_default_tag().into())),
+ let tag_scalar = |scalar| match scalar {
+ Scalar::Ptr(ptr) => Scalar::Ptr(self.tag_static_base_pointer(ptr)),
+ Scalar::Raw { data, size } => Scalar::Raw { data, size },
+ };
+ // Early-return cases.
+ match val.val {
+ ConstValue::Param(_) => return err!(TooGeneric), // FIXME(oli-obk): try to monomorphize
ConstValue::Unevaluated(def_id, substs) => {
let instance = self.resolve(def_id, substs)?;
return Ok(OpTy::from(self.const_eval_raw(GlobalId {
instance,
promoted: None,
})?));
- },
- };
+ }
+ _ => {}
+ }
+ // Other cases need layout.
let layout = from_known_layout(layout, || {
self.layout_of(self.monomorphize(val.ty)?)
})?;
- Ok(OpTy {
- op,
- layout,
- })
+ let op = match val.val {
+ ConstValue::ByRef(ptr, _alloc) => {
+ // We rely on mutability being set correctly in that allocation to prevent writes
+ // where none should happen.
+ let ptr = self.tag_static_base_pointer(ptr);
+ Operand::Indirect(MemPlace::from_ptr(ptr, layout.align.abi))
+ },
+ ConstValue::Scalar(x) =>
+ Operand::Immediate(Immediate::Scalar(tag_scalar(x).into())),
+ ConstValue::Slice { data, start, end } => {
+ // We rely on mutability being set correctly in `data` to prevent writes
+ // where none should happen.
+ let ptr = Pointer::new(
+ self.tcx.alloc_map.lock().create_memory_alloc(data),
+ Size::from_bytes(start as u64), // offset: `start`
+ );
+ Operand::Immediate(Immediate::new_slice(
+ self.tag_static_base_pointer(ptr).into(),
+ (end - start) as u64, // len: `end - start`
+ self,
+ ))
+ }
+ ConstValue::Param(..) |
+ ConstValue::Infer(..) |
+ ConstValue::Placeholder(..) |
+ ConstValue::Unevaluated(..) =>
+ bug!("eval_const_to_op: Unexpected ConstValue {:?}", val),
+ };
+ Ok(OpTy { op, layout })
}
/// Read discriminant, return the runtime value as well as the variant index.
use std::convert::TryFrom;
use std::hash::Hash;
-use rustc::hir;
use rustc::mir;
use rustc::mir::interpret::truncate;
use rustc::ty::{self, Ty};
impl<'a, 'mir, 'tcx, Tag, M> InterpretCx<'a, 'mir, 'tcx, M>
where
// FIXME: Working around https://github.com/rust-lang/rust/issues/54385
- Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
+ Tag: ::std::fmt::Debug + Copy + Eq + Hash + 'static,
M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
// FIXME: Working around https://github.com/rust-lang/rust/issues/24159
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
// Take an operand, representing a pointer, and dereference it to a place -- that
// will always be a MemPlace. Lives in `place.rs` because it creates a place.
- // This calls the "deref" machine hook, and counts as a deref as far as
- // Stacked Borrows is concerned.
pub fn deref_operand(
&self,
src: OpTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let val = self.read_immediate(src)?;
trace!("deref to {} on {:?}", val.layout.ty, *val);
- let mut place = self.ref_to_mplace(val)?;
- // Pointer tag tracking might want to adjust the tag.
- let mutbl = match val.layout.ty.sty {
- // `builtin_deref` considers boxes immutable, that's useless for our purposes
- ty::Ref(_, _, mutbl) => Some(mutbl),
- ty::Adt(def, _) if def.is_box() => Some(hir::MutMutable),
- ty::RawPtr(_) => None,
- _ => bug!("Unexpected pointer type {}", val.layout.ty),
- };
- place.mplace.ptr = M::tag_dereference(self, place, mutbl)?;
- Ok(place)
+ self.ref_to_mplace(val)
}
- /// Offset a pointer to project to a field. Unlike place_field, this is always
- /// possible without allocating, so it can take &self. Also return the field's layout.
+ /// Offset a pointer to project to a field. Unlike `place_field`, this is always
+ /// possible without allocating, so it can take `&self`. Also return the field's layout.
/// This supports both struct and array fields.
#[inline(always)]
pub fn mplace_field(
promoted: None
};
// Just create a lazy reference, so we can support recursive statics.
- // tcx takes are of assigning every static one and only one unique AllocId.
+ // tcx takes care of assigning every static one and only one unique AllocId.
// When the data here is ever actually used, memory will notice,
// and it knows how to deal with alloc_id that are present in the
// global table but not in its local memory: It calls back into tcx through
// a query, triggering the CTFE machinery to actually turn this lazy reference
// into a bunch of bytes. IOW, statics are evaluated with CTFE even when
// this InterpretCx uses another Machine (e.g., in miri). This is what we
- // want! This way, computing statics works concistently between codegen
+ // want! This way, computing statics works consistently between codegen
// and miri: They use the same query to eventually obtain a `ty::Const`
// and use that for further computation.
- let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
- MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
+ //
+ // Notice that statics have *two* AllocIds: the lazy one, and the resolved
+ // one. Here we make sure that the interpreted program never sees the
+ // resolved ID. Also see the doc comment of `Memory::get_static_alloc`.
+ let alloc_id = self.tcx.alloc_map.lock().create_static_alloc(cid.instance.def_id());
+ let ptr = self.tag_static_base_pointer(Pointer::from(alloc_id));
+ MPlaceTy::from_aligned_ptr(ptr, layout)
}
})
}
}
/// Write an immediate to memory.
- /// If you use this you are responsible for validating that things git copied at the
+ /// If you use this you are responsible for validating that things got copied at the
/// right type.
fn write_immediate_to_mplace_no_validate(
&mut self,
/// Copies the data from an operand to a place. This does not support transmuting!
/// Use `copy_op_transmute` if the layouts could disagree.
- /// Also, if you use this you are responsible for validating that things git copied at the
+ /// Also, if you use this you are responsible for validating that things get copied at the
/// right type.
fn copy_op_no_validate(
&mut self,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
// This must be an allocation in `tcx`
assert!(self.tcx.alloc_map.lock().get(raw.alloc_id).is_some());
+ let ptr = self.tag_static_base_pointer(Pointer::from(raw.alloc_id));
let layout = self.layout_of(raw.ty)?;
- Ok(MPlaceTy::from_aligned_ptr(
- Pointer::new(raw.alloc_id, Size::ZERO).with_default_tag(),
- layout,
- ))
+ Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
}
/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
// always use the same vtable for the same (Type, Trait) combination.
// That's not what happens in rustc, but emulating per-crate deduplication
// does not sound like it actually makes anything any better.
- return Ok(Pointer::from(vtable).with_default_tag());
+ return Ok(vtable);
}
let methods = if let Some(poly_trait_ref) = poly_trait_ref {
let tcx = &*self.tcx;
let drop = crate::monomorphize::resolve_drop_in_place(*tcx, ty);
- let drop = self.memory.create_fn_alloc(drop).with_default_tag();
+ let drop = self.memory.create_fn_alloc(drop);
// no need to do any alignment checks on the memory accesses below, because we know the
// allocation is correctly aligned as we created it above. Also we're only offsetting by
// multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
def_id,
substs,
).ok_or_else(|| InterpError::TooGeneric)?;
- let fn_ptr = self.memory.create_fn_alloc(instance).with_default_tag();
+ let fn_ptr = self.memory.create_fn_alloc(instance);
let method_ptr = vtable.offset(ptr_size * (3 + i as u64), self)?;
self.memory
.get_mut(method_ptr.alloc_id)?
}
self.memory.mark_immutable(vtable.alloc_id)?;
- assert!(self.vtables.insert((ty, poly_trait_ref), vtable.alloc_id).is_none());
+ assert!(self.vtables.insert((ty, poly_trait_ref), vtable).is_none());
Ok(vtable)
}
use rustc::ty;
use rustc_data_structures::fx::FxHashSet;
use rustc::mir::interpret::{
- Scalar, AllocKind, EvalResult, InterpError, CheckInAllocMsg,
+ Scalar, GlobalAlloc, EvalResult, InterpError, CheckInAllocMsg,
};
use super::{
if let Some(upvars) = tables.upvar_list.get(&def_id) {
// Sometimes the index is beyond the number of upvars (seen
// for a generator).
- if let Some(upvar_id) = upvars.get(field) {
- let var_hir_id = upvar_id.var_path.hir_id;
+ if let Some((&var_hir_id, _)) = upvars.get_index(field) {
let var_node_id = self.ecx.tcx.hir().hir_to_node_id(var_hir_id);
if let hir::Node::Binding(pat) = self.ecx.tcx.hir().get(var_node_id) {
if let hir::PatKind::Binding(_, _, ident, _) = pat.node {
"integer pointer in non-ZST reference", self.path);
// Skip validation entirely for some external statics
let alloc_kind = self.ecx.tcx.alloc_map.lock().get(ptr.alloc_id);
- if let Some(AllocKind::Static(did)) = alloc_kind {
+ if let Some(GlobalAlloc::Static(did)) = alloc_kind {
// `extern static` cannot be validated as they have no body.
// FIXME: Statics from other crates are also skipped.
// They might be checked at a different type, but for now we
/// is an indirect operand.
/// It will error if the bits at the destination do not match the ones described by the layout.
///
- /// `ref_tracking` can be None to avoid recursive checking below references.
+ /// `ref_tracking` can be `None` to avoid recursive checking below references.
/// This also toggles between "run-time" (no recursion) and "compile-time" (with recursion)
/// validation (e.g., pointer values are fine in integers at runtime).
pub fn validate_operand(
#![feature(unicode_internals)]
#![feature(step_trait)]
#![feature(slice_concat_ext)]
-#![feature(reverse_bits)]
#![feature(try_blocks)]
#![recursion_limit="256"]
use rustc::mir::{self, Location, Place, PlaceBase, Promoted, Static, StaticKind};
use rustc::mir::visit::Visitor as MirVisitor;
use rustc::mir::mono::MonoItem;
-use rustc::mir::interpret::{Scalar, GlobalId, AllocKind, ErrorHandled};
+use rustc::mir::interpret::{Scalar, GlobalId, GlobalAlloc, ErrorHandled};
use crate::monomorphize::{self, Instance};
use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
) {
let alloc_kind = tcx.alloc_map.lock().get(alloc_id);
match alloc_kind {
- Some(AllocKind::Static(did)) => {
- let instance = Instance::mono(tcx, did);
+ Some(GlobalAlloc::Static(def_id)) => {
+ let instance = Instance::mono(tcx, def_id);
if should_monomorphize_locally(tcx, &instance) {
- trace!("collecting static {:?}", did);
- output.push(MonoItem::Static(did));
+ trace!("collecting static {:?}", def_id);
+ output.push(MonoItem::Static(def_id));
}
}
- Some(AllocKind::Memory(alloc)) => {
+ Some(GlobalAlloc::Memory(alloc)) => {
trace!("collecting {:?} with {:#?}", alloc_id, alloc);
for &((), inner) in alloc.relocations.values() {
collect_miri(tcx, inner, output);
}
},
- Some(AllocKind::Function(fn_instance)) => {
+ Some(GlobalAlloc::Function(fn_instance)) => {
if should_monomorphize_locally(tcx, &fn_instance) {
trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
output.push(create_fn_mono_item(fn_instance));
collect_miri(tcx, id, output);
}
}
- ConstValue::Unevaluated(did, substs) => {
+ ConstValue::Unevaluated(def_id, substs) => {
let param_env = ty::ParamEnv::reveal_all();
let substs = tcx.subst_and_normalize_erasing_regions(
param_substs,
);
let instance = ty::Instance::resolve(tcx,
param_env,
- did,
+ def_id,
substs).unwrap();
let cid = GlobalId {
Ok(val) => collect_const(tcx, val, param_substs, output),
Err(ErrorHandled::Reported) => {},
Err(ErrorHandled::TooGeneric) => span_bug!(
- tcx.def_span(did), "collection encountered polymorphic constant",
+ tcx.def_span(def_id), "collection encountered polymorphic constant",
),
}
}
debug!("make_shim({:?}) = {:?}", instance, result);
- tcx.alloc_mir(result)
+ tcx.arena.alloc(result)
}
#[derive(Copy, Clone, Debug, PartialEq)]
&add_call_guards::CriticalCallEdges,
&dump_mir::Marker("PreCodegen"),
]);
- tcx.alloc_mir(mir)
+ tcx.arena.alloc(mir)
}
} else if let ty::Array(_, len) = ty.sty {
// FIXME(eddyb) the `cx.mode == Mode::Fn` condition
// seems unnecessary, given that this is merely a ZST.
- if !(len.unwrap_usize(cx.tcx) == 0 && cx.mode == Mode::Fn) {
- return true;
+ match len.assert_usize(cx.tcx) {
+ Some(0) if cx.mode == Mode::Fn => {},
+ _ => return true,
}
} else {
return true;
let param_env = self.param_env;
let region_scope_tree = self.tcx.region_scope_tree(item_def_id);
let tables = self.tables;
- euv::ExprUseVisitor::new(self, tcx, param_env, ®ion_scope_tree, tables, None)
- .consume_body(body);
+ euv::ExprUseVisitor::new(
+ self,
+ tcx,
+ item_def_id,
+ param_env,
+ ®ion_scope_tree,
+ tables,
+ None,
+ ).consume_body(body);
let body_promotable = self.check_expr(&body.value);
self.in_fn = outer_in_fn;
[dependencies]
bitflags = "1.0"
+indexmap = "1"
log = "0.4"
syntax = { path = "../libsyntax" }
rustc = { path = "../librustc" }
};
use rustc::hir::def::Namespace::*;
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
-use rustc::hir::{Upvar, UpvarMap, TraitCandidate, TraitMap, GlobMap};
+use rustc::hir::{TraitCandidate, TraitMap, GlobMap};
use rustc::ty::{self, DefIdTree};
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
use rustc::{bug, span_bug};
| Res::Def(DefKind::Const, _)
| Res::Def(DefKind::Static, _)
| Res::Local(..)
- | Res::Upvar(..)
| Res::Def(DefKind::Fn, _)
| Res::Def(DefKind::Method, _)
| Res::Def(DefKind::AssocConst, _)
function_kind: FnKind<'tcx>,
declaration: &'tcx FnDecl,
_: Span,
- node_id: NodeId)
+ _: NodeId)
{
debug!("(resolving function) entering function");
let (rib_kind, asyncness) = match function_kind {
FnKind::Closure(_) =>
// Async closures aren't resolved through `visit_fn`-- they're
// processed separately
- (ClosureRibKind(node_id), &IsAsync::NotAsync),
+ (NormalRibKind, &IsAsync::NotAsync),
};
// Create a value rib for the function.
visit::walk_fn_ret_ty(self, &declaration.output);
// Resolve the function body, potentially inside the body of an async closure
- if let IsAsync::Async { closure_id, .. } = asyncness {
- let rib_kind = ClosureRibKind(*closure_id);
- self.ribs[ValueNS].push(Rib::new(rib_kind));
- self.label_ribs.push(Rib::new(rib_kind));
- }
-
match function_kind {
FnKind::ItemFn(.., body) | FnKind::Method(.., body) => {
if let IsAsync::Async { ref arguments, .. } = asyncness {
}
};
- // Leave the body of the async closure
- if asyncness.is_async() {
- self.label_ribs.pop();
- self.ribs[ValueNS].pop();
- }
-
debug!("(resolving function) leaving function");
self.label_ribs.pop();
RibKind<'a>),
}
-/// The rib kind controls the translation of local
-/// definitions (`Res::Local`) to upvars (`Res::Upvar`).
+/// The rib kind restricts certain accesses,
+/// e.g. to a `Res::Local` of an outer item.
#[derive(Copy, Clone, Debug)]
enum RibKind<'a> {
- /// No translation needs to be applied.
+ /// No restriction needs to be applied.
NormalRibKind,
- /// We passed through a closure scope at the given `NodeId`.
- /// Translate upvars as appropriate.
- ClosureRibKind(NodeId /* func id */),
-
/// We passed through an impl or trait and are now in one of its
/// methods or associated types. Allow references to ty params that impl or trait
/// binds. Disallow any other upvars (including other ty params that are
/// Resolutions for labels (node IDs of their corresponding blocks or loops).
label_res_map: NodeMap<NodeId>,
- pub upvars: UpvarMap,
- upvars_seen: NodeMap<NodeMap<usize>>,
pub export_map: ExportMap<NodeId>,
pub trait_map: TraitMap,
partial_res_map: Default::default(),
import_res_map: Default::default(),
label_res_map: Default::default(),
- upvars: Default::default(),
- upvars_seen: Default::default(),
export_map: FxHashMap::default(),
trait_map: Default::default(),
module_map,
if let Some(res) = self.ribs[ns][i].bindings.get(&ident).cloned() {
// The ident resolves to a type parameter or local variable.
return Some(LexicalScopeBinding::Res(
- self.adjust_local_res(ns, i, res, record_used, path_span)
+ self.validate_res_from_ribs(ns, i, res, record_used, path_span),
));
}
diag);
}
- // Resolve a local definition, potentially adjusting for closures.
- fn adjust_local_res(&mut self,
- ns: Namespace,
- rib_index: usize,
- mut res: Res,
- record_used: bool,
- span: Span) -> Res {
- debug!("adjust_local_res");
+ // Validate a local resolution (from ribs).
+ fn validate_res_from_ribs(
+ &mut self,
+ ns: Namespace,
+ rib_index: usize,
+ res: Res,
+ record_used: bool,
+ span: Span,
+ ) -> Res {
+ debug!("validate_res_from_ribs({:?})", res);
let ribs = &self.ribs[ns][rib_index + 1..];
// An invalid forward use of a type parameter from a previous default.
}
match res {
- Res::Upvar(..) => {
- span_bug!(span, "unexpected {:?} in bindings", res)
- }
- Res::Local(node_id) => {
+ Res::Local(_) => {
use ResolutionError::*;
let mut res_err = None;
ForwardTyParamBanRibKind | TyParamAsConstParamTy => {
// Nothing to do. Continue.
}
- ClosureRibKind(function_id) => {
- let prev_res = res;
-
- let seen = self.upvars_seen
- .entry(function_id)
- .or_default();
- if let Some(&index) = seen.get(&node_id) {
- res = Res::Upvar(node_id, index, function_id);
- continue;
- }
- let vec = self.upvars
- .entry(function_id)
- .or_default();
- let depth = vec.len();
- res = Res::Upvar(node_id, depth, function_id);
-
- if record_used {
- vec.push(Upvar {
- res: prev_res,
- span,
- });
- seen.insert(node_id, depth);
- }
- }
ItemRibKind | FnItemRibKind | AssocItemRibKind => {
// This was an attempt to access an upvar inside a
// named function item. This is not allowed, so we
Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
for rib in ribs {
match rib.kind {
- NormalRibKind | AssocItemRibKind | ClosureRibKind(..) |
+ NormalRibKind | AssocItemRibKind |
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
ConstantItemRibKind | TyParamAsConstParamTy => {
// Nothing to do. Continue.
visit::walk_expr(self, expr);
self.current_type_ascription.pop();
}
- // Resolve the body of async exprs inside the async closure to which they desugar
- ExprKind::Async(_, async_closure_id, ref block) => {
- let rib_kind = ClosureRibKind(async_closure_id);
- self.ribs[ValueNS].push(Rib::new(rib_kind));
- self.label_ribs.push(Rib::new(rib_kind));
- self.visit_block(&block);
- self.label_ribs.pop();
- self.ribs[ValueNS].pop();
- }
// `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
// resolve the arguments within the proper scopes so that usages of them inside the
// closure are detected as upvars rather than normal closure arg usages.
ExprKind::Closure(
- _, IsAsync::Async { closure_id: inner_closure_id, .. }, _,
+ _, IsAsync::Async { .. }, _,
ref fn_decl, ref body, _span,
) => {
- let rib_kind = ClosureRibKind(expr.id);
+ let rib_kind = NormalRibKind;
self.ribs[ValueNS].push(Rib::new(rib_kind));
- self.label_ribs.push(Rib::new(rib_kind));
// Resolve arguments:
let mut bindings_list = FxHashMap::default();
for argument in &fn_decl.inputs {
// Now resolve the inner closure
{
- let rib_kind = ClosureRibKind(inner_closure_id);
- self.ribs[ValueNS].push(Rib::new(rib_kind));
- self.label_ribs.push(Rib::new(rib_kind));
// No need to resolve arguments: the inner closure has none.
// Resolve the return type:
visit::walk_fn_ret_ty(self, &fn_decl.output);
// Resolve the body
self.visit_expr(body);
- self.label_ribs.pop();
- self.ribs[ValueNS].pop();
}
- self.label_ribs.pop();
self.ribs[ValueNS].pop();
}
_ => {
let span = self.span_from_span(span);
match res {
- Res::Upvar(id, ..) | Res::Local(id) => {
+ Res::Local(id) => {
Some(Ref {
kind: RefKind::Variable,
span,
for br in late_bound_in_ret.difference(&late_bound_in_args) {
let lifetime_name = match *br {
ty::BrNamed(_, name) => format!("lifetime `{}`,", name),
- ty::BrAnon(_) | ty::BrFresh(_) | ty::BrEnv => "an anonymous lifetime".to_string(),
+ ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(),
};
let mut err = struct_span_err!(tcx.sess,
decl.output.span(),
let expected_ty = self.structurally_resolved_type(pat.span, expected);
let (inner_ty, slice_ty) = match expected_ty.sty {
ty::Array(inner_ty, size) => {
- let size = size.unwrap_usize(tcx);
- let min_len = before.len() as u64 + after.len() as u64;
- if slice.is_none() {
- if min_len != size {
- struct_span_err!(
- tcx.sess, pat.span, E0527,
- "pattern requires {} elements but array has {}",
- min_len, size)
- .span_label(pat.span, format!("expected {} elements", size))
+ if let Some(size) = size.assert_usize(tcx) {
+ let min_len = before.len() as u64 + after.len() as u64;
+ if slice.is_none() {
+ if min_len != size {
+ struct_span_err!(
+ tcx.sess, pat.span, E0527,
+ "pattern requires {} elements but array has {}",
+ min_len, size)
+ .span_label(pat.span, format!("expected {} elements", size))
+ .emit();
+ }
+ (inner_ty, tcx.types.err)
+ } else if let Some(rest) = size.checked_sub(min_len) {
+ (inner_ty, tcx.mk_array(inner_ty, rest))
+ } else {
+ struct_span_err!(tcx.sess, pat.span, E0528,
+ "pattern requires at least {} elements but array has {}",
+ min_len, size)
+ .span_label(pat.span,
+ format!("pattern cannot match array of {} elements", size))
.emit();
+ (inner_ty, tcx.types.err)
}
- (inner_ty, tcx.types.err)
- } else if let Some(rest) = size.checked_sub(min_len) {
- (inner_ty, tcx.mk_array(inner_ty, rest))
} else {
- struct_span_err!(tcx.sess, pat.span, E0528,
- "pattern requires at least {} elements but array has {}",
- min_len, size)
- .span_label(pat.span,
- format!("pattern cannot match array of {} elements", size))
- .emit();
+ struct_span_err!(
+ tcx.sess,
+ pat.span,
+ E0730,
+ "cannot pattern-match on an array without a fixed length",
+ ).emit();
(inner_ty, tcx.types.err)
}
}
let msg = format!("expected tuple struct/variant, found {} `{}`",
res.descr(),
hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false)));
- struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg)
- .span_label(pat.span, "not a tuple variant or struct").emit();
+ let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg);
+ match (res, &pat.node) {
+ (Res::Def(DefKind::Fn, _), _) | (Res::Def(DefKind::Method, _), _) => {
+ err.span_label(pat.span, "`fn` calls are not allowed in patterns");
+ err.help("for more information, visit \
+ https://doc.rust-lang.org/book/ch18-00-patterns.html");
+ }
+ _ => {
+ err.span_label(pat.span, "not a tuple variant or struct");
+ }
+ }
+ err.emit();
on_error();
};
let def_span = match def {
Res::Err => None,
- Res::Local(id) | Res::Upvar(id, ..) => {
+ Res::Local(id) => {
Some(self.tcx.hir().span_by_hir_id(id))
},
_ => def
// the moment, give a kind of vague error message.
if trait_params != impl_params {
let def_span = tcx.sess.source_map().def_span(span);
- let span = tcx.hir().get_generics_span(impl_m.def_id).unwrap_or(def_span);
+ let span = tcx.hir().get_generics(impl_m.def_id).map(|g| g.span).unwrap_or(def_span);
let mut err = struct_span_err!(
tcx.sess,
span,
err.span_label(span, "lifetimes do not match method in trait");
if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) {
let def_sp = tcx.sess.source_map().def_span(sp);
- let sp = tcx.hir().get_generics_span(trait_m.def_id).unwrap_or(def_sp);
+ let sp = tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp);
err.span_label(sp, "lifetimes in impl do not match this method in trait");
}
err.emit();
fn compare_number_of_generics<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_: &ty::AssocItem,
- impl_span: Span,
+ _impl_span: Span,
trait_: &ty::AssocItem,
trait_span: Option<Span>,
) -> Result<(), ErrorReported> {
if impl_count != trait_count {
err_occurred = true;
- let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap();
- let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
- let span = if impl_item.generics.params.is_empty()
- || impl_item.generics.span.is_dummy() { // argument position impl Trait (#55374)
- impl_span
+ let (
+ trait_spans,
+ impl_trait_spans,
+ ) = if let Some(trait_hir_id) = tcx.hir().as_local_hir_id(trait_.def_id) {
+ let trait_item = tcx.hir().expect_trait_item(trait_hir_id);
+ if trait_item.generics.params.is_empty() {
+ (Some(vec![trait_item.generics.span]), vec![])
+ } else {
+ let arg_spans: Vec<Span> = trait_item.generics.params.iter()
+ .map(|p| p.span)
+ .collect();
+ let impl_trait_spans: Vec<Span> = trait_item.generics.params.iter()
+ .filter_map(|p| match p.kind {
+ GenericParamKind::Type {
+ synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
+ } => Some(p.span),
+ _ => None,
+ }).collect();
+ (Some(arg_spans), impl_trait_spans)
+ }
} else {
- impl_item.generics.span
+ (trait_span.map(|s| vec![s]), vec![])
};
+ let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap();
+ let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
+ let impl_item_impl_trait_spans: Vec<Span> = impl_item.generics.params.iter()
+ .filter_map(|p| match p.kind {
+ GenericParamKind::Type {
+ synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
+ } => Some(p.span),
+ _ => None,
+ }).collect();
+ let spans = impl_item.generics.spans();
+ let span = spans.primary_span();
+
let mut err = tcx.sess.struct_span_err_with_code(
- span,
+ spans,
&format!(
"method `{}` has {} {kind} parameter{} but its trait \
declaration has {} {kind} parameter{}",
let mut suffix = None;
- if let Some(span) = trait_span {
- err.span_label(
- span,
- format!("expected {} {} parameter{}", trait_count, kind,
- if trait_count != 1 { "s" } else { "" })
- );
+ if let Some(spans) = trait_spans {
+ let mut spans = spans.iter();
+ if let Some(span) = spans.next() {
+ err.span_label(*span, format!(
+ "expected {} {} parameter{}",
+ trait_count,
+ kind,
+ if trait_count != 1 { "s" } else { "" },
+ ));
+ }
+ for span in spans {
+ err.span_label(*span, "");
+ }
} else {
suffix = Some(format!(", expected {}", trait_count));
}
- err.span_label(
- span,
- format!("found {} {} parameter{}{}", impl_count, kind,
+ if let Some(span) = span {
+ err.span_label(span, format!(
+ "found {} {} parameter{}{}",
+ impl_count,
+ kind,
if impl_count != 1 { "s" } else { "" },
- suffix.unwrap_or_else(|| String::new())),
- );
+ suffix.unwrap_or_else(|| String::new()),
+ ));
+ }
+
+ for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {
+ err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
+ }
err.emit();
}
Err(ErrorReported) => return (tcx.types.err, res),
};
let path_segs = match res {
- Res::Local(_) | Res::Upvar(..) => Vec::new(),
+ Res::Local(_) => vec![],
Res::Def(kind, def_id) =>
AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id),
_ => bug!("instantiate_value_path on {:?}", res),
}
}));
- match res {
- Res::Local(hid) | Res::Upvar(hid, ..) => {
- let ty = self.local_ty(span, hid).decl_ty;
- let ty = self.normalize_associated_types_in(span, &ty);
- self.write_ty(hir_id, ty);
- return (ty, res);
- }
- _ => {}
+ if let Res::Local(hid) = res {
+ let ty = self.local_ty(span, hid).decl_ty;
+ let ty = self.normalize_associated_types_in(span, &ty);
+ self.write_ty(hir_id, ty);
+ return (ty, res);
}
if generics_has_err {
// id of innermost fn body id
body_id: hir::HirId,
+ body_owner: DefId,
// call_site scope of innermost fn
call_site_scope: Option<region::Scope>,
region_scope_tree,
repeating_scope: initial_repeating_scope,
body_id: initial_body_id,
+ body_owner: subject,
call_site_scope: None,
subject_def_id: subject,
outlives_environment,
let body_id = body.id();
self.body_id = body_id.hir_id;
+ self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
let call_site = region::Scope {
id: body.value.hir_id.local_id,
// Save state of current function before invoking
// `visit_fn_body`. We will restore afterwards.
let old_body_id = self.body_id;
+ let old_body_owner = self.body_owner;
let old_call_site_scope = self.call_site_scope;
let env_snapshot = self.outlives_environment.push_snapshot_pre_closure();
.pop_snapshot_post_closure(env_snapshot);
self.call_site_scope = old_call_site_scope;
self.body_id = old_body_id;
+ self.body_owner = old_body_owner;
}
//visit_pat: visit_pat, // (..) see above
{
f(mc::MemCategorizationContext::with_infer(
&self.infcx,
+ self.body_owner,
&self.region_scope_tree,
&self.tables.borrow(),
))
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::infer::UpvarRegion;
use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts};
+use rustc_data_structures::fx::FxIndexMap;
use syntax::ast;
use syntax_pos::Span;
};
if let Some(upvars) = self.tcx.upvars(closure_def_id) {
- let mut upvar_list: Vec<ty::UpvarId> = Vec::with_capacity(upvars.len());
- for upvar in upvars.iter() {
+ let mut upvar_list: FxIndexMap<hir::HirId, ty::UpvarId> =
+ FxIndexMap::with_capacity_and_hasher(upvars.len(), Default::default());
+ for (&var_hir_id, _) in upvars.iter() {
let upvar_id = ty::UpvarId {
var_path: ty::UpvarPath {
- hir_id: upvar.var_id(),
+ hir_id: var_hir_id,
},
closure_expr_id: LocalDefId::from_def_id(closure_def_id),
};
debug!("seed upvar_id {:?}", upvar_id);
// Adding the upvar Id to the list of Upvars, which will be added
// to the map for the closure at the end of the for loop.
- upvar_list.push(upvar_id);
+ upvar_list.insert(var_hir_id, upvar_id);
let capture_kind = match capture_clause {
hir::CaptureByValue => ty::UpvarCapture::ByValue,
}
let body_owner_def_id = self.tcx.hir().body_owner_def_id(body.id());
+ assert_eq!(body_owner_def_id, closure_def_id);
let region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id);
let mut delegate = InferBorrowKind {
fcx: self,
euv::ExprUseVisitor::with_infer(
&mut delegate,
&self.infcx,
+ body_owner_def_id,
self.param_env,
region_scope_tree,
&self.tables.borrow(),
tcx.upvars(closure_def_id).iter().flat_map(|upvars| {
upvars
.iter()
- .map(|upvar| {
- let var_hir_id = upvar.var_id();
+ .map(|(&var_hir_id, _)| {
let upvar_ty = self.node_ty(var_hir_id);
let upvar_id = ty::UpvarId {
var_path: ty::UpvarPath { hir_id: var_hir_id },
}
wbcx.visit_body(body);
wbcx.visit_upvar_capture_map();
- wbcx.visit_upvar_list_map();
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types();
);
wbcx.tables.used_trait_imports = used_trait_imports;
+ wbcx.tables.upvar_list = mem::replace(
+ &mut self.tables.borrow_mut().upvar_list,
+ Default::default(),
+ );
+
wbcx.tables.tainted_by_errors = self.is_tainted_by_errors();
debug!(
item_def_id, wbcx.tables
);
- self.tcx.alloc_tables(wbcx.tables)
+ self.tcx.arena.alloc(wbcx.tables)
}
}
}
}
- /// Runs through the function context's upvar list map and adds the same to
- /// the TypeckTables. upvarlist is a hashmap of the list of upvars referred
- /// to in a closure..
- fn visit_upvar_list_map(&mut self) {
- for (closure_def_id, upvar_list) in self.fcx.tables.borrow().upvar_list.iter() {
- debug!(
- "UpvarIDs captured by closure {:?} are: {:?}",
- closure_def_id, upvar_list
- );
- self.tables
- .upvar_list
- .insert(*closure_def_id, upvar_list.to_vec());
- }
- }
-
fn visit_closures(&mut self) {
let fcx_tables = self.fcx.tables.borrow();
debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
let is_marker = tcx.has_attr(def_id, sym::marker);
let def_path_hash = tcx.def_path_hash(def_id);
let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, is_marker, def_path_hash);
- tcx.alloc_trait_def(def)
+ tcx.arena.alloc(def)
}
fn has_late_bound_regions<'a, 'tcx>(
.map(|param| (param.def_id, param.index))
.collect();
- tcx.alloc_generics(ty::Generics {
+ tcx.arena.alloc(ty::Generics {
parent: parent_def_id,
parent_count,
params,
```
"##,
+E0730: r##"
+An array without a fixed length was pattern-matched.
+
+Example of erroneous code:
+
+```compile_fail,E0730
+#![feature(const_generics)]
+
+fn is_123<const N: usize>(x: [u32; N]) -> bool {
+ match x {
+ [1, 2, 3] => true, // error: cannot pattern-match on an
+ // array without a fixed length
+ _ => false
+ }
+}
+```
+
+Ensure that the pattern is consistent with the size of the matched
+array. Additional elements can be matched with `..`:
+
+```
+#![feature(slice_patterns)]
+
+let r = &[1, 2, 3, 4];
+match r {
+ &[a, b, ..] => { // ok!
+ println!("a={}, b={}", a, b);
+ }
+}
+```
+"##,
+
}
register_diagnostics! {
}
}
if attrs.len() > 0 {
- write!(w, "<div class=\"docblock attributes{}\">{}</div>",
+ write!(w, "<span class=\"docblock attributes{}\">{}</span>",
if top { " top-attr" } else { "" }, &attrs)?;
}
Ok(())
var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
if (match) {
from = parseInt(match[1], 10);
- to = Math.min(50000, parseInt(match[2] || match[1], 10));
- from = Math.min(from, to);
+ to = from;
+ if (typeof match[2] !== "undefined") {
+ to = parseInt(match[2], 10);
+ }
+ if (to < from) {
+ var tmp = to;
+ to = from;
+ from = tmp;
+ }
elem = document.getElementById(from);
if (!elem) {
return;
});
});
for (i = from; i <= to; ++i) {
- addClass(document.getElementById(i), "line-highlighted");
+ elem = document.getElementById(i);
+ if (!elem) {
+ break;
+ }
+ addClass(elem, "line-highlighted");
}
} else if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
addClass(search, "hidden");
crate-type = ["dylib", "rlib"]
[dependencies]
+indexmap = "1"
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
}
}
+impl<K, V, S> Encodable for indexmap::IndexMap<K, V, S>
+ where K: Encodable + Hash + Eq,
+ V: Encodable,
+ S: BuildHasher,
+{
+ fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
+ e.emit_map(self.len(), |e| {
+ let mut i = 0;
+ for (key, val) in self {
+ e.emit_map_elt_key(i, |e| key.encode(e))?;
+ e.emit_map_elt_val(i, |e| val.encode(e))?;
+ i += 1;
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<K, V, S> Decodable for indexmap::IndexMap<K, V, S>
+ where K: Decodable + Hash + Eq,
+ V: Decodable,
+ S: BuildHasher + Default,
+{
+ fn decode<D: Decoder>(d: &mut D) -> Result<indexmap::IndexMap<K, V, S>, D::Error> {
+ d.read_map(|d, len| {
+ let state = Default::default();
+ let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state);
+ for i in 0..len {
+ let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?;
+ let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?;
+ map.insert(key, val);
+ }
+ Ok(map)
+ })
+ }
+}
+
+impl<T, S> Encodable for indexmap::IndexSet<T, S>
+ where T: Encodable + Hash + Eq,
+ S: BuildHasher,
+{
+ fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
+ s.emit_seq(self.len(), |s| {
+ let mut i = 0;
+ for e in self {
+ s.emit_seq_elt(i, |s| e.encode(s))?;
+ i += 1;
+ }
+ Ok(())
+ })
+ }
+}
+
+impl<T, S> Decodable for indexmap::IndexSet<T, S>
+ where T: Decodable + Hash + Eq,
+ S: BuildHasher + Default,
+{
+ fn decode<D: Decoder>(d: &mut D) -> Result<indexmap::IndexSet<T, S>, D::Error> {
+ d.read_seq(|d, len| {
+ let state = Default::default();
+ let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state);
+ for i in 0..len {
+ set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ }
+ Ok(set)
+ })
+ }
+}
+
impl<T: Encodable> Encodable for Rc<[T]> {
fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
s.emit_seq(self.len(), |s| {
compiler_builtins = { version = "0.1.15" }
profiler_builtins = { path = "../libprofiler_builtins", optional = true }
unwind = { path = "../libunwind" }
-hashbrown = { version = "0.3.0", features = ['rustc-dep-of-std'] }
+hashbrown = { version = "0.4.0", features = ['rustc-dep-of-std'] }
[dependencies.backtrace]
version = "0.3.25"
/// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
/// ```
fn from(err: String) -> Box<dyn Error + Send + Sync> {
- #[derive(Debug)]
struct StringError(String);
impl Error for StringError {
}
}
+ // Purposefully skip printing "StringError(..)"
+ impl Debug for StringError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Debug::fmt(&self.0, f)
+ }
+ }
+
Box::new(StringError(err))
}
}
///
/// ```compile_fail
/// #[cfg(not(any(feature = "foo", feature = "bar")))]
- /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.")
+ /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.");
/// ```
///
/// [`panic!`]: ../std/macro.panic.html
///
/// The following return false:
///
- /// - private address (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16)
- /// - the loopback address (127.0.0.0/8)
- /// - the link-local address (169.254.0.0/16)
- /// - the broadcast address (255.255.255.255/32)
- /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24)
- /// - the unspecified address (0.0.0.0)
+ /// - private addresses (see [`is_private()`](#method.is_private))
+ /// - the loopback address (see [`is_loopback()`](#method.is_loopback))
+ /// - the link-local address (see [`is_link_local()`](#method.is_link_local))
+ /// - the broadcast address (see [`is_broadcast()`](#method.is_broadcast))
+ /// - addresses used for documentation (see [`is_documentation()`](#method.is_documentation))
+ /// - the unspecified address (see [`is_unspecified()`](#method.is_unspecified)), and the whole
+ /// 0.0.0.0/8 block
+ /// - addresses reserved for future protocols (see
+ /// [`is_ietf_protocol_assignment()`](#method.is_ietf_protocol_assignment), except
+ /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable
+ /// - addresses reserved for future use (see [`is_reserved()`](#method.is_reserved)
+ /// - addresses reserved for networking devices benchmarking (see
+ /// [`is_benchmarking`](#method.is_benchmarking))
///
/// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
/// [`true`]: ../../std/primitive.bool.html
/// use std::net::Ipv4Addr;
///
/// fn main() {
+ /// // private addresses are not global
/// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
/// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
/// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
+ ///
+ /// // the 0.0.0.0/8 block is not global
+ /// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false);
+ /// // in particular, the unspecified address is not global
/// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false);
+ ///
+ /// // the loopback address is not global
+ /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false);
+ ///
+ /// // link local addresses are not global
+ /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false);
+ ///
+ /// // the broadcast address is not global
+ /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false);
+ ///
+ /// // the broadcast address is not global
+ /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false);
+ /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false);
+ /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false);
+ ///
+ /// // shared addresses are not global
+ /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
+ ///
+ /// // addresses reserved for protocol assignment are not global
+ /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false);
+ /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false);
+ ///
+ /// // addresses reserved for future use are not global
+ /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
+ ///
+ /// // addresses reserved for network devices benchmarking are not global
+ /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
+ ///
+ /// // All the other addresses are global
+ /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true);
/// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
/// }
/// ```
pub fn is_global(&self) -> bool {
- !self.is_private() && !self.is_loopback() && !self.is_link_local() &&
- !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified()
+ // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
+ // globally routable addresses in the 192.0.0.0/24 range.
+ if u32::from(*self) == 0xc0000009 || u32::from(*self) == 0xc000000a {
+ return true;
+ }
+ !self.is_private()
+ && !self.is_loopback()
+ && !self.is_link_local()
+ && !self.is_broadcast()
+ && !self.is_documentation()
+ && !self.is_shared()
+ && !self.is_ietf_protocol_assignment()
+ && !self.is_reserved()
+ && !self.is_benchmarking()
+ // Make sure the address is not in 0.0.0.0/8
+ && self.octets()[0] != 0
+ }
+
+ /// Returns [`true`] if this address is part of the Shared Address Space defined in
+ /// [IETF RFC 6598] (`100.64.0.0/10`).
+ ///
+ /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ /// use std::net::Ipv4Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true);
+ /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true);
+ /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false);
+ /// }
+ /// ```
+ pub fn is_shared(&self) -> bool {
+ self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
+ }
+
+ /// Returns [`true`] if this address is part of `192.0.0.0/24`, which is reserved to
+ /// IANA for IETF protocol assignments, as documented in [IETF RFC 6890].
+ ///
+ /// Note that parts of this block are in use:
+ ///
+ /// - `192.0.0.8/32` is the "IPv4 dummy address" (see [IETF RFC 7600])
+ /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723])
+ /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155])
+ ///
+ /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890
+ /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600
+ /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723
+ /// [IETF RFC 8155]: https://tools.ietf.org/html/rfc8155
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ /// use std::net::Ipv4Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true);
+ /// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).is_ietf_protocol_assignment(), true);
+ /// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).is_ietf_protocol_assignment(), true);
+ /// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_ietf_protocol_assignment(), true);
+ /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false);
+ /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false);
+ /// }
+ /// ```
+ pub fn is_ietf_protocol_assignment(&self) -> bool {
+ self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
+ }
+
+ /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for
+ /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0`
+ /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`.
+ ///
+ /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112
+ /// [errate 423]: https://www.rfc-editor.org/errata/eid423
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ /// use std::net::Ipv4Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false);
+ /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true);
+ /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true);
+ /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false);
+ /// }
+ /// ```
+ pub fn is_benchmarking(&self) -> bool {
+ self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
+ }
+
+ /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112]
+ /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the
+ /// broadcast address `255.255.255.255`, but this implementation explicitely excludes it, since
+ /// it is obviously not reserved for future use.
+ ///
+ /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112
+ /// [`true`]: ../../std/primitive.bool.html
+ ///
+ /// # Warning
+ ///
+ /// As IANA assigns new addresses, this method will be
+ /// updated. This may result in non-reserved addresses being
+ /// treated as reserved in code that relies on an outdated version
+ /// of this method.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ /// use std::net::Ipv4Addr;
+ ///
+ /// fn main() {
+ /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true);
+ /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true);
+ ///
+ /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false);
+ /// // The broadcast address is not considered as reserved for future use by this
+ /// // implementation
+ /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false);
+ /// }
+ /// ```
+ pub fn is_reserved(&self) -> bool {
+ self.octets()[0] & 240 == 240 && !self.is_broadcast()
}
/// Returns [`true`] if this is a multicast address (224.0.0.0/4).
}
}
- /// Returns [`true`] if this is a unique local address (fc00::/7).
+ /// Returns [`true`] if this is a unique local address (`fc00::/7`).
///
/// This property is defined in [IETF RFC 4193].
///
(self.segments()[0] & 0xfe00) == 0xfc00
}
- /// Returns [`true`] if the address is unicast and link-local (fe80::/10).
+ /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`).
///
- /// This property is defined in [IETF RFC 4291].
+ /// A common mis-conception is to think that "unicast link-local addresses start with
+ /// `fe80::`", but the [IETF RFC 4291] actually defines a stricter format for these addresses:
+ ///
+ /// ```no_rust
+ /// | 10 |
+ /// | bits | 54 bits | 64 bits |
+ /// +----------+-------------------------+----------------------------+
+ /// |1111111010| 0 | interface ID |
+ /// +----------+-------------------------+----------------------------+
+ /// ```
+ ///
+ /// This method validates the format defined in the RFC and won't recognize the following
+ /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example.
+ /// If you need a less strict validation use [`is_unicast_link_local()`] instead.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip)]
+ ///
+ /// use std::net::Ipv6Addr;
+ ///
+ /// fn main() {
+ /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
+ /// assert!(ip.is_unicast_link_local_strict());
+ ///
+ /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
+ /// assert!(ip.is_unicast_link_local_strict());
+ ///
+ /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
+ /// assert!(!ip.is_unicast_link_local_strict());
+ /// assert!(ip.is_unicast_link_local());
+ ///
+ /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
+ /// assert!(!ip.is_unicast_link_local_strict());
+ /// assert!(ip.is_unicast_link_local());
+ /// }
+ /// ```
+ ///
+ /// # See also
+ ///
+ /// - [IETF RFC 4291 section 2.5.6]
+ /// - [RFC 4291 errata 4406]
+ /// - [`is_unicast_link_local()`]
///
/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+ /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
/// [`true`]: ../../std/primitive.bool.html
+ /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
+ /// [`is_unicast_link_local()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local
+ ///
+ pub fn is_unicast_link_local_strict(&self) -> bool {
+ (self.segments()[0] & 0xffff) == 0xfe80
+ && (self.segments()[1] & 0xffff) == 0
+ && (self.segments()[2] & 0xffff) == 0
+ && (self.segments()[3] & 0xffff) == 0
+ }
+
+ /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`).
+ ///
+ /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4],
+ /// i.e. addresses with the following format:
+ ///
+ /// ```no_rust
+ /// | 10 |
+ /// | bits | 54 bits | 64 bits |
+ /// +----------+-------------------------+----------------------------+
+ /// |1111111010| arbitratry value | interface ID |
+ /// +----------+-------------------------+----------------------------+
+ /// ```
+ ///
+ /// As a result, this method consider addresses such as `fe80:0:0:1::` or `fe81::` to be
+ /// unicast link-local addresses, whereas [`is_unicast_link_local_strict()`] does not. If you
+ /// need a strict validation fully compliant with the RFC, use
+ /// [`is_unicast_link_local_strict()`].
///
/// # Examples
///
/// use std::net::Ipv6Addr;
///
/// fn main() {
- /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_link_local(),
- /// false);
- /// assert_eq!(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
+ /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
+ /// assert!(ip.is_unicast_link_local());
+ ///
+ /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
+ /// assert!(ip.is_unicast_link_local());
+ ///
+ /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
+ /// assert!(ip.is_unicast_link_local());
+ /// assert!(!ip.is_unicast_link_local_strict());
+ ///
+ /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
+ /// assert!(ip.is_unicast_link_local());
+ /// assert!(!ip.is_unicast_link_local_strict());
/// }
/// ```
+ ///
+ /// # See also
+ ///
+ /// - [IETF RFC 4291 section 2.4]
+ /// - [RFC 4291 errata 4406]
+ ///
+ /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
+ /// [`true`]: ../../std/primitive.bool.html
+ /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
+ /// [`is_unicast_link_local_strict()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local_strict
+ ///
pub fn is_unicast_link_local(&self) -> bool {
(self.segments()[0] & 0xffc0) == 0xfe80
}
- /// Returns [`true`] if this is a deprecated unicast site-local address
- /// (fec0::/10).
+ /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The
+ /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as:
+ ///
+ /// ```no_rust
+ /// | 10 |
+ /// | bits | 54 bits | 64 bits |
+ /// +----------+-------------------------+----------------------------+
+ /// |1111111011| subnet ID | interface ID |
+ /// +----------+-------------------------+----------------------------+
+ /// ```
///
/// [`true`]: ../../std/primitive.bool.html
+ /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
///
/// # Examples
///
/// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true);
/// }
/// ```
+ ///
+ /// # Warning
+ ///
+ /// As per [RFC 3879], the whole `FEC0::/10` prefix is
+ /// deprecated. New software must not support site-local
+ /// addresses.
+ ///
+ /// [RFC 3879]: https://tools.ietf.org/html/rfc3879
pub fn is_unicast_site_local(&self) -> bool {
(self.segments()[0] & 0xffc0) == 0xfec0
}
///
/// - the loopback address
/// - the link-local addresses
- /// - the (deprecated) site-local addresses
/// - unique local addresses
/// - the unspecified address
/// - the address range reserved for documentation
///
+ /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7]
+ ///
+ /// ```no_rust
+ /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer
+ /// be supported in new implementations (i.e., new implementations must treat this prefix as
+ /// Global Unicast).
+ /// ```
+ ///
/// [`true`]: ../../std/primitive.bool.html
+ /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
///
/// # Examples
///
/// ```
pub fn is_unicast_global(&self) -> bool {
!self.is_multicast()
- && !self.is_loopback() && !self.is_unicast_link_local()
- && !self.is_unicast_site_local() && !self.is_unique_local()
- && !self.is_unspecified() && !self.is_documentation()
+ && !self.is_loopback()
+ && !self.is_unicast_link_local()
+ && !self.is_unique_local()
+ && !self.is_unspecified()
+ && !self.is_documentation()
}
/// Returns the address's multicast scope if the address is multicast.
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests {
use crate::net::*;
- use crate::net::Ipv6MulticastScope::*;
use crate::net::test::{tsa, sa6, sa4};
+ use crate::str::FromStr;
#[test]
fn test_from_str_ipv4() {
#[test]
fn ip_properties() {
- fn check4(octets: &[u8; 4], unspec: bool, loopback: bool,
- global: bool, multicast: bool, documentation: bool) {
- let ip = IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]));
- assert_eq!(ip.is_unspecified(), unspec);
- assert_eq!(ip.is_loopback(), loopback);
- assert_eq!(ip.is_global(), global);
- assert_eq!(ip.is_multicast(), multicast);
- assert_eq!(ip.is_documentation(), documentation);
+ macro_rules! ip {
+ ($s:expr) => {
+ IpAddr::from_str($s).unwrap()
+ }
}
- fn check6(str_addr: &str, unspec: bool, loopback: bool,
- global: bool, u_doc: bool, mcast: bool) {
- let ip = IpAddr::V6(str_addr.parse().unwrap());
- assert_eq!(ip.is_unspecified(), unspec);
- assert_eq!(ip.is_loopback(), loopback);
- assert_eq!(ip.is_global(), global);
- assert_eq!(ip.is_documentation(), u_doc);
- assert_eq!(ip.is_multicast(), mcast);
+ macro_rules! check {
+ ($s:expr) => {
+ check!($s, 0);
+ };
+
+ ($s:expr, $mask:expr) => {{
+ let unspec: u8 = 1 << 0;
+ let loopback: u8 = 1 << 1;
+ let global: u8 = 1 << 2;
+ let multicast: u8 = 1 << 3;
+ let doc: u8 = 1 << 4;
+
+ if ($mask & unspec) == unspec {
+ assert!(ip!($s).is_unspecified());
+ } else {
+ assert!(!ip!($s).is_unspecified());
+ }
+
+ if ($mask & loopback) == loopback {
+ assert!(ip!($s).is_loopback());
+ } else {
+ assert!(!ip!($s).is_loopback());
+ }
+
+ if ($mask & global) == global {
+ assert!(ip!($s).is_global());
+ } else {
+ assert!(!ip!($s).is_global());
+ }
+
+ if ($mask & multicast) == multicast {
+ assert!(ip!($s).is_multicast());
+ } else {
+ assert!(!ip!($s).is_multicast());
+ }
+
+ if ($mask & doc) == doc {
+ assert!(ip!($s).is_documentation());
+ } else {
+ assert!(!ip!($s).is_documentation());
+ }
+ }}
}
- // address unspec loopbk global multicast doc
- check4(&[0, 0, 0, 0], true, false, false, false, false);
- check4(&[0, 0, 0, 1], false, false, true, false, false);
- check4(&[0, 1, 0, 0], false, false, true, false, false);
- check4(&[10, 9, 8, 7], false, false, false, false, false);
- check4(&[127, 1, 2, 3], false, true, false, false, false);
- check4(&[172, 31, 254, 253], false, false, false, false, false);
- check4(&[169, 254, 253, 242], false, false, false, false, false);
- check4(&[192, 0, 2, 183], false, false, false, false, true);
- check4(&[192, 1, 2, 183], false, false, true, false, false);
- check4(&[192, 168, 254, 253], false, false, false, false, false);
- check4(&[198, 51, 100, 0], false, false, false, false, true);
- check4(&[203, 0, 113, 0], false, false, false, false, true);
- check4(&[203, 2, 113, 0], false, false, true, false, false);
- check4(&[224, 0, 0, 0], false, false, true, true, false);
- check4(&[239, 255, 255, 255], false, false, true, true, false);
- check4(&[255, 255, 255, 255], false, false, false, false, false);
-
- // address unspec loopbk global doc mcast
- check6("::", true, false, false, false, false);
- check6("::1", false, true, false, false, false);
- check6("::0.0.0.2", false, false, true, false, false);
- check6("1::", false, false, true, false, false);
- check6("fc00::", false, false, false, false, false);
- check6("fdff:ffff::", false, false, false, false, false);
- check6("fe80:ffff::", false, false, false, false, false);
- check6("febf:ffff::", false, false, false, false, false);
- check6("fec0::", false, false, false, false, false);
- check6("ff01::", false, false, false, false, true);
- check6("ff02::", false, false, false, false, true);
- check6("ff03::", false, false, false, false, true);
- check6("ff04::", false, false, false, false, true);
- check6("ff05::", false, false, false, false, true);
- check6("ff08::", false, false, false, false, true);
- check6("ff0e::", false, false, true, false, true);
- check6("2001:db8:85a3::8a2e:370:7334", false, false, false, true, false);
- check6("102:304:506:708:90a:b0c:d0e:f10", false, false, true, false, false);
+ let unspec: u8 = 1 << 0;
+ let loopback: u8 = 1 << 1;
+ let global: u8 = 1 << 2;
+ let multicast: u8 = 1 << 3;
+ let doc: u8 = 1 << 4;
+
+ check!("0.0.0.0", unspec);
+ check!("0.0.0.1");
+ check!("0.1.0.0");
+ check!("10.9.8.7");
+ check!("127.1.2.3", loopback);
+ check!("172.31.254.253");
+ check!("169.254.253.242");
+ check!("192.0.2.183", doc);
+ check!("192.1.2.183", global);
+ check!("192.168.254.253");
+ check!("198.51.100.0", doc);
+ check!("203.0.113.0", doc);
+ check!("203.2.113.0", global);
+ check!("224.0.0.0", global|multicast);
+ check!("239.255.255.255", global|multicast);
+ check!("255.255.255.255");
+ // make sure benchmarking addresses are not global
+ check!("198.18.0.0");
+ check!("198.18.54.2");
+ check!("198.19.255.255");
+ // make sure addresses reserved for protocol assignment are not global
+ check!("192.0.0.0");
+ check!("192.0.0.255");
+ check!("192.0.0.100");
+ // make sure reserved addresses are not global
+ check!("240.0.0.0");
+ check!("251.54.1.76");
+ check!("254.255.255.255");
+ // make sure shared addresses are not global
+ check!("100.64.0.0");
+ check!("100.127.255.255");
+ check!("100.100.100.0");
+
+ check!("::", unspec);
+ check!("::1", loopback);
+ check!("::0.0.0.2", global);
+ check!("1::", global);
+ check!("fc00::");
+ check!("fdff:ffff::");
+ check!("fe80:ffff::");
+ check!("febf:ffff::");
+ check!("fec0::", global);
+ check!("ff01::", multicast);
+ check!("ff02::", multicast);
+ check!("ff03::", multicast);
+ check!("ff04::", multicast);
+ check!("ff05::", multicast);
+ check!("ff08::", multicast);
+ check!("ff0e::", global|multicast);
+ check!("2001:db8:85a3::8a2e:370:7334", doc);
+ check!("102:304:506:708:90a:b0c:d0e:f10", global);
}
#[test]
fn ipv4_properties() {
- fn check(octets: &[u8; 4], unspec: bool, loopback: bool,
- private: bool, link_local: bool, global: bool,
- multicast: bool, broadcast: bool, documentation: bool) {
- let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]);
- assert_eq!(octets, &ip.octets());
-
- assert_eq!(ip.is_unspecified(), unspec);
- assert_eq!(ip.is_loopback(), loopback);
- assert_eq!(ip.is_private(), private);
- assert_eq!(ip.is_link_local(), link_local);
- assert_eq!(ip.is_global(), global);
- assert_eq!(ip.is_multicast(), multicast);
- assert_eq!(ip.is_broadcast(), broadcast);
- assert_eq!(ip.is_documentation(), documentation);
+ macro_rules! ip {
+ ($s:expr) => {
+ Ipv4Addr::from_str($s).unwrap()
+ }
}
- // address unspec loopbk privt linloc global multicast brdcast doc
- check(&[0, 0, 0, 0], true, false, false, false, false, false, false, false);
- check(&[0, 0, 0, 1], false, false, false, false, true, false, false, false);
- check(&[0, 1, 0, 0], false, false, false, false, true, false, false, false);
- check(&[10, 9, 8, 7], false, false, true, false, false, false, false, false);
- check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false);
- check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false);
- check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false);
- check(&[192, 0, 2, 183], false, false, false, false, false, false, false, true);
- check(&[192, 1, 2, 183], false, false, false, false, true, false, false, false);
- check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false);
- check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true);
- check(&[203, 0, 113, 0], false, false, false, false, false, false, false, true);
- check(&[203, 2, 113, 0], false, false, false, false, true, false, false, false);
- check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false);
- check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false);
- check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false);
+ macro_rules! check {
+ ($s:expr) => {
+ check!($s, 0);
+ };
+
+ ($s:expr, $mask:expr) => {{
+ let unspec: u16 = 1 << 0;
+ let loopback: u16 = 1 << 1;
+ let private: u16 = 1 << 2;
+ let link_local: u16 = 1 << 3;
+ let global: u16 = 1 << 4;
+ let multicast: u16 = 1 << 5;
+ let broadcast: u16 = 1 << 6;
+ let documentation: u16 = 1 << 7;
+ let benchmarking: u16 = 1 << 8;
+ let ietf_protocol_assignment: u16 = 1 << 9;
+ let reserved: u16 = 1 << 10;
+ let shared: u16 = 1 << 11;
+
+ if ($mask & unspec) == unspec {
+ assert!(ip!($s).is_unspecified());
+ } else {
+ assert!(!ip!($s).is_unspecified());
+ }
+
+ if ($mask & loopback) == loopback {
+ assert!(ip!($s).is_loopback());
+ } else {
+ assert!(!ip!($s).is_loopback());
+ }
+
+ if ($mask & private) == private {
+ assert!(ip!($s).is_private());
+ } else {
+ assert!(!ip!($s).is_private());
+ }
+
+ if ($mask & link_local) == link_local {
+ assert!(ip!($s).is_link_local());
+ } else {
+ assert!(!ip!($s).is_link_local());
+ }
+
+ if ($mask & global) == global {
+ assert!(ip!($s).is_global());
+ } else {
+ assert!(!ip!($s).is_global());
+ }
+
+ if ($mask & multicast) == multicast {
+ assert!(ip!($s).is_multicast());
+ } else {
+ assert!(!ip!($s).is_multicast());
+ }
+
+ if ($mask & broadcast) == broadcast {
+ assert!(ip!($s).is_broadcast());
+ } else {
+ assert!(!ip!($s).is_broadcast());
+ }
+
+ if ($mask & documentation) == documentation {
+ assert!(ip!($s).is_documentation());
+ } else {
+ assert!(!ip!($s).is_documentation());
+ }
+
+ if ($mask & benchmarking) == benchmarking {
+ assert!(ip!($s).is_benchmarking());
+ } else {
+ assert!(!ip!($s).is_benchmarking());
+ }
+
+ if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment {
+ assert!(ip!($s).is_ietf_protocol_assignment());
+ } else {
+ assert!(!ip!($s).is_ietf_protocol_assignment());
+ }
+
+ if ($mask & reserved) == reserved {
+ assert!(ip!($s).is_reserved());
+ } else {
+ assert!(!ip!($s).is_reserved());
+ }
+
+ if ($mask & shared) == shared {
+ assert!(ip!($s).is_shared());
+ } else {
+ assert!(!ip!($s).is_shared());
+ }
+ }}
+ }
+
+ let unspec: u16 = 1 << 0;
+ let loopback: u16 = 1 << 1;
+ let private: u16 = 1 << 2;
+ let link_local: u16 = 1 << 3;
+ let global: u16 = 1 << 4;
+ let multicast: u16 = 1 << 5;
+ let broadcast: u16 = 1 << 6;
+ let documentation: u16 = 1 << 7;
+ let benchmarking: u16 = 1 << 8;
+ let ietf_protocol_assignment: u16 = 1 << 9;
+ let reserved: u16 = 1 << 10;
+ let shared: u16 = 1 << 11;
+
+ check!("0.0.0.0", unspec);
+ check!("0.0.0.1");
+ check!("0.1.0.0");
+ check!("10.9.8.7", private);
+ check!("127.1.2.3", loopback);
+ check!("172.31.254.253", private);
+ check!("169.254.253.242", link_local);
+ check!("192.0.2.183", documentation);
+ check!("192.1.2.183", global);
+ check!("192.168.254.253", private);
+ check!("198.51.100.0", documentation);
+ check!("203.0.113.0", documentation);
+ check!("203.2.113.0", global);
+ check!("224.0.0.0", global|multicast);
+ check!("239.255.255.255", global|multicast);
+ check!("255.255.255.255", broadcast);
+ check!("198.18.0.0", benchmarking);
+ check!("198.18.54.2", benchmarking);
+ check!("198.19.255.255", benchmarking);
+ check!("192.0.0.0", ietf_protocol_assignment);
+ check!("192.0.0.255", ietf_protocol_assignment);
+ check!("192.0.0.100", ietf_protocol_assignment);
+ check!("240.0.0.0", reserved);
+ check!("251.54.1.76", reserved);
+ check!("254.255.255.255", reserved);
+ check!("100.64.0.0", shared);
+ check!("100.127.255.255", shared);
+ check!("100.100.100.0", shared);
}
#[test]
fn ipv6_properties() {
- fn check(str_addr: &str, octets: &[u8; 16], unspec: bool, loopback: bool,
- unique_local: bool, global: bool,
- u_link_local: bool, u_site_local: bool, u_global: bool, u_doc: bool,
- m_scope: Option<Ipv6MulticastScope>) {
- let ip: Ipv6Addr = str_addr.parse().unwrap();
- assert_eq!(str_addr, ip.to_string());
- assert_eq!(&ip.octets(), octets);
- assert_eq!(Ipv6Addr::from(*octets), ip);
-
- assert_eq!(ip.is_unspecified(), unspec);
- assert_eq!(ip.is_loopback(), loopback);
- assert_eq!(ip.is_unique_local(), unique_local);
- assert_eq!(ip.is_global(), global);
- assert_eq!(ip.is_unicast_link_local(), u_link_local);
- assert_eq!(ip.is_unicast_site_local(), u_site_local);
- assert_eq!(ip.is_unicast_global(), u_global);
- assert_eq!(ip.is_documentation(), u_doc);
- assert_eq!(ip.multicast_scope(), m_scope);
- assert_eq!(ip.is_multicast(), m_scope.is_some());
+ macro_rules! ip {
+ ($s:expr) => {
+ Ipv6Addr::from_str($s).unwrap()
+ }
+ }
+
+ macro_rules! check {
+ ($s:expr, &[$($octet:expr),*], $mask:expr) => {
+ assert_eq!($s, ip!($s).to_string());
+ let octets = &[$($octet),*];
+ assert_eq!(&ip!($s).octets(), octets);
+ assert_eq!(Ipv6Addr::from(*octets), ip!($s));
+
+ let unspecified: u16 = 1 << 0;
+ let loopback: u16 = 1 << 1;
+ let unique_local: u16 = 1 << 2;
+ let global: u16 = 1 << 3;
+ let unicast_link_local: u16 = 1 << 4;
+ let unicast_link_local_strict: u16 = 1 << 5;
+ let unicast_site_local: u16 = 1 << 6;
+ let unicast_global: u16 = 1 << 7;
+ let documentation: u16 = 1 << 8;
+ let multicast_interface_local: u16 = 1 << 9;
+ let multicast_link_local: u16 = 1 << 10;
+ let multicast_realm_local: u16 = 1 << 11;
+ let multicast_admin_local: u16 = 1 << 12;
+ let multicast_site_local: u16 = 1 << 13;
+ let multicast_organization_local: u16 = 1 << 14;
+ let multicast_global: u16 = 1 << 15;
+ let multicast: u16 = multicast_interface_local
+ | multicast_admin_local
+ | multicast_global
+ | multicast_link_local
+ | multicast_realm_local
+ | multicast_site_local
+ | multicast_organization_local;
+
+ if ($mask & unspecified) == unspecified {
+ assert!(ip!($s).is_unspecified());
+ } else {
+ assert!(!ip!($s).is_unspecified());
+ }
+ if ($mask & loopback) == loopback {
+ assert!(ip!($s).is_loopback());
+ } else {
+ assert!(!ip!($s).is_loopback());
+ }
+ if ($mask & unique_local) == unique_local {
+ assert!(ip!($s).is_unique_local());
+ } else {
+ assert!(!ip!($s).is_unique_local());
+ }
+ if ($mask & global) == global {
+ assert!(ip!($s).is_global());
+ } else {
+ assert!(!ip!($s).is_global());
+ }
+ if ($mask & unicast_link_local) == unicast_link_local {
+ assert!(ip!($s).is_unicast_link_local());
+ } else {
+ assert!(!ip!($s).is_unicast_link_local());
+ }
+ if ($mask & unicast_link_local_strict) == unicast_link_local_strict {
+ assert!(ip!($s).is_unicast_link_local_strict());
+ } else {
+ assert!(!ip!($s).is_unicast_link_local_strict());
+ }
+ if ($mask & unicast_site_local) == unicast_site_local {
+ assert!(ip!($s).is_unicast_site_local());
+ } else {
+ assert!(!ip!($s).is_unicast_site_local());
+ }
+ if ($mask & unicast_global) == unicast_global {
+ assert!(ip!($s).is_unicast_global());
+ } else {
+ assert!(!ip!($s).is_unicast_global());
+ }
+ if ($mask & documentation) == documentation {
+ assert!(ip!($s).is_documentation());
+ } else {
+ assert!(!ip!($s).is_documentation());
+ }
+ if ($mask & multicast) != 0 {
+ assert!(ip!($s).multicast_scope().is_some());
+ assert!(ip!($s).is_multicast());
+ } else {
+ assert!(ip!($s).multicast_scope().is_none());
+ assert!(!ip!($s).is_multicast());
+ }
+ if ($mask & multicast_interface_local) == multicast_interface_local {
+ assert_eq!(ip!($s).multicast_scope().unwrap(),
+ Ipv6MulticastScope::InterfaceLocal);
+ }
+ if ($mask & multicast_link_local) == multicast_link_local {
+ assert_eq!(ip!($s).multicast_scope().unwrap(),
+ Ipv6MulticastScope::LinkLocal);
+ }
+ if ($mask & multicast_realm_local) == multicast_realm_local {
+ assert_eq!(ip!($s).multicast_scope().unwrap(),
+ Ipv6MulticastScope::RealmLocal);
+ }
+ if ($mask & multicast_admin_local) == multicast_admin_local {
+ assert_eq!(ip!($s).multicast_scope().unwrap(),
+ Ipv6MulticastScope::AdminLocal);
+ }
+ if ($mask & multicast_site_local) == multicast_site_local {
+ assert_eq!(ip!($s).multicast_scope().unwrap(),
+ Ipv6MulticastScope::SiteLocal);
+ }
+ if ($mask & multicast_organization_local) == multicast_organization_local {
+ assert_eq!(ip!($s).multicast_scope().unwrap(),
+ Ipv6MulticastScope::OrganizationLocal);
+ }
+ if ($mask & multicast_global) == multicast_global {
+ assert_eq!(ip!($s).multicast_scope().unwrap(),
+ Ipv6MulticastScope::Global);
+ }
+ }
}
- // unspec loopbk uniqlo global unill unisl uniglo doc mscope
- check("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- true, false, false, false, false, false, false, false, None);
- check("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
- false, true, false, false, false, false, false, false, None);
- check("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
- false, false, false, true, false, false, true, false, None);
- check("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, false, true, false, false, true, false, None);
- check("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, true, false, false, false, false, false, None);
- check("fdff:ffff::", &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, true, false, false, false, false, false, None);
- check("fe80:ffff::", &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, false, false, true, false, false, false, None);
- check("febf:ffff::", &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, false, false, true, false, false, false, None);
- check("fec0::", &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, false, false, false, true, false, false, None);
- check("ff01::", &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, false, false, false, false, false, false, Some(InterfaceLocal));
- check("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, false, false, false, false, false, false, Some(LinkLocal));
- check("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, false, false, false, false, false, false, Some(RealmLocal));
- check("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, false, false, false, false, false, false, Some(AdminLocal));
- check("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, false, false, false, false, false, false, Some(SiteLocal));
- check("ff08::", &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, false, false, false, false, false, false, Some(OrganizationLocal));
- check("ff0e::", &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- false, false, false, true, false, false, false, false, Some(Global));
- check("2001:db8:85a3::8a2e:370:7334",
- &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
- false, false, false, false, false, false, false, true, None);
- check("102:304:506:708:90a:b0c:d0e:f10",
- &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
- false, false, false, true, false, false, true, false, None);
+ let unspecified: u16 = 1 << 0;
+ let loopback: u16 = 1 << 1;
+ let unique_local: u16 = 1 << 2;
+ let global: u16 = 1 << 3;
+ let unicast_link_local: u16 = 1 << 4;
+ let unicast_link_local_strict: u16 = 1 << 5;
+ let unicast_site_local: u16 = 1 << 6;
+ let unicast_global: u16 = 1 << 7;
+ let documentation: u16 = 1 << 8;
+ let multicast_interface_local: u16 = 1 << 9;
+ let multicast_link_local: u16 = 1 << 10;
+ let multicast_realm_local: u16 = 1 << 11;
+ let multicast_admin_local: u16 = 1 << 12;
+ let multicast_site_local: u16 = 1 << 13;
+ let multicast_organization_local: u16 = 1 << 14;
+ let multicast_global: u16 = 1 << 15;
+
+ check!("::",
+ &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ unspecified);
+
+ check!("::1",
+ &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
+ loopback);
+
+ check!("::0.0.0.2",
+ &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
+ global | unicast_global);
+
+ check!("1::",
+ &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ global | unicast_global);
+
+ check!("fc00::",
+ &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ unique_local);
+
+ check!("fdff:ffff::",
+ &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ unique_local);
+
+ check!("fe80:ffff::",
+ &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ unicast_link_local);
+
+ check!("fe80::",
+ &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ unicast_link_local|unicast_link_local_strict);
+
+ check!("febf:ffff::",
+ &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ unicast_link_local);
+
+ check!("febf::",
+ &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ unicast_link_local);
+
+ check!("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+ &[0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
+ unicast_link_local);
+
+ check!("fe80::ffff:ffff:ffff:ffff",
+ &[0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
+ unicast_link_local|unicast_link_local_strict);
+
+ check!("fe80:0:0:1::",
+ &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
+ unicast_link_local);
+
+ check!("fec0::",
+ &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ unicast_site_local|unicast_global|global);
+
+ check!("ff01::",
+ &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ multicast_interface_local);
+
+ check!("ff02::",
+ &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ multicast_link_local);
+
+ check!("ff03::",
+ &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ multicast_realm_local);
+
+ check!("ff04::",
+ &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ multicast_admin_local);
+
+ check!("ff05::",
+ &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ multicast_site_local);
+
+ check!("ff08::",
+ &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ multicast_organization_local);
+
+ check!("ff0e::",
+ &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ multicast_global | global);
+
+ check!("2001:db8:85a3::8a2e:370:7334",
+ &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
+ documentation);
+
+ check!("102:304:506:708:90a:b0c:d0e:f10",
+ &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
+ global| unicast_global);
}
#[test]
}
/// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes.
-#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Stability {
pub level: StabilityLevel,
pub feature: Symbol,
}
/// The available stability levels.
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
+#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
pub enum StabilityLevel {
// Reason for the current stability level and the relevant rust-lang issue
Unstable { reason: Option<Symbol>, issue: u32 },
}
}
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
+#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
pub struct RustcDeprecation {
pub since: Symbol,
pub reason: Symbol,
Applicability::MaybeIncorrect,
);
} else {
- err.note("type ascription is a nightly-only feature that lets \
- you annotate an expression with a type: `<expr>: <type>`")
+ err.note("#![feature(type_ascription)] lets you annotate an \
+ expression with a type: `<expr>: <type>`")
.span_note(
lhs_span,
"this expression expects an ascribed type after the colon",
/// where typaramseq = ( typaram ) | ( typaram , typaramseq )
fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
let span_lo = self.span;
- if self.eat_lt() {
+ let (params, span) = if self.eat_lt() {
let params = self.parse_generic_params()?;
self.expect_gt()?;
- Ok(ast::Generics {
- params,
- where_clause: WhereClause {
- id: ast::DUMMY_NODE_ID,
- predicates: Vec::new(),
- span: DUMMY_SP,
- },
- span: span_lo.to(self.prev_span),
- })
+ (params, span_lo.to(self.prev_span))
} else {
- Ok(ast::Generics::default())
- }
+ (vec![], self.prev_span.between(self.span))
+ };
+ Ok(ast::Generics {
+ params,
+ where_clause: WhereClause {
+ id: ast::DUMMY_NODE_ID,
+ predicates: Vec::new(),
+ span: DUMMY_SP,
+ },
+ span,
+ })
}
/// Parses generic args (within a path segment) with recovery for extra leading angle brackets.
return Ok(Some(item));
}
- // `unsafe async fn` or `async fn`
- if (
- self.check_keyword(kw::Unsafe) &&
- self.is_keyword_ahead(1, &[kw::Async])
- ) || (
- self.check_keyword(kw::Async) &&
- self.is_keyword_ahead(1, &[kw::Fn])
- )
- {
- // ASYNC FUNCTION ITEM
- let unsafety = self.parse_unsafety();
- self.expect_keyword(kw::Async)?;
- let async_span = self.prev_span;
- self.expect_keyword(kw::Fn)?;
- let fn_span = self.prev_span;
- let (ident, item_, extra_attrs) =
- self.parse_item_fn(unsafety,
- respan(async_span, IsAsync::Async {
- closure_id: ast::DUMMY_NODE_ID,
- return_impl_trait_id: ast::DUMMY_NODE_ID,
- arguments: Vec::new(),
- }),
- respan(fn_span, Constness::NotConst),
- Abi::Rust)?;
- let prev_span = self.prev_span;
- let item = self.mk_item(lo.to(prev_span),
- ident,
- item_,
- visibility,
- maybe_append(attrs, extra_attrs));
- if self.span.rust_2015() {
- self.diagnostic().struct_span_err_with_code(
- async_span,
- "`async fn` is not permitted in the 2015 edition",
- DiagnosticId::Error("E0670".into())
- ).emit();
+ // Parse `async unsafe? fn`.
+ if self.check_keyword(kw::Async) {
+ let async_span = self.span;
+ if self.is_keyword_ahead(1, &[kw::Fn])
+ || self.is_keyword_ahead(2, &[kw::Fn])
+ {
+ // ASYNC FUNCTION ITEM
+ self.bump(); // `async`
+ let unsafety = self.parse_unsafety(); // `unsafe`?
+ self.expect_keyword(kw::Fn)?; // `fn`
+ let fn_span = self.prev_span;
+ let (ident, item_, extra_attrs) =
+ self.parse_item_fn(unsafety,
+ respan(async_span, IsAsync::Async {
+ closure_id: ast::DUMMY_NODE_ID,
+ return_impl_trait_id: ast::DUMMY_NODE_ID,
+ arguments: Vec::new(),
+ }),
+ respan(fn_span, Constness::NotConst),
+ Abi::Rust)?;
+ let prev_span = self.prev_span;
+ let item = self.mk_item(lo.to(prev_span),
+ ident,
+ item_,
+ visibility,
+ maybe_append(attrs, extra_attrs));
+ if self.span.rust_2015() {
+ self.diagnostic().struct_span_err_with_code(
+ async_span,
+ "`async fn` is not permitted in the 2015 edition",
+ DiagnosticId::Error("E0670".into())
+ ).emit();
+ }
+ return Ok(Some(item));
}
- return Ok(Some(item));
}
if self.check_keyword(kw::Unsafe) &&
self.is_keyword_ahead(1, &[kw::Trait, kw::Auto])
if desc.allow_fail {
TrAllowedFail
} else {
- TrFailedMsg(format!("Panic did not include expected string '{}'", msg))
+ TrFailedMsg(format!("panic did not include expected string '{}'", msg))
}
}
}
panic!("an error message");
}
let expected = "foobar";
- let failed_msg = "Panic did not include expected string";
+ let failed_msg = "panic did not include expected string";
let desc = TestDescAndFn {
desc: TestDesc {
name: StaticTestName("whatever"),
-Subproject commit 4efebe31651d5520bcba968878dbb8a4971d2045
+Subproject commit 788592fb2740d560d0614a77035b319b9d07aa38
// run-pass
#![allow(dead_code, unreachable_patterns)]
+#![allow(ellipsis_inclusive_range_patterns)]
struct Foo;
<Foo as HasNum>::NUM ... <Foo>::NUM => true,
_ => false,
});
+
+ assert!(match 2 {
+ Foo::NUM ..= 3 => true,
+ _ => false,
+ });
+ assert!(match 0 {
+ -1 ..= <Foo as HasNum>::NUM => true,
+ _ => false,
+ });
+ assert!(match 1 {
+ <Foo as HasNum>::NUM ..= <Foo>::NUM => true,
+ _ => false,
+ });
}
// run-pass
// Parsing of range patterns
+#![allow(ellipsis_inclusive_range_patterns)]
+
const NUM1: i32 = 10;
mod m {
if let NUM1 ... m::NUM2 = 10 {} else { panic!() }
if let ::NUM1 ... ::m::NUM2 = 11 {} else { panic!() }
if let -13 ... -10 = 12 { panic!() } else {}
+
+ if let NUM1 ..= m::NUM2 = 10 {} else { panic!() }
+ if let ::NUM1 ..= ::m::NUM2 = 11 {} else { panic!() }
+ if let -13 ..= -10 = 12 { panic!() } else {}
}
-#![feature(const_int_conversion, reverse_bits)]
+#![feature(const_int_conversion)]
const REVERSE: u32 = 0x12345678_u32.reverse_bits();
const FROM_BE_BYTES: i32 = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]);
data: RefCell::new(vec![])
}
}
- fn alloc(&self) -> Ptr {
+ fn alloc(&self) -> Ptr<'_> {
self.cur_ops.set(self.cur_ops.get() + 1);
if self.cur_ops.get() == self.failing_op {
data.push(true);
Ptr(addr, self)
}
+ // FIXME(#47949) Any use of this indicates a bug in rustc: we should never
+ // be leaking values in the cases here.
+ //
+ // Creates a `Ptr<'_>` and checks that the allocated value is leaked if the
+ // `failing_op` is in the list of exception.
+ fn alloc_leaked(&self, exceptions: Vec<usize>) -> Ptr<'_> {
+ let ptr = self.alloc();
+
+ if exceptions.iter().any(|operation| *operation == self.failing_op) {
+ let mut data = self.data.borrow_mut();
+ data[ptr.0] = false;
+ }
+ ptr
+ }
}
struct Ptr<'a>(usize, &'a Allocator);
let[_, _y..] = ar;
}
+fn panic_after_return(a: &Allocator) -> Ptr<'_> {
+ // Panic in the drop of `p` or `q` can leak
+ let exceptions = vec![8, 9];
+ a.alloc();
+ let p = a.alloc();
+ {
+ a.alloc();
+ let p = a.alloc();
+ // FIXME (#47949) We leak values when we panic in a destructor after
+ // evaluating an expression with `rustc_mir::build::Builder::into`.
+ a.alloc_leaked(exceptions)
+ }
+}
+
+fn panic_after_return_expr(a: &Allocator) -> Ptr<'_> {
+ // Panic in the drop of `p` or `q` can leak
+ let exceptions = vec![8, 9];
+ a.alloc();
+ let p = a.alloc();
+ {
+ a.alloc();
+ let q = a.alloc();
+ // FIXME (#47949)
+ return a.alloc_leaked(exceptions);
+ }
+}
+
+fn panic_after_init(a: &Allocator) {
+ // Panic in the drop of `r` can leak
+ let exceptions = vec![8];
+ a.alloc();
+ let p = a.alloc();
+ let q = {
+ a.alloc();
+ let r = a.alloc();
+ // FIXME (#47949)
+ a.alloc_leaked(exceptions)
+ };
+}
+
+fn panic_after_init_temp(a: &Allocator) {
+ // Panic in the drop of `r` can leak
+ let exceptions = vec![8];
+ a.alloc();
+ let p = a.alloc();
+ {
+ a.alloc();
+ let r = a.alloc();
+ // FIXME (#47949)
+ a.alloc_leaked(exceptions)
+ };
+}
+
+fn panic_after_init_by_loop(a: &Allocator) {
+ // Panic in the drop of `r` can leak
+ let exceptions = vec![8];
+ a.alloc();
+ let p = a.alloc();
+ let q = loop {
+ a.alloc();
+ let r = a.alloc();
+ // FIXME (#47949)
+ break a.alloc_leaked(exceptions);
+ };
+}
+
fn run_test<F>(mut f: F)
where F: FnMut(&Allocator)
{
run_test(|a| slice_pattern_reassign(a));
run_test(|a| subslice_pattern_reassign(a));
+ run_test(|a| {
+ panic_after_return(a);
+ });
+ run_test(|a| {
+ panic_after_return_expr(a);
+ });
+ run_test(|a| panic_after_init(a));
+ run_test(|a| panic_after_init_temp(a));
+ run_test(|a| panic_after_init_by_loop(a));
+
run_test_nopanic(|a| union1(a));
}
// Test old and new syntax for inclusive range patterns.
+#![allow(ellipsis_inclusive_range_patterns)]
+
fn main() {
assert!(match 42 { 0 ... 100 => true, _ => false });
assert!(match 42 { 0 ..= 100 => true, _ => false });
// run-pass
#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620
+#![allow(ellipsis_inclusive_range_patterns)]
// regression test for the model lexer handling the DOTDOTDOT syntax (#15877)
#![allow(dead_code)]
fn test1(x: i8) -> i32 {
match x {
- 1...10 => 0,
+ 1..=10 => 0,
_ => 1,
}
}
// ignore-tidy-linelength
pub trait Foo {
- // @has foo/trait.Foo.html '//h3[@id="tymethod.foo"]//div[@class="docblock attributes"]' '#[must_use]'
+ // @has foo/trait.Foo.html '//h3[@id="tymethod.foo"]//span[@class="docblock attributes"]' '#[must_use]'
#[must_use]
fn foo();
}
pub struct Bar;
impl Bar {
- // @has foo/struct.Bar.html '//h4[@id="method.bar"]//div[@class="docblock attributes"]' '#[must_use]'
+ // @has foo/struct.Bar.html '//h4[@id="method.bar"]//span[@class="docblock attributes"]' '#[must_use]'
#[must_use]
pub fn bar() {}
- // @has foo/struct.Bar.html '//h4[@id="method.bar2"]//div[@class="docblock attributes"]' '#[must_use]'
+ // @has foo/struct.Bar.html '//h4[@id="method.bar2"]//span[@class="docblock attributes"]' '#[must_use]'
#[must_use]
pub fn bar2() {}
}
}
}
-unsafe async fn unsafe_async_fn(x: u8) -> u8 {
+async unsafe fn unsafe_async_fn(x: u8) -> u8 {
wake_and_yield_once().await;
x
}
}
}
-unsafe async fn unsafe_async_fn(x: u8) -> u8 {
+async unsafe fn unsafe_async_fn(x: u8) -> u8 {
await!(wake_and_yield_once());
x
}
LL | let mut test = |foo: &Foo| {
| ----------- mutable borrow occurs here
LL | ptr = box Foo { x: ptr.x + 1 };
- | --- first borrow occurs due to use of `ptr` in closure
+ | --- first borrow occurs due to use of `ptr` in closure
LL | };
LL | test(&*ptr);
| ---- ^^^^^ immutable borrow occurs here
| ^^
error[E0195]: lifetime parameters or bounds on method `wrong_bound2` do not match the trait declaration
- --> $DIR/regions-bound-missing-bound-in-impl.rs:41:5
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:41:20
|
LL | fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
| ---------------- lifetimes in impl do not match this method in trait
...
LL | fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
+ | ^ lifetimes do not match method in trait
error[E0276]: impl has stricter requirements than trait
--> $DIR/regions-bound-missing-bound-in-impl.rs:48:5
--- /dev/null
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct Foo<T, const N: usize>([T; {N}]);
+
+impl<T, const N: usize> Foo<T, {N}> {
+ fn foo(&self) -> usize {
+ {N}
+ }
+}
+
+fn main() {
+ let foo = Foo([0u32; 21]);
+ assert_eq!(foo.0, [0u32; 21]);
+ assert_eq!(foo.foo(), 21);
+}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+ --> $DIR/const-generic-array-wrapper.rs:3:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+
--- /dev/null
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+use std::mem;
+
+fn foo<const SIZE: usize>() {
+ let arr: [u8; SIZE] = unsafe {
+ let mut array: [u8; SIZE] = mem::uninitialized();
+ array
+ };
+}
+
+fn main() {}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+ --> $DIR/issue-61422.rs:3:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+
--- /dev/null
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+use std::ops::AddAssign;
+
+fn inc<T: AddAssign + Clone, const N: usize>(v: &mut [T; N]) -> &mut [T; N] {
+ for x in v.iter_mut() {
+ *x += x.clone();
+ }
+ v
+}
+
+fn main() {
+ let mut v = [1, 2, 3];
+ inc(&mut v);
+ assert_eq!(v, [2, 4, 6]);
+}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+ --> $DIR/mut-ref-const-param-array.rs:3:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+
--- /dev/null
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+use std::mem::MaybeUninit;
+
+#[repr(transparent)]
+pub struct MaybeUninitWrapper<const N: usize>(MaybeUninit<[u64; N]>);
+
+fn main() {}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+ --> $DIR/transparent-maybeunit-array-wrapper.rs:3:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+
-#![feature(reverse_bits)]
-
fn main() {
let x: &'static i32 = &(5_i32.reverse_bits());
//~^ ERROR temporary value dropped while borrowed
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:4:28
+ --> $DIR/const-int-conversion.rs:2:28
|
LL | let x: &'static i32 = &(5_i32.reverse_bits());
| ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:6:28
+ --> $DIR/const-int-conversion.rs:4:28
|
LL | let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]));
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:8:28
+ --> $DIR/const-int-conversion.rs:6:28
|
LL | let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]));
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:10:28
+ --> $DIR/const-int-conversion.rs:8:28
|
LL | let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0])));
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:12:29
+ --> $DIR/const-int-conversion.rs:10:29
|
LL | let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes());
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:14:29
+ --> $DIR/const-int-conversion.rs:12:29
|
LL | let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes());
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:16:29
+ --> $DIR/const-int-conversion.rs:14:29
|
LL | let d: &'static [u8] = &(i32::min_value().to_be().to_ne_bytes());
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
fn foo(x: bool) -> Self { Bar } //~ ERROR E0049
}
+trait Fuzz {
+ fn fuzz<A: Default, B>(x: A, y: B) -> Self;
+}
+
+struct Baz;
+
+impl Fuzz for Baz {
+ fn fuzz(x: bool, y: bool) -> Self { Baz } //~ ERROR E0049
+}
+
fn main() {
}
error[E0049]: method `foo` has 0 type parameters but its trait declaration has 1 type parameter
- --> $DIR/E0049.rs:8:5
+ --> $DIR/E0049.rs:8:11
|
LL | fn foo<T: Default>(x: T) -> Self;
- | --------------------------------- expected 1 type parameter
+ | - expected 1 type parameter
...
LL | fn foo(x: bool) -> Self { Bar }
- | ^^^^^^^^^^^^^^^^^^^^^^^ found 0 type parameters
+ | ^ found 0 type parameters
-error: aborting due to previous error
+error[E0049]: method `fuzz` has 0 type parameters but its trait declaration has 2 type parameters
+ --> $DIR/E0049.rs:18:12
+ |
+LL | fn fuzz<A: Default, B>(x: A, y: B) -> Self;
+ | - -
+ | |
+ | expected 2 type parameters
+...
+LL | fn fuzz(x: bool, y: bool) -> Self { Baz }
+ | ^ found 0 type parameters
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0049`.
--- /dev/null
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+fn is_123<const N: usize>(x: [u32; N]) -> bool {
+ match x {
+ [1, 2, 3] => true, //~ ERROR cannot pattern-match on an array without a fixed length
+ _ => false
+ }
+}
+
+fn main() {}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+ --> $DIR/E0730.rs:1:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+
+error[E0730]: cannot pattern-match on an array without a fixed length
+ --> $DIR/E0730.rs:6:9
+ |
+LL | [1, 2, 3] => true,
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0730`.
// run-rustfix
// ignore-wasm32 no external library to link to.
-// compile-flags: -g -Z continue-parse-after-error
+// compile-flags: -g
#![feature(rustc_private)]
extern crate libc;
// run-rustfix
// ignore-wasm32 no external library to link to.
-// compile-flags: -g -Z continue-parse-after-error
+// compile-flags: -g
#![feature(rustc_private)]
extern crate libc;
-// compile-flags: -Z continue-parse-after-error
// ignore-tidy-tab
fn main() {
error: incorrect unicode escape sequence
- --> $DIR/format-string-error-2.rs:78:20
+ --> $DIR/format-string-error-2.rs:77:20
|
LL | println!("\x7B}\u8 {", 1);
| ^^-
| help: format of unicode escape sequences uses braces: `\u{8}`
error: invalid format string: expected `'}'`, found `'a'`
- --> $DIR/format-string-error-2.rs:6:5
+ --> $DIR/format-string-error-2.rs:5:5
|
LL | format!("{
| - because of this opening brace
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'b'`
- --> $DIR/format-string-error-2.rs:10:5
+ --> $DIR/format-string-error-2.rs:9:5
|
LL | format!("{ \
| - because of this opening brace
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'\'`
- --> $DIR/format-string-error-2.rs:12:18
+ --> $DIR/format-string-error-2.rs:11:18
|
LL | format!(r#"{ \
| - ^ expected `}` in format string
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'\'`
- --> $DIR/format-string-error-2.rs:16:18
+ --> $DIR/format-string-error-2.rs:15:18
|
LL | format!(r#"{ \n
| - ^ expected `}` in format string
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'e'`
- --> $DIR/format-string-error-2.rs:22:5
+ --> $DIR/format-string-error-2.rs:21:5
|
LL | format!("{ \n
| - because of this opening brace
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'a'`
- --> $DIR/format-string-error-2.rs:26:5
+ --> $DIR/format-string-error-2.rs:25:5
|
LL | {
| - because of this opening brace
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'a'`
- --> $DIR/format-string-error-2.rs:30:5
+ --> $DIR/format-string-error-2.rs:29:5
|
LL | {
| - because of this opening brace
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'b'`
- --> $DIR/format-string-error-2.rs:36:5
+ --> $DIR/format-string-error-2.rs:35:5
|
LL | { \
| - because of this opening brace
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'b'`
- --> $DIR/format-string-error-2.rs:41:5
+ --> $DIR/format-string-error-2.rs:40:5
|
LL | { \
| - because of this opening brace
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'\'`
- --> $DIR/format-string-error-2.rs:46:8
+ --> $DIR/format-string-error-2.rs:45:8
|
LL | raw { \
| - ^ expected `}` in format string
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'\'`
- --> $DIR/format-string-error-2.rs:51:8
+ --> $DIR/format-string-error-2.rs:50:8
|
LL | raw { \n
| - ^ expected `}` in format string
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'e'`
- --> $DIR/format-string-error-2.rs:58:5
+ --> $DIR/format-string-error-2.rs:57:5
|
LL | { \n
| - because of this opening brace
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: expected `'}'`, found `'a'`
- --> $DIR/format-string-error-2.rs:68:5
+ --> $DIR/format-string-error-2.rs:67:5
|
LL | {
| - because of this opening brace
= note: if you intended to print `{`, you can escape it using `{{`
error: 1 positional argument in format string, but no arguments were given
- --> $DIR/format-string-error-2.rs:71:17
+ --> $DIR/format-string-error-2.rs:70:17
|
LL | println!("\t{}");
| ^^
error: invalid format string: expected `'}'` but string was terminated
- --> $DIR/format-string-error-2.rs:75:27
+ --> $DIR/format-string-error-2.rs:74:27
|
LL | println!("\x7B}\u{8} {", 1);
| -^ expected `'}'` in format string
= note: if you intended to print `{`, you can escape it using `{{`
error: invalid format string: unmatched `}` found
- --> $DIR/format-string-error-2.rs:82:21
+ --> $DIR/format-string-error-2.rs:81:21
|
LL | println!(r#"\x7B}\u{8} {"#, 1);
| ^ unmatched `}` in format string
= note: if you intended to print `}`, you can escape it using `}}`
error: invalid format string: unmatched `}` found
- --> $DIR/format-string-error-2.rs:85:21
+ --> $DIR/format-string-error-2.rs:84:21
|
LL | println!(r#"\x7B}\u8 {"#, 1);
| ^ unmatched `}` in format string
--> $DIR/fn-in-pat.rs:11:9
|
LL | A::new() => (),
- | ^^^^^^^^ not a tuple variant or struct
+ | ^^^^^^^^ `fn` calls are not allowed in patterns
+ |
+ = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html
error: aborting due to previous error
-// compile-flags: -Z parse-only -Z continue-parse-after-error
+// compile-flags: -Z parse-only
fn f() -> impl A + {} // OK
fn f() -> impl A + B {} // OK
| ----------- mutable borrow occurs here
LL | println!("access {}", foo.x);
LL | ptr = box Foo { x: ptr.x + 1 };
- | --- first borrow occurs due to use of `ptr` in closure
+ | --- first borrow occurs due to use of `ptr` in closure
...
LL | test(&*ptr);
| ---- ^^^^^ immutable borrow occurs here
LL | println!("{}", a: &mut 4);
| ^ expecting a type here because of type ascription
|
- = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+ = note: #![feature(type_ascription)] lets you annotate an expression with a type: `<expr>: <type>`
note: this expression expects an ascribed type after the colon
--> $DIR/issue-22644.rs:34:20
|
-// compile-flags: -Z continue-parse-after-error
-
enum Bird {
pub Duck,
//~^ ERROR unnecessary visibility qualifier
error: unnecessary visibility qualifier
- --> $DIR/issue-28433.rs:4:5
+ --> $DIR/issue-28433.rs:2:5
|
LL | pub Duck,
| ^^^ `pub` not permitted here
error: unnecessary visibility qualifier
- --> $DIR/issue-28433.rs:7:5
+ --> $DIR/issue-28433.rs:5:5
|
LL | pub(crate) Dove
| ^^^^^^^^^^ `pub` not permitted here
LL | Test::Drill(field: 42);
| ^^ expecting a type here because of type ascription
|
- = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+ = note: #![feature(type_ascription)] lets you annotate an expression with a type: `<expr>: <type>`
note: this expression expects an ascribed type after the colon
--> $DIR/issue-34255-1.rs:8:17
|
-// compile-flags: -Z continue-parse-after-error
-
struct Foo<Self>(Self);
//~^ ERROR expected identifier, found keyword `Self`
//~^^ ERROR E0392
error: expected identifier, found keyword `Self`
- --> $DIR/issue-36638.rs:3:12
+ --> $DIR/issue-36638.rs:1:12
|
LL | struct Foo<Self>(Self);
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/issue-36638.rs:7:11
+ --> $DIR/issue-36638.rs:5:11
|
LL | trait Bar<Self> {}
| ^^^^ expected identifier, found keyword
error[E0392]: parameter `Self` is never used
- --> $DIR/issue-36638.rs:3:12
+ --> $DIR/issue-36638.rs:1:12
|
LL | struct Foo<Self>(Self);
| ^^^^ unused parameter
error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
- --> $DIR/issue-36708.rs:8:11
+ --> $DIR/issue-36708.rs:8:12
|
LL | fn foo<T>() {}
- | ^^^ found 1 type parameter, expected 0
+ | ^ found 1 type parameter, expected 0
error: aborting due to previous error
--> $DIR/issue-55587.rs:4:9
|
LL | let Path::new();
- | ^^^^^^^^^^^ not a tuple variant or struct
+ | ^^^^^^^^^^^ `fn` calls are not allowed in patterns
+ |
+ = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html
error: aborting due to previous error
fn foo(&self, t: impl Clone) {}
//~^ ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters
//~| NOTE found 1 type parameter
+//~| NOTE `impl Trait` introduces an implicit type parameter
}
fn main() {}
error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters
- --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:5
+ --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:22
|
LL | fn foo(&self, t: Self::T);
- | -------------------------- expected 0 type parameters
+ | - expected 0 type parameters
...
LL | fn foo(&self, t: impl Clone) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found 1 type parameter
+ | ^^^^^^^^^^
+ | |
+ | found 1 type parameter
+ | `impl Trait` introduces an implicit type parameter
error: aborting due to previous error
LL | loop { break 'label: loop { break 'label 42; }; }
| ^^^^ expecting a type here because of type ascription
|
- = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+ = note: #![feature(type_ascription)] lets you annotate an expression with a type: `<expr>: <type>`
note: this expression expects an ascribed type after the colon
--> $DIR/lifetime_starts_expressions.rs:6:12
|
// compile-pass
+#![allow(ellipsis_inclusive_range_patterns)]
#![allow(unreachable_patterns)]
#![allow(unused_variables)]
#![warn(unused_parens)]
fn main() {
+ match 1 {
+ (_) => {} //~ WARNING: unnecessary parentheses around pattern
+ (y) => {} //~ WARNING: unnecessary parentheses around pattern
+ (ref r) => {} //~ WARNING: unnecessary parentheses around pattern
+ (e @ 1...2) => {} //~ WARNING: unnecessary parentheses around outer pattern
+ (1...2) => {} // Non ambiguous range pattern should not warn
+ e @ (3...4) => {} // Non ambiguous range pattern should not warn
+ }
+
+ match &1 {
+ (e @ &(1...2)) => {} //~ WARNING: unnecessary parentheses around outer pattern
+ &(_) => {} //~ WARNING: unnecessary parentheses around pattern
+ e @ &(1...2) => {} // Ambiguous range pattern should not warn
+ &(1...2) => {} // Ambiguous range pattern should not warn
+ }
+
+ match &1 {
+ e @ &(1...2) | e @ &(3...4) => {} // Complex ambiguous pattern should not warn
+ &_ => {}
+ }
+
match 1 {
(_) => {} //~ WARNING: unnecessary parentheses around pattern
(y) => {} //~ WARNING: unnecessary parentheses around pattern
}
match &1 {
- (e @ &(1...2)) => {} //~ WARNING: unnecessary parentheses around outer pattern
+ (e @ &(1..=2)) => {} //~ WARNING: unnecessary parentheses around outer pattern
&(_) => {} //~ WARNING: unnecessary parentheses around pattern
- e @ &(1...2) => {} // Ambiguous range pattern should not warn
+ e @ &(1..=2) => {} // Ambiguous range pattern should not warn
&(1..=2) => {} // Ambiguous range pattern should not warn
}
match &1 {
- e @ &(1...2) | e @ &(3..=4) => {} // Complex ambiguous pattern should not warn
+ e @ &(1..=2) | e @ &(3..=4) => {} // Complex ambiguous pattern should not warn
&_ => {}
}
}
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:9:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:10:9
|
LL | (_) => {}
| ^^^ help: remove these parentheses
|
note: lint level defined here
- --> $DIR/issue-54538-unused-parens-lint.rs:5:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:6:9
|
LL | #![warn(unused_parens)]
| ^^^^^^^^^^^^^
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:10:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:11:9
|
LL | (y) => {}
| ^^^ help: remove these parentheses
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:11:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:12:9
|
LL | (ref r) => {}
| ^^^^^^^ help: remove these parentheses
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:12:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:13:9
|
-LL | (e @ 1..=2) => {}
+LL | (e @ 1...2) => {}
| ^^^^^^^^^^^ help: remove these parentheses
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:18:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:19:9
|
LL | (e @ &(1...2)) => {}
| ^^^^^^^^^^^^^^ help: remove these parentheses
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:19:10
+ --> $DIR/issue-54538-unused-parens-lint.rs:20:10
+ |
+LL | &(_) => {}
+ | ^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:31:9
+ |
+LL | (_) => {}
+ | ^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:32:9
+ |
+LL | (y) => {}
+ | ^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:33:9
+ |
+LL | (ref r) => {}
+ | ^^^^^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:34:9
+ |
+LL | (e @ 1..=2) => {}
+ | ^^^^^^^^^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:40:9
+ |
+LL | (e @ &(1..=2)) => {}
+ | ^^^^^^^^^^^^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:41:10
|
LL | &(_) => {}
| ^^^ help: remove these parentheses
--> $DIR/match-fn-call.rs:6:9
|
LL | Path::new("foo") => println!("foo"),
- | ^^^^^^^^^^^^^^^^ not a tuple variant or struct
+ | ^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns
+ |
+ = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html
error[E0164]: expected tuple struct/variant, found method `<Path>::new`
--> $DIR/match-fn-call.rs:8:9
|
LL | Path::new("bar") => println!("bar"),
- | ^^^^^^^^^^^^^^^^ not a tuple variant or struct
+ | ^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns
+ |
+ = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html
error: aborting due to 2 previous errors
fn main() {
match 5 {
- 1 ... 10 => { }
- 5 ... 6 => { }
+ 1 ..= 10 => { }
+ 5 ..= 6 => { }
_ => {}
};
match 5 {
- 3 ... 6 => { }
- 4 ... 6 => { }
+ 3 ..= 6 => { }
+ 4 ..= 6 => { }
_ => {}
};
match 5 {
- 4 ... 6 => { }
- 4 ... 6 => { }
+ 4 ..= 6 => { }
+ 4 ..= 6 => { }
_ => {}
};
match 'c' {
- 'A' ... 'z' => {}
- 'a' ... 'z' => {}
+ 'A' ..= 'z' => {}
+ 'a' ..= 'z' => {}
_ => {}
};
match 1.0f64 {
- 0.01f64 ... 6.5f64 => {}
+ 0.01f64 ..= 6.5f64 => {}
0.02f64 => {}
_ => {}
};
error: unreachable pattern
--> $DIR/match-range-fail-dominate.rs:12:7
|
-LL | 5 ... 6 => { }
+LL | 5 ..= 6 => { }
| ^^^^^^^
|
note: lint level defined here
error: unreachable pattern
--> $DIR/match-range-fail-dominate.rs:18:7
|
-LL | 4 ... 6 => { }
+LL | 4 ..= 6 => { }
| ^^^^^^^
error: unreachable pattern
--> $DIR/match-range-fail-dominate.rs:24:7
|
-LL | 4 ... 6 => { }
+LL | 4 ..= 6 => { }
| ^^^^^^^
error: unreachable pattern
--> $DIR/match-range-fail-dominate.rs:30:7
|
-LL | 'a' ... 'z' => {}
+LL | 'a' ..= 'z' => {}
| ^^^^^^^^^^^
warning: floating-point types cannot be used in patterns
--> $DIR/match-range-fail-dominate.rs:35:7
|
-LL | 0.01f64 ... 6.5f64 => {}
+LL | 0.01f64 ..= 6.5f64 => {}
| ^^^^^^^
|
= note: #[warn(illegal_floating_point_literal_pattern)] on by default
warning: floating-point types cannot be used in patterns
--> $DIR/match-range-fail-dominate.rs:35:19
|
-LL | 0.01f64 ... 6.5f64 => {}
+LL | 0.01f64 ..= 6.5f64 => {}
| ^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
warning: floating-point types cannot be used in patterns
--> $DIR/match-range-fail-dominate.rs:35:7
|
-LL | 0.01f64 ... 6.5f64 => {}
+LL | 0.01f64 ..= 6.5f64 => {}
| ^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: defining type: DefId(0:14 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]::{{closure}}[0]) with closure substs [
i16,
extern "rust-call" fn(()),
- &'_#1r mut &'_#2r i32,
- &'_#3r i32,
+ &'_#1r i32,
+ &'_#2r mut &'_#3r i32,
]
= note: number of external vids: 4
- = note: where '_#3r: '_#2r
+ = note: where '_#1r: '_#3r
note: External requirements
--> $DIR/escape-upvar-nested.rs:20:27
= note: defining type: DefId(0:13 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
extern "rust-call" fn(()),
- &'_#1r mut &'_#2r i32,
- &'_#3r i32,
+ &'_#1r i32,
+ &'_#2r mut &'_#3r i32,
]
= note: number of external vids: 4
- = note: where '_#3r: '_#2r
+ = note: where '_#1r: '_#3r
note: No external requirements
--> $DIR/escape-upvar-nested.rs:13:1
= note: defining type: DefId(0:13 ~ escape_upvar_ref[317d]::test[0]::{{closure}}[0]) with closure substs [
i16,
extern "rust-call" fn(()),
- &'_#1r mut &'_#2r i32,
- &'_#3r i32,
+ &'_#1r i32,
+ &'_#2r mut &'_#3r i32,
]
= note: number of external vids: 4
- = note: where '_#3r: '_#2r
+ = note: where '_#1r: '_#3r
note: No external requirements
--> $DIR/escape-upvar-ref.rs:17:1
fn digits(x: u8) -> u32 {
match x {
- OneDigit::FIRST...OneDigit::LAST => 1,
- TwoDigits::FIRST...TwoDigits::LAST => 2,
- ThreeDigits::FIRST...ThreeDigits::LAST => 3,
+ OneDigit::FIRST..=OneDigit::LAST => 1,
+ TwoDigits::FIRST..=TwoDigits::LAST => 2,
+ ThreeDigits::FIRST..=ThreeDigits::LAST => 3,
_ => unreachable!(),
}
}
-// compile-flags: -Z continue-parse-after-error
-
// Test you can't use a higher-ranked trait bound inside of a qualified
// path (just won't parse).
error: expected identifier, found keyword `for`
- --> $DIR/associated-types-project-from-hrtb-explicit.rs:12:21
+ --> $DIR/associated-types-project-from-hrtb-explicit.rs:10:21
|
LL | fn foo2<I>(x: <I as for<'x> Foo<&'x isize>>::A)
| ^^^ expected identifier, found keyword
| ^^^^^
error: expected one of `::` or `>`, found `Foo`
- --> $DIR/associated-types-project-from-hrtb-explicit.rs:12:29
+ --> $DIR/associated-types-project-from-hrtb-explicit.rs:10:29
|
LL | fn foo2<I>(x: <I as for<'x> Foo<&'x isize>>::A)
| ^^^ expected one of `::` or `>` here
-// compile-flags: -Z continue-parse-after-error
-
-
extern
"C"suffix //~ ERROR suffixes on an ABI spec are invalid
fn foo() {}
error: suffixes on an ABI spec are invalid
- --> $DIR/bad-lit-suffixes.rs:5:5
+ --> $DIR/bad-lit-suffixes.rs:2:5
|
LL | "C"suffix
| ^^^^^^^^^ invalid suffix `suffix`
error: suffixes on an ABI spec are invalid
- --> $DIR/bad-lit-suffixes.rs:9:5
+ --> $DIR/bad-lit-suffixes.rs:6:5
|
LL | "C"suffix
| ^^^^^^^^^ invalid suffix `suffix`
error: suffixes on a string literal are invalid
- --> $DIR/bad-lit-suffixes.rs:13:5
+ --> $DIR/bad-lit-suffixes.rs:10:5
|
LL | ""suffix;
| ^^^^^^^^ invalid suffix `suffix`
error: suffixes on a byte string literal are invalid
- --> $DIR/bad-lit-suffixes.rs:14:5
+ --> $DIR/bad-lit-suffixes.rs:11:5
|
LL | b""suffix;
| ^^^^^^^^^ invalid suffix `suffix`
error: suffixes on a string literal are invalid
- --> $DIR/bad-lit-suffixes.rs:15:5
+ --> $DIR/bad-lit-suffixes.rs:12:5
|
LL | r#""#suffix;
| ^^^^^^^^^^^ invalid suffix `suffix`
error: suffixes on a byte string literal are invalid
- --> $DIR/bad-lit-suffixes.rs:16:5
+ --> $DIR/bad-lit-suffixes.rs:13:5
|
LL | br#""#suffix;
| ^^^^^^^^^^^^ invalid suffix `suffix`
error: suffixes on a char literal are invalid
- --> $DIR/bad-lit-suffixes.rs:17:5
+ --> $DIR/bad-lit-suffixes.rs:14:5
|
LL | 'a'suffix;
| ^^^^^^^^^ invalid suffix `suffix`
error: suffixes on a byte literal are invalid
- --> $DIR/bad-lit-suffixes.rs:18:5
+ --> $DIR/bad-lit-suffixes.rs:15:5
|
LL | b'a'suffix;
| ^^^^^^^^^^ invalid suffix `suffix`
error: invalid width `1024` for integer literal
- --> $DIR/bad-lit-suffixes.rs:20:5
+ --> $DIR/bad-lit-suffixes.rs:17:5
|
LL | 1234u1024;
| ^^^^^^^^^
= help: valid widths are 8, 16, 32, 64 and 128
error: invalid width `1024` for integer literal
- --> $DIR/bad-lit-suffixes.rs:21:5
+ --> $DIR/bad-lit-suffixes.rs:18:5
|
LL | 1234i1024;
| ^^^^^^^^^
= help: valid widths are 8, 16, 32, 64 and 128
error: invalid width `1024` for float literal
- --> $DIR/bad-lit-suffixes.rs:22:5
+ --> $DIR/bad-lit-suffixes.rs:19:5
|
LL | 1234f1024;
| ^^^^^^^^^
= help: valid widths are 32 and 64
error: invalid width `1024` for float literal
- --> $DIR/bad-lit-suffixes.rs:23:5
+ --> $DIR/bad-lit-suffixes.rs:20:5
|
LL | 1234.5f1024;
| ^^^^^^^^^^^
= help: valid widths are 32 and 64
error: invalid suffix `suffix` for integer literal
- --> $DIR/bad-lit-suffixes.rs:25:5
+ --> $DIR/bad-lit-suffixes.rs:22:5
|
LL | 1234suffix;
| ^^^^^^^^^^ invalid suffix `suffix`
= help: the suffix must be one of the integral types (`u32`, `isize`, etc)
error: invalid suffix `suffix` for integer literal
- --> $DIR/bad-lit-suffixes.rs:26:5
+ --> $DIR/bad-lit-suffixes.rs:23:5
|
LL | 0b101suffix;
| ^^^^^^^^^^^ invalid suffix `suffix`
= help: the suffix must be one of the integral types (`u32`, `isize`, etc)
error: invalid suffix `suffix` for float literal
- --> $DIR/bad-lit-suffixes.rs:27:5
+ --> $DIR/bad-lit-suffixes.rs:24:5
|
LL | 1.0suffix;
| ^^^^^^^^^ invalid suffix `suffix`
= help: valid suffixes are `f32` and `f64`
error: invalid suffix `suffix` for float literal
- --> $DIR/bad-lit-suffixes.rs:28:5
+ --> $DIR/bad-lit-suffixes.rs:25:5
|
LL | 1.0e10suffix;
| ^^^^^^^^^^^^ invalid suffix `suffix`
-// compile-flags: -Z parse-only -Z continue-parse-after-error
+// compile-flags: -Z parse-only
struct S<
T: 'a + Tr, // OK
-// compile-flags: -Z continue-parse-after-error
-
struct X {
a: u8 /** document a */,
//~^ ERROR found a documentation comment that doesn't document anything
error[E0585]: found a documentation comment that doesn't document anything
- --> $DIR/doc-after-struct-field.rs:4:11
+ --> $DIR/doc-after-struct-field.rs:2:11
|
LL | a: u8 /** document a */,
| ^^^^^^^^^^^^^^^^^
= help: doc comments must come before what they document, maybe a comment was intended with `//`?
error[E0585]: found a documentation comment that doesn't document anything
- --> $DIR/doc-after-struct-field.rs:10:11
+ --> $DIR/doc-after-struct-field.rs:8:11
|
LL | a: u8 /// document a
| ^^^^^^^^^^^^^^
-// compile-flags: -Z continue-parse-after-error
-
fn main() {
/// document
//~^ ERROR found a documentation comment that doesn't document anything
error[E0585]: found a documentation comment that doesn't document anything
- --> $DIR/doc-before-fn-rbrace.rs:4:5
+ --> $DIR/doc-before-fn-rbrace.rs:2:5
|
LL | /// document
| ^^^^^^^^^^^^
-// compile-flags: -Z continue-parse-after-error
-
fn /// document
foo() {}
//~^^ ERROR expected identifier, found doc comment `/// document`
error: expected identifier, found doc comment `/// document`
- --> $DIR/doc-before-identifier.rs:3:4
+ --> $DIR/doc-before-identifier.rs:1:4
|
LL | fn /// document
| ^^^^^^^^^^^^ expected identifier, found doc comment
-// compile-flags: -Z continue-parse-after-error
-
mod Foo {
/// document
//~^ ERROR expected item after doc comment
error: expected item after doc comment
- --> $DIR/doc-before-mod-rbrace.rs:4:5
+ --> $DIR/doc-before-mod-rbrace.rs:2:5
|
LL | /// document
| ^^^^^^^^^^^^ this doc comment doesn't document anything
-// compile-flags: -Z continue-parse-after-error
-
struct X {
a: u8,
/// document
error[E0585]: found a documentation comment that doesn't document anything
- --> $DIR/doc-before-struct-rbrace-1.rs:5:5
+ --> $DIR/doc-before-struct-rbrace-1.rs:3:5
|
LL | /// document
| ^^^^^^^^^^^^
-// compile-flags: -Z continue-parse-after-error
-
struct X {
a: u8 /// document
//~^ ERROR found a documentation comment that doesn't document anything
error[E0585]: found a documentation comment that doesn't document anything
- --> $DIR/doc-before-struct-rbrace-2.rs:4:11
+ --> $DIR/doc-before-struct-rbrace-2.rs:2:11
|
LL | a: u8 /// document
| ^^^^^^^^^^^^
-// compile-flags: -Z continue-parse-after-error
-
struct Bar<T> { x: T } where T: Copy //~ ERROR expected item, found keyword `where`
fn main() {}
error: expected item, found keyword `where`
- --> $DIR/issue-17904-2.rs:3:24
+ --> $DIR/issue-17904-2.rs:1:24
|
LL | struct Bar<T> { x: T } where T: Copy
| ^^^^^ expected item
-// compile-flags: -Z continue-parse-after-error
-
struct Baz<U> where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax.
struct Baz<U> where U: Eq(U) -> R; // Notice this parses as well.
struct Baz<U>(U) where U: Eq; // This rightfully signals no error as well.
error: expected one of `:`, `==`, or `=`, found `;`
- --> $DIR/issue-17904.rs:6:33
+ --> $DIR/issue-17904.rs:4:33
|
LL | struct Foo<T> where T: Copy, (T);
| ^ expected one of `:`, `==`, or `=` here
-// compile-flags: -Z continue-parse-after-error
-
trait Trait<T> { type Item; }
pub fn test<W, I: Trait<Item=(), W> >() {}
error: associated type bindings must be declared after generic parameters
- --> $DIR/issue-32214.rs:5:25
+ --> $DIR/issue-32214.rs:3:25
|
LL | pub fn test<W, I: Trait<Item=(), W> >() {}
| -------^^^
-// compile-flags: -Z continue-parse-after-error
-
pub fn test() {
foo(|_|) //~ ERROR expected expression, found `)`
}
error: expected expression, found `)`
- --> $DIR/issue-32505.rs:4:12
+ --> $DIR/issue-32505.rs:2:12
|
LL | foo(|_|)
| ^ expected expression
-// compile-flags: -Z continue-parse-after-error
-
fn main() {
0b121; //~ ERROR invalid digit for a base 2 literal
0b10_10301; //~ ERROR invalid digit for a base 2 literal
error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:4:8
+ --> $DIR/lex-bad-binary-literal.rs:2:8
|
LL | 0b121;
| ^
error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:5:12
+ --> $DIR/lex-bad-binary-literal.rs:3:12
|
LL | 0b10_10301;
| ^
error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:6:7
+ --> $DIR/lex-bad-binary-literal.rs:4:7
|
LL | 0b30;
| ^
error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:7:7
+ --> $DIR/lex-bad-binary-literal.rs:5:7
|
LL | 0b41;
| ^
error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:8:7
+ --> $DIR/lex-bad-binary-literal.rs:6:7
|
LL | 0b5;
| ^
error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:9:7
+ --> $DIR/lex-bad-binary-literal.rs:7:7
|
LL | 0b6;
| ^
error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:10:7
+ --> $DIR/lex-bad-binary-literal.rs:8:7
|
LL | 0b7;
| ^
error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:11:7
+ --> $DIR/lex-bad-binary-literal.rs:9:7
|
LL | 0b8;
| ^
error: invalid digit for a base 2 literal
- --> $DIR/lex-bad-binary-literal.rs:12:7
+ --> $DIR/lex-bad-binary-literal.rs:10:7
|
LL | 0b9;
| ^
-// compile-flags: -Z continue-parse-after-error
-
fn main() {
0o1.0; //~ ERROR: octal float literal is not supported
0o2f32; //~ ERROR: octal float literal is not supported
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:4:5
+ --> $DIR/lex-bad-numeric-literals.rs:2:5
|
LL | 0o1.0;
| ^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:6:5
+ --> $DIR/lex-bad-numeric-literals.rs:4:5
|
LL | 0o3.0f32;
| ^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:7:5
+ --> $DIR/lex-bad-numeric-literals.rs:5:5
|
LL | 0o4e4;
| ^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:8:5
+ --> $DIR/lex-bad-numeric-literals.rs:6:5
|
LL | 0o5.0e5;
| ^^^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:9:5
+ --> $DIR/lex-bad-numeric-literals.rs:7:5
|
LL | 0o6e6f32;
| ^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:10:5
+ --> $DIR/lex-bad-numeric-literals.rs:8:5
|
LL | 0o7.0e7f64;
| ^^^^^^^
error: hexadecimal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:11:5
+ --> $DIR/lex-bad-numeric-literals.rs:9:5
|
LL | 0x8.0e+9;
| ^^^^^^^^
error: hexadecimal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:12:5
+ --> $DIR/lex-bad-numeric-literals.rs:10:5
|
LL | 0x9.0e-9;
| ^^^^^^^^
error: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:13:5
+ --> $DIR/lex-bad-numeric-literals.rs:11:5
|
LL | 0o;
| ^^
error: expected at least one digit in exponent
- --> $DIR/lex-bad-numeric-literals.rs:14:8
+ --> $DIR/lex-bad-numeric-literals.rs:12:8
|
LL | 1e+;
| ^
error: hexadecimal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:15:5
+ --> $DIR/lex-bad-numeric-literals.rs:13:5
|
LL | 0x539.0;
| ^^^^^^^
error: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:20:5
+ --> $DIR/lex-bad-numeric-literals.rs:18:5
|
LL | 0x;
| ^^
error: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:21:5
+ --> $DIR/lex-bad-numeric-literals.rs:19:5
|
LL | 0xu32;
| ^^
error: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:22:5
+ --> $DIR/lex-bad-numeric-literals.rs:20:5
|
LL | 0ou32;
| ^^
error: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:23:5
+ --> $DIR/lex-bad-numeric-literals.rs:21:5
|
LL | 0bu32;
| ^^
error: no valid digits found for number
- --> $DIR/lex-bad-numeric-literals.rs:24:5
+ --> $DIR/lex-bad-numeric-literals.rs:22:5
|
LL | 0b;
| ^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:26:5
+ --> $DIR/lex-bad-numeric-literals.rs:24:5
|
LL | 0o123.456;
| ^^^^^^^^^
error: binary float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:28:5
+ --> $DIR/lex-bad-numeric-literals.rs:26:5
|
LL | 0b111.101;
| ^^^^^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:5:5
+ --> $DIR/lex-bad-numeric-literals.rs:3:5
|
LL | 0o2f32;
| ^^^^^^ not supported
error: integer literal is too large
- --> $DIR/lex-bad-numeric-literals.rs:16:5
+ --> $DIR/lex-bad-numeric-literals.rs:14:5
|
LL | 9900000000000000000000000000999999999999999999999999999999;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: integer literal is too large
- --> $DIR/lex-bad-numeric-literals.rs:18:5
+ --> $DIR/lex-bad-numeric-literals.rs:16:5
|
LL | 9900000000000000000000000000999999999999999999999999999999;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: octal float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:25:5
+ --> $DIR/lex-bad-numeric-literals.rs:23:5
|
LL | 0o123f64;
| ^^^^^^^^ not supported
error: binary float literal is not supported
- --> $DIR/lex-bad-numeric-literals.rs:27:5
+ --> $DIR/lex-bad-numeric-literals.rs:25:5
|
LL | 0b101f64;
| ^^^^^^^^ not supported
-// compile-flags: -Z continue-parse-after-error
-
fn main() {
0o18; //~ ERROR invalid digit for a base 8 literal
0o1234_9_5670; //~ ERROR invalid digit for a base 8 literal
error: invalid digit for a base 8 literal
- --> $DIR/lex-bad-octal-literal.rs:4:8
+ --> $DIR/lex-bad-octal-literal.rs:2:8
|
LL | 0o18;
| ^
error: invalid digit for a base 8 literal
- --> $DIR/lex-bad-octal-literal.rs:5:12
+ --> $DIR/lex-bad-octal-literal.rs:3:12
|
LL | 0o1234_9_5670;
| ^
-// compile-flags: -Z continue-parse-after-error
-
macro_rules! ignored_item {
() => {
fn foo() {}
error: macro expansion ignores token `,` and any following
- --> $DIR/macro-incomplete-parse.rs:7:9
+ --> $DIR/macro-incomplete-parse.rs:5:9
|
LL | ,
| ^
= note: the usage of `ignored_item!` is likely invalid in item context
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
- --> $DIR/macro-incomplete-parse.rs:12:14
+ --> $DIR/macro-incomplete-parse.rs:10:14
|
LL | () => ( 1,
| ^ expected one of `.`, `;`, `?`, `}`, or an operator here
| ---------------- in this macro invocation
error: macro expansion ignores token `,` and any following
- --> $DIR/macro-incomplete-parse.rs:18:14
+ --> $DIR/macro-incomplete-parse.rs:16:14
|
LL | () => ( 1, 2 )
| ^
-// compile-flags: -Z continue-parse-after-error
-
pub fn main() {
let s = "\u{lol}";
//~^ ERROR invalid character in unicode escape: l
error: invalid character in unicode escape: l
- --> $DIR/new-unicode-escapes-4.rs:4:17
+ --> $DIR/new-unicode-escapes-4.rs:2:17
|
LL | let s = "\u{lol}";
| ^
-// compile-flags: -Z continue-parse-after-error
-
trait A {
fn foo(*mut self); //~ ERROR cannot pass `self` by raw pointer
fn baz(*const self); //~ ERROR cannot pass `self` by raw pointer
error: cannot pass `self` by raw pointer
- --> $DIR/no-unsafe-self.rs:4:17
+ --> $DIR/no-unsafe-self.rs:2:17
|
LL | fn foo(*mut self);
| ^^^^ cannot pass `self` by raw pointer
error: cannot pass `self` by raw pointer
- --> $DIR/no-unsafe-self.rs:5:19
+ --> $DIR/no-unsafe-self.rs:3:19
|
LL | fn baz(*const self);
| ^^^^ cannot pass `self` by raw pointer
error: cannot pass `self` by raw pointer
- --> $DIR/no-unsafe-self.rs:6:13
+ --> $DIR/no-unsafe-self.rs:4:13
|
LL | fn bar(*self);
| ^^^^ cannot pass `self` by raw pointer
error: cannot pass `self` by raw pointer
- --> $DIR/no-unsafe-self.rs:11:17
+ --> $DIR/no-unsafe-self.rs:9:17
|
LL | fn foo(*mut self) { }
| ^^^^ cannot pass `self` by raw pointer
error: cannot pass `self` by raw pointer
- --> $DIR/no-unsafe-self.rs:12:19
+ --> $DIR/no-unsafe-self.rs:10:19
|
LL | fn baz(*const self) { }
| ^^^^ cannot pass `self` by raw pointer
error: cannot pass `self` by raw pointer
- --> $DIR/no-unsafe-self.rs:13:13
+ --> $DIR/no-unsafe-self.rs:11:13
|
LL | fn bar(*self) { }
| ^^^^ cannot pass `self` by raw pointer
-// compile-flags: -Z continue-parse-after-error
-
// Make sure that inclusive ranges with `...` syntax don't parse.
use std::ops::RangeToInclusive;
error: unexpected token: `...`
- --> $DIR/range_inclusive_dotdotdot.rs:8:12
+ --> $DIR/range_inclusive_dotdotdot.rs:6:12
|
LL | return ...1;
| ^^^
| ^^^
error: unexpected token: `...`
- --> $DIR/range_inclusive_dotdotdot.rs:14:13
+ --> $DIR/range_inclusive_dotdotdot.rs:12:13
|
LL | let x = ...0;
| ^^^
| ^^^
error: unexpected token: `...`
- --> $DIR/range_inclusive_dotdotdot.rs:18:14
+ --> $DIR/range_inclusive_dotdotdot.rs:16:14
|
LL | let x = 5...5;
| ^^^
| ^^^
error: unexpected token: `...`
- --> $DIR/range_inclusive_dotdotdot.rs:22:15
+ --> $DIR/range_inclusive_dotdotdot.rs:20:15
|
LL | for _ in 0...1 {}
| ^^^
-// compile-flags: -Z continue-parse-after-error
-
-
pub fn main() {
br"é"; //~ ERROR raw byte string must be ASCII
br##~"a"~##; //~ ERROR only `#` is allowed in raw string delimitation
error: raw byte string must be ASCII: \u{e9}
- --> $DIR/raw-byte-string-literals.rs:5:8
+ --> $DIR/raw-byte-string-literals.rs:2:8
|
LL | br"é";
| ^
error: found invalid character; only `#` is allowed in raw string delimitation: ~
- --> $DIR/raw-byte-string-literals.rs:6:6
+ --> $DIR/raw-byte-string-literals.rs:3:6
|
LL | br##~"a"~##;
| ^^^
-// compile-flags: -Z continue-parse-after-error
-
fn main() {
enum Test {
Very
error: missing comma
- --> $DIR/recover-enum.rs:5:13
+ --> $DIR/recover-enum.rs:3:13
|
LL | Very
| ^ help: missing comma
error: missing comma
- --> $DIR/recover-enum.rs:7:19
+ --> $DIR/recover-enum.rs:5:19
|
LL | Bad(usize)
| ^ help: missing comma
error: missing comma
- --> $DIR/recover-enum.rs:9:27
+ --> $DIR/recover-enum.rs:7:27
|
LL | Stuff { a: usize }
| ^ help: missing comma
-// compile-flags: -Z continue-parse-after-error
-
fn main() {
enum Test {
Var1,
error: expected type, found `{`
- --> $DIR/recover-enum2.rs:8:18
+ --> $DIR/recover-enum2.rs:6:18
|
LL | abc: {},
| ^
error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{`
- --> $DIR/recover-enum2.rs:27:22
+ --> $DIR/recover-enum2.rs:25:22
|
LL | Nope(i32 {})
| ^ expected one of 7 possible tokens here
LL | let x = Enum::Foo(a: 3, b: 4);
| ^ expecting a type here because of type ascription
|
- = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+ = note: #![feature(type_ascription)] lets you annotate an expression with a type: `<expr>: <type>`
note: this expression expects an ascribed type after the colon
--> $DIR/recover-from-bad-variant.rs:7:23
|
-// compile-flags: -Z continue-parse-after-error
-
fn main() {
struct Test {
Very
error: expected `:`, found `Bad`
- --> $DIR/recover-struct.rs:6:9
+ --> $DIR/recover-struct.rs:4:9
|
LL | Very
| - expected `:`
-// compile-flags: -Z continue-parse-after-error
-
struct S {
let foo: (),
//~^ ERROR expected identifier, found keyword `let`
error: expected identifier, found keyword `let`
- --> $DIR/removed-syntax-field-let.rs:4:5
+ --> $DIR/removed-syntax-field-let.rs:2:5
|
LL | let foo: (),
| ^^^ expected identifier, found keyword
| ^^^^^
error: expected `:`, found `foo`
- --> $DIR/removed-syntax-field-let.rs:4:9
+ --> $DIR/removed-syntax-field-let.rs:2:9
|
LL | let foo: (),
| ^^^ expected `:`
// compile-pass
-// compile-flags: -Z continue-parse-after-error
#![feature(box_syntax)]
#![allow(bare_trait_objects)]
-// compile-flags: -Z continue-parse-after-error
-
-trait Foo {
-}
+trait Foo {}
struct Bar;
-impl Foo + Owned for Bar { //~ ERROR expected a trait, found type
-}
+impl Foo + Owned for Bar {} //~ ERROR expected a trait, found type
fn main() { }
error: expected a trait, found type
- --> $DIR/trait-bounds-not-on-impl.rs:8:6
+ --> $DIR/trait-bounds-not-on-impl.rs:5:6
|
-LL | impl Foo + Owned for Bar {
+LL | impl Foo + Owned for Bar {}
| ^^^^^^^^^^^
error: aborting due to previous error
-// compile-flags: -Z continue-parse-after-error
-
#![feature(optin_builtin_traits)]
#![allow(bare_trait_objects)]
error[E0178]: expected a path on the left-hand side of `+`, not `((Auto))`
- --> $DIR/trait-object-bad-parens.rs:9:16
+ --> $DIR/trait-object-bad-parens.rs:7:16
|
LL | let _: Box<((Auto)) + Auto>;
| ^^^^^^^^^^^^^^^ expected a path
error[E0178]: expected a path on the left-hand side of `+`, not `(Auto + Auto)`
- --> $DIR/trait-object-bad-parens.rs:11:16
+ --> $DIR/trait-object-bad-parens.rs:9:16
|
LL | let _: Box<(Auto + Auto) + Auto>;
| ^^^^^^^^^^^^^^^^^^^^ expected a path
error[E0178]: expected a path on the left-hand side of `+`, not `(Auto)`
- --> $DIR/trait-object-bad-parens.rs:13:16
+ --> $DIR/trait-object-bad-parens.rs:11:16
|
LL | let _: Box<(Auto +) + Auto>;
| ^^^^^^^^^^^^^^^ expected a path
error[E0178]: expected a path on the left-hand side of `+`, not `(dyn Auto)`
- --> $DIR/trait-object-bad-parens.rs:15:16
+ --> $DIR/trait-object-bad-parens.rs:13:16
|
LL | let _: Box<(dyn Auto) + Auto>;
| ^^^^^^^^^^^^^^^^^ expected a path
-// compile-flags: -Z continue-parse-after-error
-
#![allow(bare_trait_objects)]
trait Trait {}
error: parenthesized lifetime bounds are not supported
- --> $DIR/trait-object-lifetime-parens.rs:7:21
+ --> $DIR/trait-object-lifetime-parens.rs:5:21
|
LL | fn f<'a, T: Trait + ('a)>() {}
| ^^^^ help: remove the parentheses
error: parenthesized lifetime bounds are not supported
- --> $DIR/trait-object-lifetime-parens.rs:10:24
+ --> $DIR/trait-object-lifetime-parens.rs:8:24
|
LL | let _: Box<Trait + ('a)>;
| ^^^^ help: remove the parentheses
error: expected `:`, found `)`
- --> $DIR/trait-object-lifetime-parens.rs:11:19
+ --> $DIR/trait-object-lifetime-parens.rs:9:19
|
LL | let _: Box<('a) + Trait>;
| ^ expected `:`
error: chained comparison operators require parentheses
- --> $DIR/trait-object-lifetime-parens.rs:11:15
+ --> $DIR/trait-object-lifetime-parens.rs:9:15
|
LL | let _: Box<('a) + Trait>;
| ^^^^^^^^^^^^^^^
= help: or use `(...)` if you meant to specify fn arguments
error: expected type, found `'a`
- --> $DIR/trait-object-lifetime-parens.rs:11:17
+ --> $DIR/trait-object-lifetime-parens.rs:9:17
|
LL | let _: Box<('a) + Trait>;
| - ^^
-// compile-flags: -Z continue-parse-after-error
-
use std::any:: as foo; //~ ERROR expected identifier, found keyword `as`
//~^ ERROR: expected one of `::`, `;`, or `as`, found `foo`
error: expected identifier, found keyword `as`
- --> $DIR/use-as-where-use-ends-with-mod-sep.rs:3:16
+ --> $DIR/use-as-where-use-ends-with-mod-sep.rs:1:16
|
LL | use std::any:: as foo;
| ^^ expected identifier, found keyword
| ^^^^
error: expected one of `::`, `;`, or `as`, found `foo`
- --> $DIR/use-as-where-use-ends-with-mod-sep.rs:3:19
+ --> $DIR/use-as-where-use-ends-with-mod-sep.rs:1:19
|
LL | use std::any:: as foo;
| ^^^ expected one of `::`, `;`, or `as` here
-// compile-flags: -Z continue-parse-after-error
-
// Empty predicate list is OK
fn equal1<T>(_: &T, _: &T) -> bool where {
true
error: expected `:`, found `{`
- --> $DIR/where-clauses-no-bounds-or-predicates.rs:13:23
+ --> $DIR/where-clauses-no-bounds-or-predicates.rs:11:23
|
LL | fn foo<'a>() where 'a {}
| ^ expected `:`
-// compile-flags: -Z continue-parse-after-error
-
mod foo {
struct Self;
//~^ ERROR expected identifier, found keyword `Self`
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:4:10
+ --> $DIR/self_type_keyword.rs:2:10
|
LL | struct Self;
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:16:13
+ --> $DIR/self_type_keyword.rs:14:13
|
LL | ref Self => (),
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:18:13
+ --> $DIR/self_type_keyword.rs:16:13
|
LL | mut Self => (),
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:20:17
+ --> $DIR/self_type_keyword.rs:18:17
|
LL | ref mut Self => (),
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:24:15
+ --> $DIR/self_type_keyword.rs:22:15
|
LL | Foo { Self } => (),
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:30:26
+ --> $DIR/self_type_keyword.rs:28:26
|
LL | extern crate core as Self;
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:35:32
+ --> $DIR/self_type_keyword.rs:33:32
|
LL | use std::option::Option as Self;
| ^^^^ expected identifier, found keyword
error: expected identifier, found keyword `Self`
- --> $DIR/self_type_keyword.rs:40:11
+ --> $DIR/self_type_keyword.rs:38:11
|
LL | trait Self {}
| ^^^^ expected identifier, found keyword
error: lifetimes cannot use keyword names
- --> $DIR/self_type_keyword.rs:8:12
+ --> $DIR/self_type_keyword.rs:6:12
|
LL | struct Bar<'Self>;
| ^^^^^
error: cannot find macro `Self!` in this scope
- --> $DIR/self_type_keyword.rs:22:9
+ --> $DIR/self_type_keyword.rs:20:9
|
LL | Self!() => (),
| ^^^^
error[E0392]: parameter `'Self` is never used
- --> $DIR/self_type_keyword.rs:8:12
+ --> $DIR/self_type_keyword.rs:6:12
|
LL | struct Bar<'Self>;
| ^^^^^ unused parameter
-error: symbol-name(_ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo17h059a991a004536adE)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h059a991a004536adE)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling(issue_60925::foo::Foo<issue_60925::llv$6d$..Foo$GT$::foo::h059a991a004536ad)
+error: demangling(issue_60925::foo::Foo<issue_60925::llv$u6d$..Foo$GT$::foo::h059a991a004536ad)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: demangling-alt(issue_60925::foo::Foo<issue_60925::llv$6d$..Foo$GT$::foo)
+error: demangling-alt(issue_60925::foo::Foo<issue_60925::llv$u6d$..Foo$GT$::foo)
--> $DIR/issue-60925.rs:21:9
|
LL | #[rustc_symbol_name]
impl Foo<::llvm::Foo> {
#[rustc_symbol_name]
- //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo
- //[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llv$6d$..Foo$GT$::foo
- //[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo<issue_60925::llv$6d$..Foo$GT$::foo)
+ //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo
+ //[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llv$u6d$..Foo$GT$::foo
+ //[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo<issue_60925::llv$u6d$..Foo$GT$::foo)
//[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
//[v0]~| ERROR demangling(<issue_60925[317d481089b8c8fe]::foo::Foo<issue_60925[317d481089b8c8fe]::llvm::Foo>>::foo)
//[v0]~| ERROR demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo)
// A few contrived examples where lifetime should (or should not) be parsed as an object type.
// Lifetimes parsed as types are still rejected later by semantic checks.
-// compile-flags: -Z continue-parse-after-error
-
// `'static` is a lifetime, `'static +` is a type, `'a` is a type
fn g() where
'static: 'static,
error[E0224]: at least one non-builtin trait is required for an object type
- --> $DIR/trait-object-vs-lifetime-2.rs:9:5
+ --> $DIR/trait-object-vs-lifetime-2.rs:7:5
|
LL | dyn 'static +: 'static + Copy,
| ^^^^^^^^^^^^^
LL | println!("test"): 0;
| ^ expecting a type here because of type ascription
|
- = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+ = note: #![feature(type_ascription)] lets you annotate an expression with a type: `<expr>: <type>`
note: this expression expects an ascribed type after the colon
--> $DIR/type-ascription-instead-of-statement-end.rs:9:5
|
-Subproject commit d2f51228152a139a2a8aaba59b8a4e68f498ff26
+Subproject commit f3087c37bf5d8491b72ce007b65a47c2d3c2e733
-Subproject commit 0c85dbf3df0f545133dca24eccfc9f0f6107c7f8
+Subproject commit e1a0f66373a1a185334a6e3be24e94161e3b4a43
Crate("fuchsia-zircon-sys"),
Crate("getopts"),
Crate("humantime"),
+ Crate("indexmap"),
Crate("itertools"),
Crate("jobserver"),
Crate("kernel32-sys"),