# 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
# bucket.
- bash: |
set -e
+ source src/ci/shared.sh
if [ "$AGENT_OS" = "Linux" ]; then
rm -rf obj/build/dist/doc
upload_dir=obj/build/dist
if [ "$DEPLOY_ALT" == "1" ]; then
deploy_dir=rustc-builds-alt
fi
- aws s3 cp --no-progress --recursive --acl public-read ./$upload_dir s3://$DEPLOY_BUCKET/$deploy_dir/$BUILD_SOURCEVERSION
+ retry aws s3 cp --no-progress --recursive --acl public-read ./$upload_dir s3://$DEPLOY_BUCKET/$deploy_dir/$BUILD_SOURCEVERSION
env:
AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY)
condition: and(succeeded(), or(eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1')))
[[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)",
"rustc_errors 0.0.0",
"rustc_fs_util 0.0.0",
"rustc_incremental 0.0.0",
- "rustc_mir 0.0.0",
"rustc_target 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_data_structures 0.0.0",
"rustc_metadata 0.0.0",
- "rustc_mir 0.0.0",
"rustc_target 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
"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"
use std::cmp;
use build_helper::t;
-use num_cpus;
use toml;
use serde::Deserialize;
use crate::cache::{INTERNER, Interned};
config.rustc_error_format = flags.rustc_error_format;
config.on_fail = flags.on_fail;
config.stage = flags.stage;
- config.jobs = flags.jobs;
+ config.jobs = flags.jobs.map(threads_from_config);
config.cmd = flags.cmd;
config.incremental = flags.incremental;
config.dry_run = flags.dry_run;
set(&mut config.rust_codegen_backends_dir, rust.codegen_backends_dir.clone());
- match rust.codegen_units {
- Some(0) => config.rust_codegen_units = Some(num_cpus::get() as u32),
- Some(n) => config.rust_codegen_units = Some(n),
- None => {}
- }
-
- config.rust_codegen_units_std = rust.codegen_units_std;
+ config.rust_codegen_units = rust.codegen_units.map(threads_from_config);
+ config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
}
if let Some(ref t) = toml.target {
*field = v;
}
}
+
+fn threads_from_config(v: u32) -> u32 {
+ match v {
+ 0 => num_cpus::get() as u32,
+ n => n,
+ }
+}
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
function getCIBranch {
if [ "$TRAVIS" = "true" ]; then
echo "$TRAVIS_BRANCH"
+ elif [ "$APPVEYOR" = "True" ]; then
+ echo "$APPVEYOR_REPO_BRANCH"
else
echo "$BUILD_SOURCEBRANCHNAME"
fi;
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
impl<T: Clone> Rc<T> {
/// Makes a mutable reference into the given `Rc`.
///
- /// If there are other `Rc` or [`Weak`][weak] pointers to the same value,
- /// then `make_mut` will invoke [`clone`][clone] on the inner value to
- /// ensure unique ownership. This is also referred to as clone-on-write.
+ /// If there are other `Rc` pointers to the same value, then `make_mut` will
+ /// [`clone`] the inner value to ensure unique ownership. This is also
+ /// referred to as clone-on-write.
///
- /// See also [`get_mut`][get_mut], which will fail rather than cloning.
+ /// If there are no other `Rc` pointers to this value, then [`Weak`]
+ /// pointers to this value will be dissassociated.
///
- /// [weak]: struct.Weak.html
- /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
- /// [get_mut]: struct.Rc.html#method.get_mut
+ /// See also [`get_mut`], which will fail rather than cloning.
+ ///
+ /// [`Weak`]: struct.Weak.html
+ /// [`clone`]: ../../std/clone/trait.Clone.html#tymethod.clone
+ /// [`get_mut`]: struct.Rc.html#method.get_mut
///
/// # Examples
///
/// assert_eq!(*data, 8);
/// assert_eq!(*other_data, 12);
/// ```
+ ///
+ /// [`Weak`] pointers will be dissassociated:
+ ///
+ /// ```
+ /// use std::rc::Rc;
+ ///
+ /// let mut data = Rc::new(75);
+ /// let weak = Rc::downgrade(&data);
+ ///
+ /// assert!(75 == *data);
+ /// assert!(75 == *weak.upgrade().unwrap());
+ ///
+ /// *Rc::make_mut(&mut data) += 1;
+ ///
+ /// assert!(76 == *data);
+ /// assert!(weak.upgrade().is_none());
+ /// ```
#[inline]
#[stable(feature = "rc_unique", since = "1.4.0")]
pub fn make_mut(this: &mut Self) -> &mut T {
///
/// assert_eq!(new_year, new_year.to_uppercase());
/// ```
+ ///
+ /// One character can become multiple:
+ /// ```
+ /// let s = "tschüß";
+ ///
+ /// assert_eq!("TSCHÃœSS", s.to_uppercase());
+ /// ```
#[stable(feature = "unicode_case_mapping", since = "1.2.0")]
pub fn to_uppercase(&self) -> String {
let mut s = String::with_capacity(self.len());
/// with the given `replace_with` iterator and yields the removed items.
/// `replace_with` does not need to be the same length as `range`.
///
- /// Note 1: The element range is removed even if the iterator is not
- /// consumed until the end.
+ /// The element range is removed even if the iterator is not consumed until the end.
///
- /// Note 2: It is unspecified how many elements are removed from the vector,
+ /// It is unspecified how many elements are removed from the vector
/// if the `Splice` value is leaked.
///
- /// Note 3: The input iterator `replace_with` is only consumed
- /// when the `Splice` value is dropped.
+ /// The input iterator `replace_with` is only consumed when the `Splice` value is dropped.
///
- /// Note 4: This is optimal if:
+ /// This is optimal if:
///
/// * The tail (elements in the vector after `range`) is empty,
/// * or `replace_with` yields fewer elements than `range`’s length
/// # 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:
///
/// ```
/// y < 0 or y >= N, where N is the width of T in bits.
pub fn unchecked_shr<T>(x: T, y: T) -> T;
+ /// Returns the result of an unchecked addition, resulting in
+ /// undefined behavior when `x + y > T::max_value()` or `x + y < T::min_value()`.
+ #[cfg(not(stage0))]
+ pub fn unchecked_add<T>(x: T, y: T) -> T;
+
+ /// Returns the result of an unchecked substraction, resulting in
+ /// undefined behavior when `x - y > T::max_value()` or `x - y < T::min_value()`.
+ #[cfg(not(stage0))]
+ pub fn unchecked_sub<T>(x: T, y: T) -> T;
+
+ /// Returns the result of an unchecked multiplication, resulting in
+ /// undefined behavior when `x * y > T::max_value()` or `x * y < T::min_value()`.
+ #[cfg(not(stage0))]
+ pub fn unchecked_mul<T>(x: T, y: T) -> T;
+
/// Performs rotate left.
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `rotate_left` method. For example,
/// 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);
)
}
//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.
+use crate::mir;
use crate::mir::interpret::GlobalId;
use crate::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
use crate::hir::map::DefPathHash;
// 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),
fn visit_pat(&mut self, p: &'v Pat) {
walk_pat(self, p)
}
- fn visit_argument_source(&mut self, s: &'v ArgSource) {
- walk_argument_source(self, s)
- }
fn visit_anon_const(&mut self, c: &'v AnonConst) {
walk_anon_const(self, c)
}
for argument in &body.arguments {
visitor.visit_id(argument.hir_id);
visitor.visit_pat(&argument.pat);
- visitor.visit_argument_source(&argument.source);
}
visitor.visit_expr(&body.value);
}
-pub fn walk_argument_source<'v, V: Visitor<'v>>(visitor: &mut V, source: &'v ArgSource) {
- if let ArgSource::AsyncFn(pat) = source {
- visitor.visit_pat(pat);
- }
-}
-
pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
// Intentionally visiting the expr first - the initialization expr
// dominates the local's definition.
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::thin_vec::ThinVec;
+use rustc_data_structures::sync::Lrc;
use std::collections::{BTreeSet, BTreeMap};
use std::mem;
use syntax::ast;
use syntax::ast::*;
use syntax::errors;
-use syntax::ext::hygiene::Mark;
+use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::print::pprust;
use syntax::ptr::P;
-use syntax::source_map::{respan, CompilerDesugaringKind, Spanned};
+use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned};
use syntax::source_map::CompilerDesugaringKind::IfTemporary;
use syntax::std_inject;
use syntax::symbol::{kw, sym, Symbol};
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::parse::token::Token;
use syntax::visit::{self, Visitor};
-use syntax_pos::Span;
+use syntax_pos::{edition, Span};
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
visit::walk_pat(self, p)
}
- fn visit_fn(&mut self, fk: visit::FnKind<'lcx>, fd: &'lcx FnDecl, s: Span, _: NodeId) {
- if fk.header().map(|h| h.asyncness.node.is_async()).unwrap_or(false) {
- // Don't visit the original pattern for async functions as it will be
- // replaced.
- for arg in &fd.inputs {
- if let ArgSource::AsyncFn(pat) = &arg.source { self.visit_pat(pat); }
- self.visit_ty(&arg.ty)
- }
- self.visit_fn_ret_ty(&fd.output);
-
- match fk {
- visit::FnKind::ItemFn(_, decl, _, body) => {
- self.visit_fn_header(decl);
- self.visit_block(body)
- },
- visit::FnKind::Method(_, sig, _, body) => {
- self.visit_fn_header(&sig.header);
- self.visit_block(body)
- },
- visit::FnKind::Closure(body) => self.visit_expr(body),
- }
- } else {
- visit::walk_fn(self, fk, fd, s)
- }
- }
-
fn visit_item(&mut self, item: &'lcx Item) {
let hir_id = self.lctx.allocate_hir_id_counter(item.id);
})
}
- fn record_body(&mut self, value: hir::Expr, arguments: HirVec<hir::Arg>) -> hir::BodyId {
+ fn record_body(&mut self, arguments: HirVec<hir::Arg>, value: hir::Expr) -> hir::BodyId {
if self.is_generator && self.is_async_body {
span_err!(
self.sess,
self.sess.diagnostic()
}
+ /// Reuses the span but adds information like the kind of the desugaring and features that are
+ /// allowed inside this span.
+ fn mark_span_with_reason(
+ &self,
+ reason: CompilerDesugaringKind,
+ span: Span,
+ allow_internal_unstable: Option<Lrc<[Symbol]>>,
+ ) -> Span {
+ let mark = Mark::fresh(Mark::root());
+ mark.set_expn_info(source_map::ExpnInfo {
+ call_site: span,
+ def_site: Some(span),
+ format: source_map::CompilerDesugaring(reason),
+ allow_internal_unstable,
+ allow_internal_unsafe: false,
+ local_inner_macros: false,
+ edition: edition::Edition::from_session(),
+ });
+ span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
+ }
+
fn with_anonymous_lifetime_mode<R>(
&mut self,
anonymous_lifetime_mode: AnonymousLifetimeMode,
span: Span,
body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
) -> hir::ExprKind {
- let prev_is_generator = mem::replace(&mut self.is_generator, false);
- let prev_is_async_body = mem::replace(&mut self.is_async_body, true);
+ let capture_clause = self.lower_capture_clause(capture_clause);
let output = match ret_ty {
Some(ty) => FunctionRetTy::Ty(P(ty.clone())),
None => FunctionRetTy::Default(span),
};
- let decl = FnDecl {
+ let ast_decl = FnDecl {
inputs: vec![],
output,
c_variadic: false
};
- // Lower the arguments before the body otherwise the body will call `lower_res` expecting
- // the argument to have been assigned an id already.
- let arguments = self.lower_args(Some(&decl));
- let body_expr = body(self);
- let body_id = self.record_body(body_expr, arguments);
- self.is_generator = prev_is_generator;
- self.is_async_body = prev_is_async_body;
-
- let capture_clause = self.lower_capture_clause(capture_clause);
- let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, None);
+ let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None);
+ let body_id = self.lower_fn_body(&ast_decl, |this| {
+ this.is_async_body = true;
+ body(this)
+ });
let generator = hir::Expr {
hir_id: self.lower_node_id(closure_node_id),
node: hir::ExprKind::Closure(capture_clause, decl, body_id, span,
attrs: ThinVec::new(),
};
- let unstable_span = self.sess.source_map().mark_span_with_reason(
+ let unstable_span = self.mark_span_with_reason(
CompilerDesugaringKind::Async,
span,
Some(vec![sym::gen_future].into()),
hir::ExprKind::Call(P(gen_future), hir_vec![generator])
}
- fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
- where
- F: FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
- {
- let prev_generator = mem::replace(&mut self.is_generator, false);
- let prev_async = mem::replace(&mut self.is_async_body, false);
- let arguments = self.lower_args(decl);
- let result = f(self);
- let r = self.record_body(result, arguments);
- self.is_generator = prev_generator;
- self.is_async_body = prev_async;
- return r;
+ fn lower_body(
+ &mut self,
+ f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec<hir::Arg>, hir::Expr),
+ ) -> hir::BodyId {
+ let prev_is_generator = mem::replace(&mut self.is_generator, false);
+ let prev_is_async_body = mem::replace(&mut self.is_async_body, false);
+ let (arguments, result) = f(self);
+ let body_id = self.record_body(arguments, result);
+ self.is_generator = prev_is_generator;
+ self.is_async_body = prev_is_async_body;
+ body_id
+ }
+
+ fn lower_fn_body(
+ &mut self,
+ decl: &FnDecl,
+ body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
+ ) -> hir::BodyId {
+ self.lower_body(|this| (
+ decl.inputs.iter().map(|x| this.lower_arg(x)).collect(),
+ body(this),
+ ))
+ }
+
+ fn lower_const_body(&mut self, expr: &Expr) -> hir::BodyId {
+ self.lower_body(|this| (hir_vec![], this.lower_expr(expr)))
}
fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T
// desugaring that explicitly states that we don't want to track that.
// Not tracking it makes lints in rustc and clippy very fragile as
// frequently opened issues show.
- let exist_ty_span = self.sess.source_map().mark_span_with_reason(
+ let exist_ty_span = self.mark_span_with_reason(
CompilerDesugaringKind::ExistentialReturnType,
span,
None,
init: l.init.as_ref().map(|e| P(self.lower_expr(e))),
span: l.span,
attrs: l.attrs.clone(),
- source: self.lower_local_source(l.source),
+ source: hir::LocalSource::Normal,
}, ids)
}
- fn lower_local_source(&mut self, ls: LocalSource) -> hir::LocalSource {
- match ls {
- LocalSource::Normal => hir::LocalSource::Normal,
- LocalSource::AsyncFn => hir::LocalSource::AsyncFn,
- }
- }
-
fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability {
match m {
Mutability::Mutable => hir::MutMutable,
}
}
- fn lower_args(&mut self, decl: Option<&FnDecl>) -> HirVec<hir::Arg> {
- decl.map_or(hir_vec![], |decl| decl.inputs.iter().map(|x| self.lower_arg(x)).collect())
- }
-
fn lower_arg(&mut self, arg: &Arg) -> hir::Arg {
hir::Arg {
hir_id: self.lower_node_id(arg.id),
pat: self.lower_pat(&arg.pat),
- source: self.lower_arg_source(&arg.source),
- }
- }
-
- fn lower_arg_source(&mut self, source: &ArgSource) -> hir::ArgSource {
- match source {
- ArgSource::Normal => hir::ArgSource::Normal,
- ArgSource::AsyncFn(pat) => hir::ArgSource::AsyncFn(self.lower_pat(pat)),
}
}
) -> hir::FunctionRetTy {
let span = output.span();
- let exist_ty_span = self.sess.source_map().mark_span_with_reason(
+ let exist_ty_span = self.mark_span_with_reason(
CompilerDesugaringKind::Async,
span,
None,
bounds.iter().map(|bound| self.lower_param_bound(bound, itctx.reborrow())).collect()
}
- fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
+ fn lower_block_with_stmts(
+ &mut self,
+ b: &Block,
+ targeted_by_break: bool,
+ mut stmts: Vec<hir::Stmt>,
+ ) -> P<hir::Block> {
let mut expr = None;
- let mut stmts = vec![];
-
for (index, stmt) in b.stmts.iter().enumerate() {
if index == b.stmts.len() - 1 {
if let StmtKind::Expr(ref e) = stmt.node {
})
}
- fn lower_async_body(
+ fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
+ self.lower_block_with_stmts(b, targeted_by_break, vec![])
+ }
+
+ fn lower_maybe_async_body(
&mut self,
decl: &FnDecl,
- asyncness: &IsAsync,
+ asyncness: IsAsync,
body: &Block,
) -> hir::BodyId {
- self.lower_body(Some(&decl), |this| {
- if let IsAsync::Async { closure_id, ref arguments, .. } = asyncness {
- let mut body = body.clone();
+ let closure_id = match asyncness {
+ IsAsync::Async { closure_id, .. } => closure_id,
+ IsAsync::NotAsync => return self.lower_fn_body(&decl, |this| {
+ let body = this.lower_block(body, false);
+ this.expr_block(body, ThinVec::new())
+ }),
+ };
- // Async function arguments are lowered into the closure body so that they are
- // captured and so that the drop order matches the equivalent non-async functions.
- //
- // async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
- // async move {
- // }
- // }
- //
- // // ...becomes...
- // fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
- // async move {
- // let __arg2 = __arg2;
- // let <pattern> = __arg2;
- // let __arg1 = __arg1;
- // let <pattern> = __arg1;
- // let __arg0 = __arg0;
- // let <pattern> = __arg0;
- // }
- // }
+ self.lower_body(|this| {
+ let mut arguments: Vec<hir::Arg> = Vec::new();
+ let mut statements: Vec<hir::Stmt> = Vec::new();
+
+ // Async function arguments are lowered into the closure body so that they are
+ // captured and so that the drop order matches the equivalent non-async functions.
+ //
+ // from:
+ //
+ // async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
+ // async move {
+ // }
+ // }
+ //
+ // into:
+ //
+ // fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
+ // async move {
+ // let __arg2 = __arg2;
+ // let <pattern> = __arg2;
+ // let __arg1 = __arg1;
+ // let <pattern> = __arg1;
+ // let __arg0 = __arg0;
+ // let <pattern> = __arg0;
+ // }
+ // }
+ //
+ // If `<pattern>` is a simple ident, then it is lowered to a single
+ // `let <pattern> = <pattern>;` statement as an optimization.
+ for (index, argument) in decl.inputs.iter().enumerate() {
+ let argument = this.lower_arg(argument);
+ let span = argument.pat.span;
+
+ // Check if this is a binding pattern, if so, we can optimize and avoid adding a
+ // `let <pat> = __argN;` statement. In this case, we do not rename the argument.
+ let (ident, is_simple_argument) = match argument.pat.node {
+ hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, _) =>
+ (ident, true),
+ _ => {
+ // Replace the ident for bindings that aren't simple.
+ let name = format!("__arg{}", index);
+ let ident = Ident::from_str(&name);
+
+ (ident, false)
+ },
+ };
+
+ let desugared_span =
+ this.mark_span_with_reason(CompilerDesugaringKind::Async, span, None);
+
+ // Construct an argument representing `__argN: <ty>` to replace the argument of the
+ // async function.
//
- // If `<pattern>` is a simple ident, then it is lowered to a single
- // `let <pattern> = <pattern>;` statement as an optimization.
- for a in arguments.iter().rev() {
- if let Some(pat_stmt) = a.pat_stmt.clone() {
- body.stmts.insert(0, pat_stmt);
- }
- body.stmts.insert(0, a.move_stmt.clone());
- }
+ // If this is the simple case, this argument will end up being the same as the
+ // original argument, but with a different pattern id.
+ let (new_argument_pat, new_argument_id) = this.pat_ident(desugared_span, ident);
+ let new_argument = hir::Arg {
+ hir_id: argument.hir_id,
+ pat: new_argument_pat,
+ };
- let async_expr = this.make_async_expr(
- CaptureBy::Value, *closure_id, None, body.span,
- |this| {
- let body = this.lower_block(&body, false);
- this.expr_block(body, ThinVec::new())
- });
- this.expr(body.span, async_expr, ThinVec::new())
- } else {
- let body = this.lower_block(body, false);
- this.expr_block(body, ThinVec::new())
+ if is_simple_argument {
+ // If this is the simple case, then we only insert one statement that is
+ // `let <pat> = <pat>;`. We re-use the original argument's pattern so that
+ // `HirId`s are densely assigned.
+ let expr = this.expr_ident(desugared_span, ident, new_argument_id);
+ let stmt = this.stmt_let_pat(
+ desugared_span, Some(P(expr)), argument.pat, hir::LocalSource::AsyncFn);
+ statements.push(stmt);
+ } else {
+ // If this is not the simple case, then we construct two statements:
+ //
+ // ```
+ // let __argN = __argN;
+ // let <pat> = __argN;
+ // ```
+ //
+ // The first statement moves the argument into the closure and thus ensures
+ // that the drop order is correct.
+ //
+ // The second statement creates the bindings that the user wrote.
+
+ // Construct the `let mut __argN = __argN;` statement. It must be a mut binding
+ // because the user may have specified a `ref mut` binding in the next
+ // statement.
+ let (move_pat, move_id) = this.pat_ident_binding_mode(
+ desugared_span, ident, hir::BindingAnnotation::Mutable);
+ let move_expr = this.expr_ident(desugared_span, ident, new_argument_id);
+ let move_stmt = this.stmt_let_pat(
+ desugared_span, Some(P(move_expr)), move_pat, hir::LocalSource::AsyncFn);
+
+ // Construct the `let <pat> = __argN;` statement. We re-use the original
+ // argument's pattern so that `HirId`s are densely assigned.
+ let pattern_expr = this.expr_ident(desugared_span, ident, move_id);
+ let pattern_stmt = this.stmt_let_pat(
+ desugared_span, Some(P(pattern_expr)), argument.pat,
+ hir::LocalSource::AsyncFn);
+
+ statements.push(move_stmt);
+ statements.push(pattern_stmt);
+ };
+
+ arguments.push(new_argument);
}
+
+ let async_expr = this.make_async_expr(
+ CaptureBy::Value, closure_id, None, body.span,
+ |this| {
+ let body = this.lower_block_with_stmts(body, false, statements);
+ this.expr_block(body, ThinVec::new())
+ });
+ (HirVec::from(arguments), this.expr(body.span, async_expr, ThinVec::new()))
})
}
self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs)
}
ItemKind::Static(ref t, m, ref e) => {
- let value = self.lower_body(None, |this| this.lower_expr(e));
hir::ItemKind::Static(
self.lower_ty(
t,
}
),
self.lower_mutability(m),
- value,
+ self.lower_const_body(e),
)
}
ItemKind::Const(ref t, ref e) => {
- let value = self.lower_body(None, |this| this.lower_expr(e));
hir::ItemKind::Const(
self.lower_ty(
t,
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
}
),
- value
+ self.lower_const_body(e)
)
}
- ItemKind::Fn(ref decl, ref header, ref generics, ref body) => {
+ ItemKind::Fn(ref decl, header, ref generics, ref body) => {
let fn_def_id = self.resolver.definitions().local_def_id(id);
self.with_new_scopes(|this| {
this.current_item = Some(ident.span);
- let mut lower_fn = |decl: &FnDecl| {
- // Note: we don't need to change the return type from `T` to
- // `impl Future<Output = T>` here because lower_body
- // only cares about the input argument patterns in the function
- // declaration (decl), not the return types.
- let body_id = this.lower_async_body(&decl, &header.asyncness.node, body);
-
- let (generics, fn_decl) = this.add_in_band_defs(
- generics,
- fn_def_id,
- AnonymousLifetimeMode::PassThrough,
- |this, idty| this.lower_fn_decl(
- &decl,
- Some((fn_def_id, idty)),
- true,
- header.asyncness.node.opt_return_id()
- ),
- );
- (body_id, generics, fn_decl)
- };
+ // Note: we don't need to change the return type from `T` to
+ // `impl Future<Output = T>` here because lower_body
+ // only cares about the input argument patterns in the function
+ // declaration (decl), not the return types.
+ let body_id = this.lower_maybe_async_body(&decl, header.asyncness.node, body);
- let (body_id, generics, fn_decl) = if let IsAsync::Async {
- arguments, ..
- } = &header.asyncness.node {
- let mut decl = decl.clone();
- // Replace the arguments of this async function with the generated
- // arguments that will be moved into the closure.
- for (i, a) in arguments.clone().drain(..).enumerate() {
- if let Some(arg) = a.arg {
- decl.inputs[i] = arg;
- }
- }
- lower_fn(&decl)
- } else {
- lower_fn(decl)
- };
+ let (generics, fn_decl) = this.add_in_band_defs(
+ generics,
+ fn_def_id,
+ AnonymousLifetimeMode::PassThrough,
+ |this, idty| this.lower_fn_decl(
+ &decl,
+ Some((fn_def_id, idty)),
+ true,
+ header.asyncness.node.opt_return_id()
+ ),
+ );
hir::ItemKind::Fn(
fn_decl,
self.lower_ty(ty, ImplTraitContext::disallowed()),
default
.as_ref()
- .map(|x| self.lower_body(None, |this| this.lower_expr(x))),
+ .map(|x| self.lower_const_body(x)),
),
),
TraitItemKind::Method(ref sig, None) => {
(generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names)))
}
TraitItemKind::Method(ref sig, Some(ref body)) => {
- let body_id = self.lower_body(Some(&sig.decl), |this| {
+ let body_id = self.lower_fn_body(&sig.decl, |this| {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
});
let impl_item_def_id = self.resolver.definitions().local_def_id(i.id);
let (generics, node) = match i.node {
- ImplItemKind::Const(ref ty, ref expr) => {
- let body_id = self.lower_body(None, |this| this.lower_expr(expr));
- (
- self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
- hir::ImplItemKind::Const(
- self.lower_ty(ty, ImplTraitContext::disallowed()),
- body_id,
- ),
- )
- }
+ ImplItemKind::Const(ref ty, ref expr) => (
+ self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
+ hir::ImplItemKind::Const(
+ self.lower_ty(ty, ImplTraitContext::disallowed()),
+ self.lower_const_body(expr),
+ ),
+ ),
ImplItemKind::Method(ref sig, ref body) => {
- let mut lower_method = |sig: &MethodSig| {
- let body_id = self.lower_async_body(
- &sig.decl, &sig.header.asyncness.node, body
- );
- let impl_trait_return_allow = !self.is_in_trait_impl;
- let (generics, sig) = self.lower_method_sig(
- &i.generics,
- sig,
- impl_item_def_id,
- impl_trait_return_allow,
- sig.header.asyncness.node.opt_return_id(),
- );
- (body_id, generics, sig)
- };
-
- let (body_id, generics, sig) = if let IsAsync::Async {
- ref arguments, ..
- } = sig.header.asyncness.node {
- let mut sig = sig.clone();
- // Replace the arguments of this async function with the generated
- // arguments that will be moved into the closure.
- for (i, a) in arguments.clone().drain(..).enumerate() {
- if let Some(arg) = a.arg {
- sig.decl.inputs[i] = arg;
- }
- }
- lower_method(&sig)
- } else {
- lower_method(sig)
- };
self.current_item = Some(i.span);
+ let body_id = self.lower_maybe_async_body(
+ &sig.decl, sig.header.asyncness.node, body
+ );
+ let impl_trait_return_allow = !self.is_in_trait_impl;
+ let (generics, sig) = self.lower_method_sig(
+ &i.generics,
+ sig,
+ impl_item_def_id,
+ impl_trait_return_allow,
+ sig.header.asyncness.node.opt_return_id(),
+ );
(generics, hir::ImplItemKind::Method(sig, body_id))
}
impl_trait_return_allow: bool,
is_async: Option<NodeId>,
) -> (hir::Generics, hir::MethodSig) {
- let header = self.lower_fn_header(&sig.header);
+ let header = self.lower_fn_header(sig.header);
let (generics, decl) = self.add_in_band_defs(
generics,
fn_def_id,
}
}
- fn lower_fn_header(&mut self, h: &FnHeader) -> hir::FnHeader {
+ fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
hir::FnHeader {
unsafety: self.lower_unsafety(h.unsafety),
- asyncness: self.lower_asyncness(&h.asyncness.node),
+ asyncness: self.lower_asyncness(h.asyncness.node),
constness: self.lower_constness(h.constness),
abi: h.abi,
}
}
}
- fn lower_asyncness(&mut self, a: &IsAsync) -> hir::IsAsync {
+ fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync {
match a {
IsAsync::Async { .. } => hir::IsAsync::Async,
IsAsync::NotAsync => hir::IsAsync::NotAsync,
self.with_new_scopes(|this| {
hir::AnonConst {
hir_id: this.lower_node_id(c.id),
- body: this.lower_body(None, |this| this.lower_expr(&c.value)),
+ body: this.lower_const_body(&c.value),
}
})
}
let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
// Lower condition:
- let span_block = self
- .sess
- .source_map()
- .mark_span_with_reason(IfTemporary, cond.span, None);
+ let span_block = self.mark_span_with_reason(IfTemporary, cond.span, None);
let cond = self.lower_expr(cond);
// Wrap in a construct equivalent to `{ let _t = $cond; _t }` to preserve drop
// semantics since `if cond { ... }` don't let temporaries live outside of `cond`.
}),
ExprKind::TryBlock(ref body) => {
self.with_catch_scope(body.id, |this| {
- let unstable_span = this.sess.source_map().mark_span_with_reason(
+ let unstable_span = this.mark_span_with_reason(
CompilerDesugaringKind::TryBlock,
body.span,
Some(vec![sym::try_trait].into()),
}
ExprKind::Await(_origin, ref expr) => self.lower_await(e.span, expr),
ExprKind::Closure(
- capture_clause, ref asyncness, movability, ref decl, ref body, fn_decl_span
+ capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span
) => {
if let IsAsync::Async { closure_id, .. } = asyncness {
let outer_decl = FnDecl {
// Transform `async |x: u8| -> X { ... }` into
// `|x: u8| future_from_generator(|| -> X { ... })`.
- let body_id = this.lower_body(Some(&outer_decl), |this| {
+ let body_id = this.lower_fn_body(&outer_decl, |this| {
let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
Some(&**ty)
} else { None };
let async_body = this.make_async_expr(
- capture_clause, *closure_id, async_ret_ty, body.span,
+ capture_clause, closure_id, async_ret_ty, body.span,
|this| {
this.with_new_scopes(|this| this.lower_expr(body))
});
self.with_new_scopes(|this| {
this.current_item = Some(fn_decl_span);
let mut is_generator = false;
- let body_id = this.lower_body(Some(decl), |this| {
+ let body_id = this.lower_fn_body(decl, |this| {
let e = this.lower_expr(body);
is_generator = this.is_generator;
e
// expand <head>
let mut head = self.lower_expr(head);
let head_sp = head.span;
- let desugared_span = self.sess.source_map().mark_span_with_reason(
+ let desugared_span = self.mark_span_with_reason(
CompilerDesugaringKind::ForLoop,
head_sp,
None,
// return Try::from_error(From::from(err)),
// }
- let unstable_span = self.sess.source_map().mark_span_with_reason(
+ let unstable_span = self.mark_span_with_reason(
CompilerDesugaringKind::QuestionMark,
e.span,
Some(vec![sym::try_trait].into()),
);
let try_span = self.sess.source_map().end_point(e.span);
- let try_span = self.sess.source_map().mark_span_with_reason(
+ let try_span = self.mark_span_with_reason(
CompilerDesugaringKind::QuestionMark,
try_span,
Some(vec![sym::try_trait].into()),
err.emit();
return hir::ExprKind::Err;
}
- let span = self.sess.source_map().mark_span_with_reason(
+ let span = self.mark_span_with_reason(
CompilerDesugaringKind::Await,
await_span,
None,
);
- let gen_future_span = self.sess.source_map().mark_span_with_reason(
+ let gen_future_span = self.mark_span_with_reason(
CompilerDesugaringKind::Await,
await_span,
Some(vec![sym::gen_future].into()),
id: NodeId,
name: Name,
span: Span,
- header: &'a FnHeader,
+ header: &FnHeader,
generics: &'a Generics,
decl: &'a FnDecl,
body: &'a Block,
) {
- let (closure_id, return_impl_trait_id, arguments) = match &header.asyncness.node {
+ let (closure_id, return_impl_trait_id) = match header.asyncness.node {
IsAsync::Async {
closure_id,
return_impl_trait_id,
- arguments,
- } => (closure_id, return_impl_trait_id, arguments),
+ } => (closure_id, return_impl_trait_id),
_ => unreachable!(),
};
let fn_def_data = DefPathData::ValueNs(name.as_interned_str());
let fn_def = self.create_def(id, fn_def_data, span);
return self.with_parent(fn_def, |this| {
- this.create_def(*return_impl_trait_id, DefPathData::ImplTrait, span);
+ this.create_def(return_impl_trait_id, DefPathData::ImplTrait, span);
visit::walk_generics(this, generics);
-
- // Walk the generated arguments for the `async fn`.
- for (i, a) in arguments.iter().enumerate() {
- use visit::Visitor;
- if let Some(arg) = &a.arg {
- this.visit_ty(&arg.ty);
- } else {
- this.visit_ty(&decl.inputs[i].ty);
- }
- }
-
- // We do not invoke `walk_fn_decl` as this will walk the arguments that are being
- // replaced.
- visit::walk_fn_ret_ty(this, &decl.output);
+ visit::walk_fn_decl(this, decl);
let closure_def = this.create_def(
- *closure_id, DefPathData::ClosureExpr, span,
+ closure_id, DefPathData::ClosureExpr, span,
);
this.with_parent(closure_def, |this| {
- use visit::Visitor;
- // Walk each of the generated statements before the regular block body.
- for a in arguments {
- this.visit_stmt(&a.move_stmt);
- if let Some(pat_stmt) = &a.pat_stmt {
- this.visit_stmt(&pat_stmt);
- }
- }
-
- visit::walk_block(this, &body);
+ visit::walk_block(this, body);
})
})
}
match expr.node {
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
- ExprKind::Closure(_, ref asyncness, ..) => {
+ ExprKind::Closure(_, asyncness, ..) => {
let closure_def = self.create_def(expr.id,
DefPathData::ClosureExpr,
expr.span);
// Async closures desugar to closures inside of closures, so
// we must create two defs.
if let IsAsync::Async { closure_id, .. } = asyncness {
- let async_def = self.create_def(*closure_id,
+ let async_def = self.create_def(closure_id,
DefPathData::ClosureExpr,
expr.span);
self.parent_def = Some(async_def);
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,
pub struct Arg {
pub pat: P<Pat>,
pub hir_id: HirId,
- pub source: ArgSource,
-}
-
-impl Arg {
- /// Returns the pattern representing the original binding for this argument.
- pub fn original_pat(&self) -> &P<Pat> {
- match &self.source {
- ArgSource::Normal => &self.pat,
- ArgSource::AsyncFn(pat) => &pat,
- }
- }
-}
-
-/// Represents the source of an argument in a function header.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
-pub enum ArgSource {
- /// Argument as specified by the user.
- Normal,
- /// Generated argument from `async fn` lowering, contains the original binding pattern.
- AsyncFn(P<Pat>),
}
/// Represents the header (not the body) of a function declaration.
/// 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)),
hir_map: &'a hir::map::Map<'gcx>,
found_local_pattern: Option<&'gcx Pat>,
found_arg_pattern: Option<&'gcx Pat>,
+ found_ty: Option<Ty<'tcx>>,
}
impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
- fn node_matches_type(&mut self, hir_id: HirId) -> bool {
+ fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
let ty_opt = self.infcx.in_progress_tables.and_then(|tables| {
tables.borrow().node_type_opt(hir_id)
});
match ty_opt {
Some(ty) => {
let ty = self.infcx.resolve_vars_if_possible(&ty);
- ty.walk().any(|inner_ty| {
+ if ty.walk().any(|inner_ty| {
inner_ty == self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) {
(&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
self.infcx
}
_ => false,
}
- })
+ }) {
+ Some(ty)
+ } else {
+ None
+ }
}
- None => false,
+ None => None,
}
}
}
}
fn visit_local(&mut self, local: &'gcx Local) {
- if self.found_local_pattern.is_none() && self.node_matches_type(local.hir_id) {
+ if let (None, Some(ty)) = (self.found_local_pattern, self.node_matches_type(local.hir_id)) {
self.found_local_pattern = Some(&*local.pat);
+ self.found_ty = Some(ty);
}
intravisit::walk_local(self, local);
}
fn visit_body(&mut self, body: &'gcx Body) {
for argument in &body.arguments {
- if self.found_arg_pattern.is_none() && self.node_matches_type(argument.hir_id) {
+ if let (None, Some(ty)) = (
+ self.found_arg_pattern,
+ self.node_matches_type(argument.hir_id),
+ ) {
self.found_arg_pattern = Some(&*argument.pat);
+ self.found_ty = Some(ty);
}
}
intravisit::walk_body(self, body);
let name = self.extract_type_name(&ty, None);
let mut err_span = span;
- let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))];
let mut local_visitor = FindLocalByTypeVisitor {
infcx: &self,
hir_map: &self.tcx.hir(),
found_local_pattern: None,
found_arg_pattern: None,
+ found_ty: None,
+ };
+ let ty_to_string = |ty: Ty<'tcx>| -> String {
+ let mut s = String::new();
+ let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
+ let ty_vars = self.type_variables.borrow();
+ let getter = move |ty_vid| {
+ if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
+ *ty_vars.var_origin(ty_vid) {
+ return Some(name.to_string());
+ }
+ None
+ };
+ printer.name_resolver = Some(Box::new(&getter));
+ let _ = ty.print(printer);
+ s
};
if let Some(body_id) = body_id {
local_visitor.visit_expr(expr);
}
+ // When `name` corresponds to a type argument, show the path of the full type we're
+ // trying to infer. In the following example, `ty_msg` contains
+ // " in `std::result::Result<i32, E>`":
+ // ```
+ // error[E0282]: type annotations needed for `std::result::Result<i32, E>`
+ // --> file.rs:L:CC
+ // |
+ // L | let b = Ok(4);
+ // | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>`
+ // | |
+ // | consider giving `b` the explicit type `std::result::Result<i32, E>`, where
+ // | the type parameter `E` is specified
+ // ```
+ let (ty_msg, suffix) = match &local_visitor.found_ty {
+ Some(ty) if &ty.to_string() != "_" && name == "_" => {
+ let ty = ty_to_string(ty);
+ (format!(" for `{}`", ty),
+ format!("the explicit type `{}`, with the type parameters specified", ty))
+ }
+ Some(ty) if &ty.to_string() != "_" && ty.to_string() != name => {
+ let ty = ty_to_string(ty);
+ (format!(" for `{}`", ty),
+ format!(
+ "the explicit type `{}`, where the type parameter `{}` is specified",
+ ty,
+ name,
+ ))
+ }
+ _ => (String::new(), "a type".to_owned()),
+ };
+ let mut labels = vec![(span, InferCtxt::missing_type_msg(&name))];
+
if let Some(pattern) = local_visitor.found_arg_pattern {
err_span = pattern.span;
// We don't want to show the default label for closures.
// After clearing, it looks something like this:
// ```
// let x = |_| { };
- // ^ consider giving this closure parameter a type
+ // ^ consider giving this closure parameter the type `[_; 0]`
+ // with the type parameter `_` specified
// ```
labels.clear();
- labels.push(
- (pattern.span, "consider giving this closure parameter a type".to_owned()));
+ labels.push((
+ pattern.span,
+ format!("consider giving this closure parameter {}", suffix),
+ ));
} else if let Some(pattern) = local_visitor.found_local_pattern {
if let Some(simple_ident) = pattern.simple_ident() {
match pattern.span.compiler_desugaring_kind() {
- None => labels.push((pattern.span,
- format!("consider giving `{}` a type", simple_ident))),
+ None => labels.push((
+ pattern.span,
+ format!("consider giving `{}` {}", simple_ident, suffix),
+ )),
Some(CompilerDesugaringKind::ForLoop) => labels.push((
pattern.span,
"the element type for this iterator is not specified".to_owned(),
_ => {}
}
} else {
- labels.push((pattern.span, "consider giving the pattern a type".to_owned()));
+ labels.push((pattern.span, format!("consider giving this pattern {}", suffix)));
}
- }
+ };
- let mut err = struct_span_err!(self.tcx.sess,
- err_span,
- E0282,
- "type annotations needed");
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ err_span,
+ E0282,
+ "type annotations needed{}",
+ ty_msg,
+ );
for (target_span, label_message) in labels {
err.span_label(target_span, label_message);
let sub_is_ret_type =
self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
- let span_label_var1 = match anon_arg_sup.original_pat().simple_ident() {
+ let span_label_var1 = match anon_arg_sup.pat.simple_ident() {
Some(simple_ident) => format!(" from `{}`", simple_ident),
None => String::new(),
};
- let span_label_var2 = match anon_arg_sub.original_pat().simple_ident() {
+ let span_label_var2 = match anon_arg_sub.pat.simple_ident() {
Some(simple_ident) => format!(" into `{}`", simple_ident),
None => String::new(),
};
}
}
- let (error_var, span_label_var) = match arg.original_pat().simple_ident() {
+ let (error_var, span_label_var) = match arg.pat.simple_ident() {
Some(simple_ident) => (
format!("the type of `{}`", simple_ident),
format!("the type of `{}`", simple_ident),
use crate::ty::fold::{TypeFolder, TypeFoldable};
use crate::ty::relate::RelateResult;
use crate::ty::subst::{Kind, InternalSubsts, SubstsRef};
-use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt, CtxtInterners, InferConst};
+use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt, InferConst};
use crate::ty::{FloatVid, IntVid, TyVid, ConstVid};
use crate::util::nodemap::FxHashMap;
-use arena::SyncDroplessArena;
use errors::DiagnosticBuilder;
use rustc_data_structures::unify as ut;
use std::cell::{Cell, Ref, RefCell, RefMut};
/// `F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(InferCtxt<'b, 'gcx, 'tcx>)`.
pub struct InferCtxtBuilder<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
global_tcx: TyCtxt<'a, 'gcx, 'gcx>,
- arena: SyncDroplessArena,
- interners: Option<CtxtInterners<'tcx>>,
fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
}
pub fn infer_ctxt(self) -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
InferCtxtBuilder {
global_tcx: self,
- arena: SyncDroplessArena::default(),
- interners: None,
fresh_tables: None,
}
}
pub fn enter<R>(&'tcx mut self, f: impl for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R) -> R {
let InferCtxtBuilder {
global_tcx,
- ref arena,
- ref mut interners,
ref fresh_tables,
} = *self;
let in_progress_tables = fresh_tables.as_ref();
- // Check that we haven't entered before
- assert!(interners.is_none());
- global_tcx.enter_local(arena, interners, |tcx| {
+ global_tcx.enter_local(|tcx| {
f(InferCtxt {
tcx,
in_progress_tables,
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!(
run_early_pass!(self, check_mac, mac);
}
-
- fn visit_fn_header(&mut self, header: &'a ast::FnHeader) {
- // Unlike in HIR lowering and name resolution, the `AsyncArgument` statements are not added
- // to the function body and the arguments do not replace those in the declaration. They are
- // still visited manually here so that buffered lints can be emitted.
- if let ast::IsAsync::Async { ref arguments, .. } = header.asyncness.node {
- for a in arguments {
- // Visit the argument..
- if let Some(arg) = &a.arg {
- self.visit_pat(&arg.pat);
- if let ast::ArgSource::AsyncFn(pat) = &arg.source {
- self.visit_pat(pat);
- }
- self.visit_ty(&arg.ty);
- }
-
- // ..and the statement.
- self.visit_stmt(&a.move_stmt);
- if let Some(pat_stmt) = &a.pat_stmt {
- self.visit_stmt(&pat_stmt);
- }
- }
- }
- }
}
struct LateLintPassObjects<'a> {
}
_ 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) => {
have_bound_regions,
} = info;
- let help_name = if let Some(body) = parent {
- let arg = &self.tcx.hir().body(body).arguments[index];
- format!("`{}`", self.tcx.hir().hir_to_pretty_string(arg.original_pat().hir_id))
+ let help_name = if let Some(ident) = parent.and_then(|body| {
+ self.tcx.hir().body(body).arguments[index].pat.simple_ident()
+ }) {
+ format!("`{}`", ident)
} else {
format!("argument {}", index + 1)
};
// 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);
}
}
use crate::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use crate::hir::HirId;
use syntax::symbol::InternedString;
-use crate::ty::{Instance, TyCtxt};
+use syntax::attr::InlineAttr;
+use syntax::source_map::Span;
+use crate::ty::{Instance, InstanceDef, TyCtxt, SymbolName, subst::InternalSubsts};
use crate::util::nodemap::FxHashMap;
+use crate::ty::print::obsolete::DefPathBasedNames;
+use crate::dep_graph::{WorkProductId, DepNode, WorkProduct, DepConstructor};
use rustc_data_structures::base_n;
use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult,
StableHasher};
use crate::ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
+use crate::session::config::OptLevel;
use std::fmt;
use std::hash::Hash;
+/// Describes how a monomorphization will be instantiated in object files.
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
+pub enum InstantiationMode {
+ /// There will be exactly one instance of the given MonoItem. It will have
+ /// external linkage so that it can be linked to from other codegen units.
+ GloballyShared {
+ /// In some compilation scenarios we may decide to take functions that
+ /// are typically `LocalCopy` and instead move them to `GloballyShared`
+ /// to avoid codegenning them a bunch of times. In this situation,
+ /// however, our local copy may conflict with other crates also
+ /// inlining the same function.
+ ///
+ /// This flag indicates that this situation is occurring, and informs
+ /// symbol name calculation that some extra mangling is needed to
+ /// avoid conflicts. Note that this may eventually go away entirely if
+ /// ThinLTO enables us to *always* have a globally shared instance of a
+ /// function within one crate's compilation.
+ may_conflict: bool,
+ },
+
+ /// Each codegen unit containing a reference to the given MonoItem will
+ /// have its own private copy of the function (with internal linkage).
+ LocalCopy,
+}
+
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
pub enum MonoItem<'tcx> {
Fn(Instance<'tcx>),
MonoItem::GlobalAsm(_) => 1,
}
}
+
+ pub fn is_generic_fn(&self) -> bool {
+ match *self {
+ MonoItem::Fn(ref instance) => {
+ instance.substs.non_erasable_generics().next().is_some()
+ }
+ MonoItem::Static(..) |
+ MonoItem::GlobalAsm(..) => false,
+ }
+ }
+
+ pub fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> SymbolName {
+ match *self {
+ MonoItem::Fn(instance) => tcx.symbol_name(instance),
+ MonoItem::Static(def_id) => {
+ tcx.symbol_name(Instance::mono(tcx, def_id))
+ }
+ MonoItem::GlobalAsm(hir_id) => {
+ let def_id = tcx.hir().local_def_id_from_hir_id(hir_id);
+ SymbolName {
+ name: InternedString::intern(&format!("global_asm_{:?}", def_id))
+ }
+ }
+ }
+ }
+
+ pub fn instantiation_mode(&self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>)
+ -> InstantiationMode {
+ let inline_in_all_cgus =
+ tcx.sess.opts.debugging_opts.inline_in_all_cgus.unwrap_or_else(|| {
+ tcx.sess.opts.optimize != OptLevel::No
+ }) && !tcx.sess.opts.cg.link_dead_code;
+
+ match *self {
+ MonoItem::Fn(ref instance) => {
+ let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
+ // If this function isn't inlined or otherwise has explicit
+ // linkage, then we'll be creating a globally shared version.
+ if self.explicit_linkage(tcx).is_some() ||
+ !instance.def.requires_local(tcx) ||
+ Some(instance.def_id()) == entry_def_id
+ {
+ return InstantiationMode::GloballyShared { may_conflict: false }
+ }
+
+ // At this point we don't have explicit linkage and we're an
+ // inlined function. If we're inlining into all CGUs then we'll
+ // be creating a local copy per CGU
+ if inline_in_all_cgus {
+ return InstantiationMode::LocalCopy
+ }
+
+ // Finally, if this is `#[inline(always)]` we're sure to respect
+ // that with an inline copy per CGU, but otherwise we'll be
+ // creating one copy of this `#[inline]` function which may
+ // conflict with upstream crates as it could be an exported
+ // symbol.
+ match tcx.codegen_fn_attrs(instance.def_id()).inline {
+ InlineAttr::Always => InstantiationMode::LocalCopy,
+ _ => {
+ InstantiationMode::GloballyShared { may_conflict: true }
+ }
+ }
+ }
+ MonoItem::Static(..) |
+ MonoItem::GlobalAsm(..) => {
+ InstantiationMode::GloballyShared { may_conflict: false }
+ }
+ }
+ }
+
+ pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Linkage> {
+ let def_id = match *self {
+ MonoItem::Fn(ref instance) => instance.def_id(),
+ MonoItem::Static(def_id) => def_id,
+ MonoItem::GlobalAsm(..) => return None,
+ };
+
+ let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
+ codegen_fn_attrs.linkage
+ }
+
+ /// Returns `true` if this instance is instantiable - whether it has no unsatisfied
+ /// predicates.
+ ///
+ /// In order to codegen an item, all of its predicates must hold, because
+ /// otherwise the item does not make sense. Type-checking ensures that
+ /// the predicates of every item that is *used by* a valid item *do*
+ /// hold, so we can rely on that.
+ ///
+ /// However, we codegen collector roots (reachable items) and functions
+ /// in vtables when they are seen, even if they are not used, and so they
+ /// might not be instantiable. For example, a programmer can define this
+ /// public function:
+ ///
+ /// pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
+ /// <&mut () as Clone>::clone(&s);
+ /// }
+ ///
+ /// That function can't be codegened, because the method `<&mut () as Clone>::clone`
+ /// does not exist. Luckily for us, that function can't ever be used,
+ /// because that would require for `&'a mut (): Clone` to hold, so we
+ /// can just not emit any code, or even a linker reference for it.
+ ///
+ /// Similarly, if a vtable method has such a signature, and therefore can't
+ /// be used, we can just not emit it and have a placeholder (a null pointer,
+ /// which will never be accessed) in its place.
+ pub fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
+ debug!("is_instantiable({:?})", self);
+ let (def_id, substs) = match *self {
+ MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs),
+ MonoItem::Static(def_id) => (def_id, InternalSubsts::empty()),
+ // global asm never has predicates
+ MonoItem::GlobalAsm(..) => return true
+ };
+
+ tcx.substitute_normalize_and_test_predicates((def_id, &substs))
+ }
+
+ pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, debug: bool) -> String {
+ return match *self {
+ MonoItem::Fn(instance) => {
+ to_string_internal(tcx, "fn ", instance, debug)
+ },
+ MonoItem::Static(def_id) => {
+ let instance = Instance::new(def_id, tcx.intern_substs(&[]));
+ to_string_internal(tcx, "static ", instance, debug)
+ },
+ MonoItem::GlobalAsm(..) => {
+ "global_asm".to_string()
+ }
+ };
+
+ fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ prefix: &str,
+ instance: Instance<'tcx>,
+ debug: bool)
+ -> String {
+ let mut result = String::with_capacity(32);
+ result.push_str(prefix);
+ let printer = DefPathBasedNames::new(tcx, false, false);
+ printer.push_instance_as_string(instance, &mut result, debug);
+ result
+ }
+ }
+
+ pub fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Span> {
+ match *self {
+ MonoItem::Fn(Instance { def, .. }) => {
+ tcx.hir().as_local_hir_id(def.def_id())
+ }
+ MonoItem::Static(def_id) => {
+ tcx.hir().as_local_hir_id(def_id)
+ }
+ MonoItem::GlobalAsm(hir_id) => {
+ Some(hir_id)
+ }
+ }.map(|hir_id| tcx.hir().span_by_hir_id(hir_id))
+ }
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
self.size_estimate = Some(size_estimate + delta);
}
}
+
+ pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool {
+ self.items().contains_key(item)
+ }
+
+ pub fn work_product_id(&self) -> WorkProductId {
+ WorkProductId::from_cgu_name(&self.name().as_str())
+ }
+
+ pub fn work_product(&self, tcx: TyCtxt<'_, '_, '_>) -> WorkProduct {
+ let work_product_id = self.work_product_id();
+ tcx.dep_graph
+ .previous_work_product(&work_product_id)
+ .unwrap_or_else(|| {
+ panic!("Could not find work-product for CGU `{}`", self.name())
+ })
+ }
+
+ pub fn items_in_deterministic_order<'a>(&self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>)
+ -> Vec<(MonoItem<'tcx>,
+ (Linkage, Visibility))> {
+ // The codegen tests rely on items being process in the same order as
+ // they appear in the file, so for local items, we sort by node_id first
+ #[derive(PartialEq, Eq, PartialOrd, Ord)]
+ pub struct ItemSortKey(Option<HirId>, SymbolName);
+
+ fn item_sort_key<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item: MonoItem<'tcx>) -> ItemSortKey {
+ ItemSortKey(match item {
+ MonoItem::Fn(ref instance) => {
+ match instance.def {
+ // We only want to take HirIds of user-defined
+ // instances into account. The others don't matter for
+ // the codegen tests and can even make item order
+ // unstable.
+ InstanceDef::Item(def_id) => {
+ tcx.hir().as_local_hir_id(def_id)
+ }
+ InstanceDef::VtableShim(..) |
+ InstanceDef::Intrinsic(..) |
+ InstanceDef::FnPtrShim(..) |
+ InstanceDef::Virtual(..) |
+ InstanceDef::ClosureOnceShim { .. } |
+ InstanceDef::DropGlue(..) |
+ InstanceDef::CloneShim(..) => {
+ None
+ }
+ }
+ }
+ MonoItem::Static(def_id) => {
+ tcx.hir().as_local_hir_id(def_id)
+ }
+ MonoItem::GlobalAsm(hir_id) => {
+ Some(hir_id)
+ }
+ }, item.symbol_name(tcx))
+ }
+
+ let mut items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect();
+ items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i));
+ items
+ }
+
+ pub fn codegen_dep_node(&self, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> DepNode {
+ DepNode::new(tcx, DepConstructor::CompileCodegenUnit(self.name().clone()))
+ }
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {
use crate::ty::subst::SubstsRef;
use crate::dep_graph::SerializedDepNodeIndex;
use crate::hir::def_id::{CrateNum, DefId, DefIndex};
+use crate::mir;
use crate::mir::interpret::GlobalId;
use crate::traits;
use crate::traits::query::{
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))
}
}
}
tcx.queries.on_disk_cache.try_load_query_result(tcx, id).map(Ok)
}
}
+
+ /// Extracts a field of a (variant of a) const.
+ query const_field(
+ key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field)>
+ ) -> &'tcx ty::Const<'tcx> {
+ eval_always
+ no_force
+ desc { "extract field of const" }
+ }
+
+ /// Produces an absolute path representation of the given type. See also the documentation
+ /// on `std::any::type_name`.
+ query type_name(key: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
+ eval_always
+ no_force
+ desc { "get absolute path of type" }
+ }
+
}
TypeChecking {
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,
+ pub local_interner: SyncDroplessArena,
}
-impl<'tcx> AllArenas<'tcx> {
+impl AllArenas {
pub fn new() -> Self {
AllArenas {
- global: WorkerLocal::new(|_| GlobalArenas::default()),
interner: SyncDroplessArena::default(),
+ local_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> {
/// Intern a type
#[inline(never)]
fn intern_ty(
- local: &CtxtInterners<'tcx>,
+ local: &CtxtInterners<'gcx>,
global: &CtxtInterners<'gcx>,
st: TyKind<'tcx>
) -> Ty<'tcx> {
&ty_struct);
}
+ // This is safe because all the types the ty_struct can point to
+ // already is in the local arena or the global arena
+ let ty_struct: TyS<'gcx> = unsafe {
+ mem::transmute(ty_struct)
+ };
+
Interned(local.arena.alloc(ty_struct))
}).0
} else {
#[derive(Copy, Clone)]
pub struct TyCtxt<'a, 'gcx: 'tcx, 'tcx: 'a> {
gcx: &'gcx GlobalCtxt<'gcx>,
- interners: &'tcx CtxtInterners<'tcx>,
- dummy: PhantomData<&'a ()>,
+ interners: &'gcx CtxtInterners<'gcx>,
+ dummy: PhantomData<(&'a (), &'tcx ())>,
}
impl<'gcx> Deref for TyCtxt<'_, 'gcx, '_> {
pub struct GlobalCtxt<'tcx> {
pub arena: WorkerLocal<Arena<'tcx>>,
- global_arenas: &'tcx WorkerLocal<GlobalArenas<'tcx>>,
+
global_interners: CtxtInterners<'tcx>,
+ local_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>,
s.fatal(&err);
});
let interners = CtxtInterners::new(&arenas.interner);
+ let local_interners = CtxtInterners::new(&arenas.local_interner);
let common = Common {
empty_predicates: ty::GenericPredicates {
parent: None,
sess: s,
cstore,
arena: WorkerLocal::new(|_| Arena::default()),
- global_arenas: &arenas.global,
global_interners: interners,
+ local_interners: local_interners,
dep_graph,
common,
types: common_types,
}).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()
/// with the same lifetime as `arena`.
pub fn enter_local<'tcx, F, R>(
&'gcx self,
- arena: &'tcx SyncDroplessArena,
- interners: &'tcx mut Option<CtxtInterners<'tcx>>,
f: F
) -> R
where
F: FnOnce(TyCtxt<'tcx, 'gcx, 'tcx>) -> R,
'gcx: 'tcx,
{
- *interners = Some(CtxtInterners::new(&arena));
let tcx = TyCtxt {
gcx: self,
- interners: interners.as_ref().unwrap(),
+ interners: &self.local_interners,
dummy: PhantomData,
};
ty::tls::with_related_context(tcx.global_tcx(), |icx| {
pub fn $method(self, v: $alloc) -> &$lt_tcx $ty {
let key = ($alloc_to_key)(&v);
+ let alloc = |v, interners: &'gcx CtxtInterners<'gcx>| {
+ // This transmutes $alloc<'tcx> to $alloc<'gcx>
+ let v = unsafe {
+ mem::transmute(v)
+ };
+ let i: &$lt_tcx $ty = $alloc_method(&interners.arena, v);
+ // Cast to 'gcx
+ let i = unsafe { mem::transmute(i) };
+ Interned(i)
+ };
+
// HACK(eddyb) Depend on flags being accurate to
// determine that all contents are in the global tcx.
// See comments on Lift for why we can't use that.
v);
}
- Interned($alloc_method(&self.interners.arena, v))
+ alloc(v, &self.interners)
}).0
} else {
self.global_interners.$name.borrow_mut().intern_ref(key, || {
- // This transmutes $alloc<'tcx> to $alloc<'gcx>
- let v = unsafe {
- mem::transmute(v)
- };
- let i: &$lt_tcx $ty = $alloc_method(&self.global_interners.arena, v);
- // Cast to 'gcx
- let i = unsafe { mem::transmute(i) };
- Interned(i)
+ alloc(v, &self.global_interners)
}).0
}
}
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)
};
use crate::ty::{self, Ty, PolyFnSig, TypeFoldable, SubstsRef, TyCtxt};
use crate::ty::print::{FmtPrinter, Printer};
use crate::traits;
+use crate::middle::lang_items::DropInPlaceFnLangItem;
use rustc_target::spec::abi::Abi;
use rustc_macros::HashStable;
let actual_kind = substs.closure_kind(def_id, tcx);
match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
- Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
+ Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, substs),
_ => Instance::new(def_id, substs.substs)
}
}
+ pub fn resolve_drop_in_place(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ ty: Ty<'tcx>)
+ -> ty::Instance<'tcx>
+ {
+ let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
+ let substs = tcx.intern_substs(&[ty.into()]);
+ Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap()
+ }
+
+ pub fn fn_once_adapter_instance(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ closure_did: DefId,
+ substs: ty::ClosureSubsts<'tcx>)
+ -> Instance<'tcx>
+ {
+ debug!("fn_once_adapter_shim({:?}, {:?})",
+ closure_did,
+ substs);
+ let fn_once = tcx.lang_items().fn_once_trait().unwrap();
+ let call_once = tcx.associated_items(fn_once)
+ .find(|it| it.kind == ty::AssocKind::Method)
+ .unwrap().def_id;
+ let def = ty::InstanceDef::ClosureOnceShim { call_once };
+
+ let self_ty = tcx.mk_closure(closure_did, substs);
+
+ let sig = substs.closure_sig(closure_did, tcx);
+ let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+ assert_eq!(sig.inputs().len(), 1);
+ let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
+
+ debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
+ Instance { def, substs }
+ }
+
pub fn is_vtable_shim(&self) -> bool {
if let InstanceDef::VtableShim(..) = self.def {
true
(ty::ClosureKind::FnOnce, _) => Err(())
}
}
-
-fn fn_once_adapter_instance<'a, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- closure_did: DefId,
- substs: ty::ClosureSubsts<'tcx>)
- -> Instance<'tcx>
-{
- debug!("fn_once_adapter_shim({:?}, {:?})",
- closure_did,
- substs);
- let fn_once = tcx.lang_items().fn_once_trait().unwrap();
- let call_once = tcx.associated_items(fn_once)
- .find(|it| it.kind == ty::AssocKind::Method)
- .unwrap().def_id;
- let def = ty::InstanceDef::ClosureOnceShim { call_once };
-
- let self_ty = tcx.mk_closure(closure_did, substs);
-
- let sig = substs.closure_sig(closure_did, tcx);
- let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
- assert_eq!(sig.inputs().len(), 1);
- let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
-
- debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
- Instance { def, substs }
-}
}
}
+ 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)]
mod pretty;
pub use self::pretty::*;
+pub mod obsolete;
+
pub trait Print<'gcx, 'tcx, P> {
type Output;
type Error;
--- /dev/null
+//! Allows for producing a unique string key for a mono item.
+//! These keys are used by the handwritten auto-tests, so they need to be
+//! predictable and human-readable.
+//!
+//! Note: A lot of this could looks very similar to what's already in `ty::print`.
+//! FIXME(eddyb) implement a custom `PrettyPrinter` for this.
+
+use rustc::hir::def_id::DefId;
+use rustc::mir::interpret::ConstValue;
+use rustc::ty::subst::SubstsRef;
+use rustc::ty::{self, ClosureSubsts, Const, GeneratorSubsts, Instance, Ty, TyCtxt};
+use rustc::{bug, hir};
+use std::fmt::Write;
+use std::iter;
+use syntax::ast;
+
+/// Same as `unique_type_name()` but with the result pushed onto the given
+/// `output` parameter.
+pub struct DefPathBasedNames<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ omit_disambiguators: bool,
+ omit_local_crate_name: bool,
+}
+
+impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
+ pub fn new(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ omit_disambiguators: bool,
+ omit_local_crate_name: bool,
+ ) -> Self {
+ DefPathBasedNames { tcx, omit_disambiguators, omit_local_crate_name }
+ }
+
+ // Pushes the type name of the specified type to the provided string.
+ // If `debug` is true, printing normally unprintable types is allowed
+ // (e.g. `ty::GeneratorWitness`). This parameter should only be set when
+ // this method is being used for logging purposes (e.g. with `debug!` or `info!`)
+ // When being used for codegen purposes, `debug` should be set to `false`
+ // in order to catch unexpected types that should never end up in a type name.
+ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
+ match t.sty {
+ ty::Bool => output.push_str("bool"),
+ ty::Char => output.push_str("char"),
+ ty::Str => output.push_str("str"),
+ ty::Never => output.push_str("!"),
+ ty::Int(ast::IntTy::Isize) => output.push_str("isize"),
+ ty::Int(ast::IntTy::I8) => output.push_str("i8"),
+ ty::Int(ast::IntTy::I16) => output.push_str("i16"),
+ ty::Int(ast::IntTy::I32) => output.push_str("i32"),
+ ty::Int(ast::IntTy::I64) => output.push_str("i64"),
+ ty::Int(ast::IntTy::I128) => output.push_str("i128"),
+ ty::Uint(ast::UintTy::Usize) => output.push_str("usize"),
+ ty::Uint(ast::UintTy::U8) => output.push_str("u8"),
+ ty::Uint(ast::UintTy::U16) => output.push_str("u16"),
+ ty::Uint(ast::UintTy::U32) => output.push_str("u32"),
+ ty::Uint(ast::UintTy::U64) => output.push_str("u64"),
+ ty::Uint(ast::UintTy::U128) => output.push_str("u128"),
+ ty::Float(ast::FloatTy::F32) => output.push_str("f32"),
+ ty::Float(ast::FloatTy::F64) => output.push_str("f64"),
+ ty::Adt(adt_def, substs) => {
+ self.push_def_path(adt_def.did, output);
+ self.push_generic_params(substs, iter::empty(), output, debug);
+ }
+ ty::Tuple(component_types) => {
+ output.push('(');
+ for &component_type in component_types {
+ self.push_type_name(component_type.expect_ty(), output, debug);
+ output.push_str(", ");
+ }
+ if !component_types.is_empty() {
+ output.pop();
+ output.pop();
+ }
+ output.push(')');
+ }
+ ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
+ output.push('*');
+ match mutbl {
+ hir::MutImmutable => output.push_str("const "),
+ hir::MutMutable => output.push_str("mut "),
+ }
+
+ self.push_type_name(inner_type, output, debug);
+ }
+ ty::Ref(_, inner_type, mutbl) => {
+ output.push('&');
+ if mutbl == hir::MutMutable {
+ output.push_str("mut ");
+ }
+
+ self.push_type_name(inner_type, output, debug);
+ }
+ ty::Array(inner_type, len) => {
+ output.push('[');
+ self.push_type_name(inner_type, output, debug);
+ write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
+ output.push(']');
+ }
+ ty::Slice(inner_type) => {
+ output.push('[');
+ self.push_type_name(inner_type, output, debug);
+ output.push(']');
+ }
+ ty::Dynamic(ref trait_data, ..) => {
+ if let Some(principal) = trait_data.principal() {
+ self.push_def_path(principal.def_id(), output);
+ self.push_generic_params(
+ principal.skip_binder().substs,
+ trait_data.projection_bounds(),
+ output,
+ debug,
+ );
+ } else {
+ output.push_str("dyn '_");
+ }
+ }
+ ty::Foreign(did) => self.push_def_path(did, output),
+ ty::FnDef(..) | ty::FnPtr(_) => {
+ let sig = t.fn_sig(self.tcx);
+ if sig.unsafety() == hir::Unsafety::Unsafe {
+ output.push_str("unsafe ");
+ }
+
+ let abi = sig.abi();
+ if abi != ::rustc_target::spec::abi::Abi::Rust {
+ output.push_str("extern \"");
+ output.push_str(abi.name());
+ output.push_str("\" ");
+ }
+
+ output.push_str("fn(");
+
+ let sig =
+ self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+
+ if !sig.inputs().is_empty() {
+ for ¶meter_type in sig.inputs() {
+ self.push_type_name(parameter_type, output, debug);
+ output.push_str(", ");
+ }
+ output.pop();
+ output.pop();
+ }
+
+ if sig.c_variadic {
+ if !sig.inputs().is_empty() {
+ output.push_str(", ...");
+ } else {
+ output.push_str("...");
+ }
+ }
+
+ output.push(')');
+
+ if !sig.output().is_unit() {
+ output.push_str(" -> ");
+ self.push_type_name(sig.output(), output, debug);
+ }
+ }
+ ty::Generator(def_id, GeneratorSubsts { ref substs }, _)
+ | ty::Closure(def_id, ClosureSubsts { ref substs }) => {
+ self.push_def_path(def_id, output);
+ let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
+ let substs = substs.truncate_to(self.tcx, generics);
+ self.push_generic_params(substs, iter::empty(), output, debug);
+ }
+ ty::Error
+ | ty::Bound(..)
+ | ty::Infer(_)
+ | ty::Placeholder(..)
+ | ty::UnnormalizedProjection(..)
+ | ty::Projection(..)
+ | ty::Param(_)
+ | ty::GeneratorWitness(_)
+ | ty::Opaque(..) => {
+ if debug {
+ output.push_str(&format!("`{:?}`", t));
+ } else {
+ bug!(
+ "DefPathBasedNames: trying to create type name for unexpected type: {:?}",
+ t,
+ );
+ }
+ }
+ }
+ }
+
+ // Pushes the the name of the specified const to the provided string.
+ // If `debug` is true, usually-unprintable consts (such as `Infer`) will be printed,
+ // as well as the unprintable types of constants (see `push_type_name` for more details).
+ pub fn push_const_name(&self, c: &Const<'tcx>, output: &mut String, debug: bool) {
+ match c.val {
+ ConstValue::Scalar(..) | ConstValue::Slice { .. } | ConstValue::ByRef(..) => {
+ // FIXME(const_generics): we could probably do a better job here.
+ write!(output, "{:?}", c).unwrap()
+ }
+ _ => {
+ if debug {
+ write!(output, "{:?}", c).unwrap()
+ } else {
+ bug!(
+ "DefPathBasedNames: trying to create const name for unexpected const: {:?}",
+ c,
+ );
+ }
+ }
+ }
+ output.push_str(": ");
+ self.push_type_name(c.ty, output, debug);
+ }
+
+ pub fn push_def_path(&self, def_id: DefId, output: &mut String) {
+ let def_path = self.tcx.def_path(def_id);
+
+ // some_crate::
+ if !(self.omit_local_crate_name && def_id.is_local()) {
+ output.push_str(&self.tcx.crate_name(def_path.krate).as_str());
+ output.push_str("::");
+ }
+
+ // foo::bar::ItemName::
+ for part in self.tcx.def_path(def_id).data {
+ if self.omit_disambiguators {
+ write!(output, "{}::", part.data.as_interned_str()).unwrap();
+ } else {
+ write!(output, "{}[{}]::", part.data.as_interned_str(), part.disambiguator)
+ .unwrap();
+ }
+ }
+
+ // remove final "::"
+ output.pop();
+ output.pop();
+ }
+
+ fn push_generic_params<I>(
+ &self,
+ substs: SubstsRef<'tcx>,
+ projections: I,
+ output: &mut String,
+ debug: bool,
+ ) where
+ I: Iterator<Item = ty::PolyExistentialProjection<'tcx>>,
+ {
+ let mut projections = projections.peekable();
+ if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() {
+ return;
+ }
+
+ output.push('<');
+
+ for type_parameter in substs.types() {
+ self.push_type_name(type_parameter, output, debug);
+ output.push_str(", ");
+ }
+
+ for projection in projections {
+ let projection = projection.skip_binder();
+ let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str();
+ output.push_str(name);
+ output.push_str("=");
+ self.push_type_name(projection.ty, output, debug);
+ output.push_str(", ");
+ }
+
+ for const_parameter in substs.consts() {
+ self.push_const_name(const_parameter, output, debug);
+ output.push_str(", ");
+ }
+
+ output.pop();
+ output.pop();
+
+ output.push('>');
+ }
+
+ pub fn push_instance_as_string(
+ &self,
+ instance: Instance<'tcx>,
+ output: &mut String,
+ debug: bool,
+ ) {
+ self.push_def_path(instance.def_id(), output);
+ self.push_generic_params(instance.substs, iter::empty(), output, debug);
+ }
+}
ty::FnPtr(ref bare_fn) => {
p!(print(bare_fn))
}
- ty::Infer(infer_ty) => p!(write("{}", infer_ty)),
+ ty::Infer(infer_ty) => {
+ if let ty::TyVar(ty_vid) = infer_ty {
+ if let Some(name) = self.infer_ty_name(ty_vid) {
+ p!(write("{}", name))
+ } else {
+ p!(write("{}", infer_ty))
+ }
+ } else {
+ p!(write("{}", infer_ty))
+ }
+ },
ty::Error => p!(write("[type error]")),
ty::Param(ref param_ty) => p!(write("{}", param_ty)),
ty::Bound(debruijn, bound_ty) => {
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 = ", ";
}
Ok(self)
}
+ fn infer_ty_name(&self, _: ty::TyVid) -> Option<String> {
+ None
+ }
+
fn pretty_print_dyn_existential(
mut self,
predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
binder_depth: usize,
pub region_highlight_mode: RegionHighlightMode,
+
+ pub name_resolver: Option<Box<&'a dyn Fn(ty::sty::TyVid) -> Option<String>>>,
}
impl<F> Deref for FmtPrinter<'a, 'gcx, 'tcx, F> {
region_index: 0,
binder_depth: 0,
region_highlight_mode: RegionHighlightMode::default(),
+ name_resolver: None,
}))
}
}
}
impl<F: fmt::Write> PrettyPrinter<'gcx, 'tcx> for FmtPrinter<'_, 'gcx, 'tcx, F> {
+ fn infer_ty_name(&self, id: ty::TyVid) -> Option<String> {
+ self.0.name_resolver.as_ref().and_then(|func| func(id))
+ }
+
fn print_value_path(
mut self,
def_id: DefId,
br
}
ty::BrAnon(_) |
- ty::BrFresh(_) |
ty::BrEnv => {
let name = loop {
let name = name_by_region_index(region_index);
}
}
+impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) {
+ fn query_crate(&self) -> CrateNum {
+ LOCAL_CRATE
+ }
+ fn default_span(&self, _: TyCtxt<'_, '_, '_>) -> Span {
+ DUMMY_SP
+ }
+}
+
impl<'tcx> Key for ty::PolyTraitRef<'tcx>{
fn query_crate(&self) -> CrateNum {
self.def_id().krate
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 crate::builder::Builder;
use crate::common;
use crate::context::CodegenCx;
-use crate::monomorphize::partitioning::CodegenUnitExt;
use rustc::dep_graph;
use rustc::mir::mono::{Linkage, Visibility};
use rustc::middle::cstore::{EncodedMetadata};
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,
+ unchecked_sadd(x, y) => LLVMBuildNSWAdd,
+ unchecked_uadd(x, y) => LLVMBuildNUWAdd,
+ unchecked_ssub(x, y) => LLVMBuildNSWSub,
+ unchecked_usub(x, y) => LLVMBuildNUWSub,
+ unchecked_smul(x, y) => LLVMBuildNSWMul,
+ unchecked_umul(x, y) => LLVMBuildNUWMul,
}
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::attributes;
use crate::llvm;
-use crate::monomorphize::Instance;
use crate::context::CodegenCx;
use crate::value::Value;
use rustc_codegen_ssa::traits::*;
-use rustc::ty::TypeFoldable;
+use rustc::ty::{TypeFoldable, Instance};
use rustc::ty::layout::{LayoutOf, HasTyCtxt};
/// Codegens a reference to a fn/method item, monomorphizing and
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)
}
use crate::llvm::{self, SetUnnamedAddr, True};
use crate::debuginfo;
-use crate::monomorphize::MonoItem;
use crate::common::CodegenCx;
-use crate::monomorphize::Instance;
use crate::base;
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use rustc::hir::def_id::DefId;
use rustc::mir::interpret::{ConstValue, Allocation, read_target_uint,
Pointer, ErrorHandled, GlobalId};
+use rustc::mir::mono::MonoItem;
use rustc::hir::Node;
use syntax_pos::Span;
use rustc_target::abi::HasDataLayout;
use syntax::symbol::sym;
use syntax_pos::symbol::LocalInternedString;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, Instance};
use rustc_codegen_ssa::traits::*;
use rustc::ty::layout::{self, Size, Align, LayoutOf};
use crate::attributes;
use crate::llvm;
use crate::debuginfo;
-use crate::monomorphize::Instance;
use crate::value::Value;
use rustc::dep_graph::DepGraphSafe;
use rustc::hir;
-use crate::monomorphize::partitioning::CodegenUnit;
use crate::type_::Type;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::base_n;
use rustc_data_structures::small_c_str::SmallCStr;
+use rustc::mir::mono::CodegenUnit;
use rustc::session::config::{self, DebugInfo};
use rustc::session::Session;
use rustc::ty::layout::{
LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx, HasParamEnv
};
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt, Instance};
use rustc::util::nodemap::FxHashMap;
use rustc_target::spec::{HasTargetSpec, Target};
use rustc_codegen_ssa::callee::resolve_and_get_fn;
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
};
use crate::abi::Abi;
use crate::common::CodegenCx;
use crate::builder::Builder;
-use crate::monomorphize::Instance;
use crate::value::Value;
-use rustc::ty::{self, ParamEnv, Ty, InstanceDef};
+use rustc::ty::{self, ParamEnv, Ty, InstanceDef, Instance};
use rustc::mir;
use rustc::session::config::{self, DebugInfo};
use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
use super::metadata::{unknown_file_metadata, UNKNOWN_LINE_NUMBER};
use super::utils::{DIB, debug_context};
-use crate::monomorphize::Instance;
-use rustc::ty;
+use rustc::ty::{self, Instance};
use crate::llvm;
use crate::llvm::debuginfo::DIScope;
}
"type_name" => {
let tp_ty = substs.type_at(0);
- let ty_name = rustc_mir::interpret::type_name(self.tcx, tp_ty);
+ let ty_name = self.tcx.type_name(tp_ty);
OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self)
}
"type_id" => {
"ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" |
"bitreverse" | "add_with_overflow" | "sub_with_overflow" |
"mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
- "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" |
+ "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" |
+ "unchecked_add" | "unchecked_sub" | "unchecked_mul" | "exact_div" |
"rotate_left" | "rotate_right" | "saturating_add" | "saturating_sub" => {
let ty = arg_tys[0];
match int_type_width_signed(ty, self) {
} else {
self.lshr(args[0].immediate(), args[1].immediate())
},
+ "unchecked_add" => {
+ if signed {
+ self.unchecked_sadd(args[0].immediate(), args[1].immediate())
+ } else {
+ self.unchecked_uadd(args[0].immediate(), args[1].immediate())
+ }
+ },
+ "unchecked_sub" => {
+ if signed {
+ self.unchecked_ssub(args[0].immediate(), args[1].immediate())
+ } else {
+ self.unchecked_usub(args[0].immediate(), args[1].immediate())
+ }
+ },
+ "unchecked_mul" => {
+ if signed {
+ self.unchecked_smul(args[0].immediate(), args[1].immediate())
+ } else {
+ self.unchecked_umul(args[0].immediate(), args[1].immediate())
+ }
+ },
"rotate_left" | "rotate_right" => {
let is_left = name == "rotate_left";
let val = args[0].immediate();
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(const_cstr_unchecked)]
#![feature(crate_visibility_modifier)]
#![feature(custom_attribute)]
#![feature(extern_types)]
#[macro_use] extern crate bitflags;
extern crate libc;
#[macro_use] extern crate rustc;
-extern crate rustc_mir;
extern crate rustc_allocator;
extern crate rustc_target;
#[macro_use] extern crate rustc_data_structures;
use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel};
use rustc::ty::{self, TyCtxt};
use rustc::util::common::ErrorReported;
-use rustc_mir::monomorphize;
use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
RHS: &'a Value,
Name: *const c_char)
-> &'a Value;
+ pub fn LLVMBuildNSWAdd(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildNUWAdd(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildNSWSub(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildNUWSub(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildNSWMul(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
+ pub fn LLVMBuildNUWMul(B: &Builder<'a>,
+ LHS: &'a Value,
+ RHS: &'a Value,
+ Name: *const c_char)
+ -> &'a Value;
pub fn LLVMBuildAnd(B: &Builder<'a>,
LHS: &'a Value,
RHS: &'a Value,
use crate::base;
use crate::context::CodegenCx;
use crate::llvm;
-use crate::monomorphize::Instance;
use crate::type_of::LayoutLlvmExt;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::mir::mono::{Linkage, Visibility};
-use rustc::ty::TypeFoldable;
+use rustc::ty::{TypeFoldable, Instance};
use rustc::ty::layout::{LayoutOf, HasTyCtxt};
use rustc_codegen_ssa::traits::*;
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::ty::layout::{self, Align, LayoutOf, FnTypeExt, PointeeInfo, Size, TyLayout};
use rustc_target::abi::{FloatTy, TyLayoutMethods};
-use rustc_mir::monomorphize::item::DefPathBasedNames;
+use rustc::ty::print::obsolete::DefPathBasedNames;
use rustc_codegen_ssa::traits::*;
use std::fmt::Write;
rustc_errors = { path = "../librustc_errors" }
rustc_fs_util = { path = "../librustc_fs_util" }
rustc_incremental = { path = "../librustc_incremental" }
-rustc_mir = { path = "../librustc_mir" }
rustc_target = { path = "../librustc_target" }
@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> {
use rustc::middle::cstore::EncodedMetadata;
use rustc::middle::lang_items::StartFnLangItem;
use rustc::middle::weak_lang_items;
-use rustc::mir::mono::CodegenUnitNameBuilder;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::mir::mono::{CodegenUnitNameBuilder, CodegenUnit, MonoItem};
+use rustc::ty::{self, Ty, TyCtxt, Instance};
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt};
use rustc::ty::query::Providers;
use rustc::middle::cstore::{self, LinkagePreference};
use rustc::util::common::{time, print_time_passes_entry};
use rustc::session::config::{self, EntryFnType, Lto};
use rustc::session::Session;
-use rustc_mir::monomorphize::Instance;
-use rustc_mir::monomorphize::partitioning::{CodegenUnit, CodegenUnitExt};
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
use rustc_codegen_utils::{symbol_names_test, check_for_rustc_errors_attr};
use crate::common::{RealPredicate, TypeKind, IntPredicate};
use crate::meth;
use crate::mir;
-use crate::mono_item::MonoItem;
use crate::traits::*;
use rustc_target::abi::call::FnType;
-use rustc_mir::monomorphize;
use crate::callee;
use crate::traits::*;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, Instance};
#[derive(Copy, Clone, Debug)]
pub struct VirtualIndex(u64);
// `get_vtable` in rust_mir/interpret/traits.rs
// /////////////////////////////////////////////////////////////////////////////////////////////
let components: Vec<_> = [
- cx.get_fn(monomorphize::resolve_drop_in_place(cx.tcx(), ty)),
+ cx.get_fn(Instance::resolve_drop_in_place(cx.tcx(), ty)),
cx.const_usize(layout.size.bytes()),
cx.const_usize(layout.align.abi.bytes())
].iter().cloned().chain(methods).collect();
use rustc::middle::lang_items;
-use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable, Instance};
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
use rustc::mir::interpret::InterpError;
use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode};
use rustc_target::spec::abi::Abi;
-use rustc_mir::monomorphize;
use crate::base;
use crate::MemFlags;
use crate::common::{self, IntPredicate};
) {
let ty = location.ty(self.mir, bx.tcx()).ty;
let ty = self.monomorphize(&ty);
- let drop_fn = monomorphize::resolve_drop_in_place(bx.tcx(), ty);
+ let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty);
if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
// we don't actually need to drop anything.
use rustc::mir::interpret::ErrorHandled;
-use rustc_mir::const_eval::const_field;
use rustc::mir;
use rustc_data_structures::indexed_vec::Idx;
use rustc::ty::{self, Ty};
_ => bug!("invalid simd shuffle type: {}", c.ty),
};
let values: Vec<_> = (0..fields).map(|field| {
- let field = const_field(
- bx.tcx(),
- ty::ParamEnv::reveal_all(),
- None,
- mir::Field::new(field as usize),
- c,
+ let field = bx.tcx().const_field(
+ ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize)))
);
if let Some(prim) = field.val.try_to_scalar() {
let layout = bx.layout_of(field_ty);
-use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts};
+use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts, Instance};
use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt};
use rustc::mir::{self, Body};
use rustc::session::config::DebugInfo;
-use rustc_mir::monomorphize::Instance;
use rustc_target::abi::call::{FnType, PassMode, IgnoreMode};
use rustc_target::abi::{Variants, VariantIdx};
use crate::base;
_ => 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(
-use rustc::ty::{self, Ty, adjustment::{PointerCast}};
+use rustc::ty::{self, Ty, adjustment::{PointerCast}, Instance};
use rustc::ty::cast::{CastTy, IntTy};
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
use rustc::mir;
use crate::MemFlags;
use crate::callee;
use crate::common::{self, RealPredicate, IntPredicate};
-use rustc_mir::monomorphize;
use crate::traits::*;
mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)) => {
match operand.layout.ty.sty {
ty::Closure(def_id, substs) => {
- let instance = monomorphize::resolve_closure(
+ let instance = Instance::resolve_closure(
bx.cx().tcx(), def_id, substs, ty::ClosureKind::FnOnce);
OperandValue::Immediate(bx.cx().get_fn(instance))
}
use rustc::hir;
use rustc::mir::mono::{Linkage, Visibility};
use rustc::ty::layout::HasTyCtxt;
-use std::fmt;
use crate::base;
use crate::traits::*;
-pub use rustc::mir::mono::MonoItem;
+use rustc::mir::mono::MonoItem;
-pub use rustc_mir::monomorphize::item::MonoItemExt as BaseMonoItemExt;
+pub trait MonoItemExt<'a, 'tcx: 'a> {
+ fn define<Bx: BuilderMethods<'a, 'tcx>>(&self, cx: &'a Bx::CodegenCx);
+ fn predefine<Bx: BuilderMethods<'a, 'tcx>>(
+ &self,
+ cx: &'a Bx::CodegenCx,
+ linkage: Linkage,
+ visibility: Visibility
+ );
+ fn to_raw_string(&self) -> String;
+}
-pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
+impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
fn define<Bx: BuilderMethods<'a, 'tcx>>(&self, cx: &'a Bx::CodegenCx) {
debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}",
self.to_string(cx.tcx(), true),
self.to_raw_string(),
cx.codegen_unit().name());
- match *self.as_mono_item() {
+ match *self {
MonoItem::Static(def_id) => {
cx.codegen_static(def_id, cx.tcx().is_mutable_static(def_id));
}
debug!("symbol {}", &symbol_name);
- match *self.as_mono_item() {
+ match *self {
MonoItem::Static(def_id) => {
cx.predefine_static(def_id, linkage, visibility, &symbol_name);
}
}
fn to_raw_string(&self) -> String {
- match *self.as_mono_item() {
+ match *self {
MonoItem::Fn(instance) => {
format!("Fn({:?}, {})",
instance.def,
}
}
}
-
-impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {}
fn shl(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn lshr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn ashr(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
+ fn unchecked_sadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
+ fn unchecked_uadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
+ fn unchecked_ssub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
+ fn unchecked_usub(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
+ fn unchecked_smul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
+ fn unchecked_umul(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn and(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn or(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
fn xor(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
use crate::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, VariableKind};
use rustc::hir::def_id::CrateNum;
use rustc::mir;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, Instance};
use rustc_data_structures::indexed_vec::IndexVec;
-use rustc_mir::monomorphize::Instance;
use syntax::ast::Name;
use syntax_pos::{SourceFile, Span};
use super::BackendTypes;
use rustc::hir::def_id::DefId;
use rustc::mir::mono::{Linkage, Visibility};
-use rustc::ty;
-use rustc_mir::monomorphize::Instance;
+use rustc::ty::{self, Instance};
pub trait DeclareMethods<'tcx>: BackendTypes {
/// Declare a global value.
use super::BackendTypes;
+use rustc::mir::mono::CodegenUnit;
use rustc::session::Session;
use rustc::ty::{self, Instance, Ty};
use rustc::util::nodemap::FxHashMap;
-use rustc_mir::monomorphize::partitioning::CodegenUnit;
use std::cell::RefCell;
use std::sync::Arc;
rustc_target = { path = "../librustc_target" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_metadata = { path = "../librustc_metadata" }
-rustc_mir = { path = "../librustc_mir" }
use rustc::hir::CodegenFnAttrFlags;
use rustc::session::config::SymbolManglingVersion;
use rustc::ty::query::Providers;
-use rustc::ty::{self, TyCtxt};
-use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt};
-use rustc_mir::monomorphize::Instance;
+use rustc::ty::{self, TyCtxt, Instance};
+use rustc::mir::mono::{MonoItem, InstantiationMode};
use syntax_pos::symbol::InternedString;
use rustc::mir::interpret::{ConstValue, Scalar};
use rustc::ty::print::{PrettyPrinter, Printer, Print};
use rustc::ty::subst::{Kind, UnpackedKind};
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Instance};
use rustc::util::common::record_time;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_mir::monomorphize::Instance;
use log::debug;
'-' | ':' => 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),
use rustc::hir;
use rustc::hir::def_id::{CrateNum, DefId};
use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Instance};
use rustc::ty::print::{Printer, Print};
use rustc::ty::subst::{Kind, Subst, UnpackedKind};
use rustc_data_structures::base_n;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_mir::monomorphize::Instance;
use rustc_target::spec::abi::Abi;
use syntax::ast::{IntTy, UintTy, FloatTy};
//! paths etc in all kinds of annoying scenarios.
use rustc::hir;
-use rustc::ty::TyCtxt;
-use rustc_mir::monomorphize::Instance;
+use rustc::ty::{TyCtxt, Instance};
use syntax::symbol::{Symbol, sym};
const SYMBOL_NAME: Symbol = sym::rustc_symbol_name;
[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"
}
use rustc::hir::def::{Res, DefKind};
use rustc::hir::def_id::DefId;
use rustc::lint;
-use rustc::ty;
+use rustc::ty::{self, Ty};
use rustc::ty::adjustment;
use rustc_data_structures::fx::FxHashMap;
use lint::{LateContext, EarlyContext, LintContext, LintArray};
return;
}
- let t = cx.tables.expr_ty(&expr);
- let type_permits_lack_of_use = if t.is_unit()
- || cx.tcx.is_ty_uninhabited_from(
- cx.tcx.hir().get_module_parent_by_hir_id(expr.hir_id), t)
- {
- true
- } else {
- match t.sty {
- ty::Adt(def, _) => check_must_use(cx, def.did, s.span, "", ""),
- ty::Opaque(def, _) => {
- let mut must_use = false;
- for (predicate, _) in &cx.tcx.predicates_of(def).predicates {
- if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate {
- let trait_ref = poly_trait_predicate.skip_binder().trait_ref;
- if check_must_use(cx, trait_ref.def_id, s.span, "implementer of ", "") {
- must_use = true;
- break;
- }
- }
- }
- must_use
- }
- ty::Dynamic(binder, _) => {
- let mut must_use = false;
- for predicate in binder.skip_binder().iter() {
- if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate {
- if check_must_use(cx, trait_ref.def_id, s.span, "", " trait object") {
- must_use = true;
- break;
- }
- }
- }
- must_use
- }
- _ => false,
- }
- };
+ let ty = cx.tables.expr_ty(&expr);
+ let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "");
let mut fn_warned = false;
let mut op_warned = false;
_ => None
};
if let Some(def_id) = maybe_def_id {
- fn_warned = check_must_use(cx, def_id, s.span, "return value of ", "");
+ fn_warned = check_must_use_def(cx, def_id, s.span, "return value of ", "");
} else if type_permits_lack_of_use {
// We don't warn about unused unit or uninhabited types.
// (See https://github.com/rust-lang/rust/issues/43806 for details.)
cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
}
- fn check_must_use(
+ // Returns whether an error has been emitted (and thus another does not need to be later).
+ fn check_must_use_ty<'tcx>(
+ cx: &LateContext<'_, 'tcx>,
+ ty: Ty<'tcx>,
+ expr: &hir::Expr,
+ span: Span,
+ descr_post_path: &str,
+ ) -> bool {
+ if ty.is_unit() || cx.tcx.is_ty_uninhabited_from(
+ cx.tcx.hir().get_module_parent_by_hir_id(expr.hir_id), ty)
+ {
+ return true;
+ }
+
+ match ty.sty {
+ ty::Adt(def, _) => check_must_use_def(cx, def.did, span, "", descr_post_path),
+ ty::Opaque(def, _) => {
+ let mut has_emitted = false;
+ for (predicate, _) in &cx.tcx.predicates_of(def).predicates {
+ if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate {
+ let trait_ref = poly_trait_predicate.skip_binder().trait_ref;
+ let def_id = trait_ref.def_id;
+ if check_must_use_def(cx, def_id, span, "implementer of ", "") {
+ has_emitted = true;
+ break;
+ }
+ }
+ }
+ has_emitted
+ }
+ ty::Dynamic(binder, _) => {
+ let mut has_emitted = false;
+ for predicate in binder.skip_binder().iter() {
+ if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate {
+ let def_id = trait_ref.def_id;
+ if check_must_use_def(cx, def_id, span, "", " trait object") {
+ has_emitted = true;
+ break;
+ }
+ }
+ }
+ has_emitted
+ }
+ ty::Tuple(ref tys) => {
+ let mut has_emitted = false;
+ let spans = if let hir::ExprKind::Tup(comps) = &expr.node {
+ debug_assert_eq!(comps.len(), tys.len());
+ comps.iter().map(|e| e.span).collect()
+ } else {
+ vec![]
+ };
+ for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() {
+ let descr_post_path = &format!(" in tuple element {}", i);
+ let span = *spans.get(i).unwrap_or(&span);
+ if check_must_use_ty(cx, ty, expr, span, descr_post_path) {
+ has_emitted = true;
+ }
+ }
+ has_emitted
+ }
+ _ => false,
+ }
+ }
+
+ // Returns whether an error has been emitted (and thus another does not need to be later).
+ fn check_must_use_def(
cx: &LateContext<'_, '_>,
def_id: DefId,
- sp: Span,
+ span: Span,
descr_pre_path: &str,
descr_post_path: &str,
) -> bool {
if attr.check_name(sym::must_use) {
let msg = format!("unused {}`{}`{} that must be used",
descr_pre_path, cx.tcx.def_path_str(def_id), descr_post_path);
- let mut err = cx.struct_span_lint(UNUSED_MUST_USE, sp, &msg);
+ let mut err = cx.struct_span_lint(UNUSED_MUST_USE, span, &msg);
// check for #[must_use = "..."]
if let Some(note) = attr.value_str() {
err.note(¬e.as_str());
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;
mbcx: &'visit mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
}
+impl GatherUsedMutsVisitor<'_, '_, '_, '_> {
+ fn remove_never_initialized_mut_locals(&mut self, into: &Place<'_>) {
+ // Remove any locals that we found were initialized from the
+ // `never_initialized_mut_locals` set. At the end, the only remaining locals will
+ // be those that were never initialized - we will consider those as being used as
+ // they will either have been removed by unreachable code optimizations; or linted
+ // as unused variables.
+ if let Some(local) = into.base_local() {
+ let _ = self.never_initialized_mut_locals.remove(&local);
+ }
+ }
+}
+
impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'gcx, 'tcx> {
fn visit_terminator_kind(
&mut self,
debug!("visit_terminator_kind: kind={:?}", kind);
match &kind {
TerminatorKind::Call { destination: Some((into, _)), .. } => {
- if let Some(local) = into.base_local() {
- debug!(
- "visit_terminator_kind: kind={:?} local={:?} \
- never_initialized_mut_locals={:?}",
- kind, local, self.never_initialized_mut_locals
- );
- let _ = self.never_initialized_mut_locals.remove(&local);
- }
+ self.remove_never_initialized_mut_locals(&into);
+ },
+ TerminatorKind::DropAndReplace { location, .. } => {
+ self.remove_never_initialized_mut_locals(&location);
},
_ => {},
}
) {
match &statement.kind {
StatementKind::Assign(into, _) => {
- // Remove any locals that we found were initialized from the
- // `never_initialized_mut_locals` set. At the end, the only remaining locals will
- // be those that were never initialized - we will consider those as being used as
- // they will either have been removed by unreachable code optimizations; or linted
- // as unused variables.
if let Some(local) = into.base_local() {
debug!(
"visit_statement: statement={:?} local={:?} \
never_initialized_mut_locals={:?}",
statement, local, self.never_initialized_mut_locals
);
- let _ = self.never_initialized_mut_locals.remove(&local);
}
+ self.remove_never_initialized_mut_locals(into);
},
_ => {},
}
opt_ty_info = None;
self_arg = None;
}
+
ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&*arg.pat), self_arg)
});
///////////////////////////////////////////////////////////////////////////
/// the main entry point for building MIR for a function
-struct ArgInfo<'gcx>(Ty<'gcx>,
- Option<Span>,
- Option<&'gcx hir::Pat>,
- Option<ImplicitSelfKind>);
+struct ArgInfo<'gcx>(Ty<'gcx>, Option<Span>, Option<&'gcx hir::Pat>, Option<ImplicitSelfKind>);
fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
fn_id: hir::HirId,
.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,
// debuginfo and so that error reporting knows that this is a user
// variable. For any other pattern the pattern introduces new
// variables which will be named instead.
- let mut name = None;
- if let Some(pat) = pattern {
- match pat.node {
- hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, _)
- | hir::PatKind::Binding(hir::BindingAnnotation::Mutable, _, ident, _) => {
- name = Some(ident.name);
- }
- _ => (),
- }
- }
-
- let source_info = SourceInfo {
- scope: OUTERMOST_SOURCE_SCOPE,
- span: pattern.map_or(self.fn_span, |pat| pat.span)
+ let (name, span) = if let Some(pat) = pattern {
+ (pat.simple_ident().map(|ident| ident.name), pat.span)
+ } else {
+ (None, self.fn_span)
};
+
+ let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, span, };
self.local_decls.push(LocalDecl {
mutability: Mutability::Mut,
ty,
match *pattern.kind {
// Don't introduce extra copies for simple bindings
- PatternKind::Binding { mutability, var, mode: BindingMode::ByValue, .. } => {
+ PatternKind::Binding {
+ mutability,
+ var,
+ mode: BindingMode::ByValue,
+ subpattern: None,
+ ..
+ } => {
self.local_decls[local].mutability = mutability;
self.local_decls[local].is_user_variable =
if let Some(kind) = self_binding {
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(
}
}
-/// Projects to a field of a (variant of a) const.
+/// Extracts a field of a (variant of a) const.
// this function uses `unwrap` copiously, because an already validated constant must have valid
// fields and can thus never fail outside of compiler bugs
pub fn const_field<'a, 'tcx>(
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,
pub(crate) use self::check_match::check_match;
-use crate::const_eval::{const_field, const_variant_index};
+use crate::const_eval::const_variant_index;
use crate::hair::util::UserAnnotatedTyHelpers;
use crate::hair::constant::*;
debug!("const_to_pat: cv={:#?} id={:?}", cv, id);
let adt_subpattern = |i, variant_opt| {
let field = Field::new(i);
- let val = const_field(self.tcx, self.param_env, variant_opt, field, cv);
+ let val = crate::const_eval::const_field(
+ self.tcx, self.param_env, variant_opt, field, cv
+ );
self.const_to_pat(instance, val, id, span)
};
let adt_subpatterns = |n, variant_opt| {
use rustc::mir::CastKind;
use rustc_apfloat::Float;
-use super::{InterpretCx, Machine, PlaceTy, OpTy, ImmTy, Immediate};
+use super::{InterpretCx, Machine, PlaceTy, OpTy, Immediate};
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
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)?;
}
src: OpTy<'tcx, M::PointerTag>,
dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
+ trace!("Unsizing {:?} into {:?}", src, dest);
match (&src.layout.ty.sty, &dest.layout.ty.sty) {
(&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
(&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) |
if dst_field.layout.is_zst() {
continue;
}
- let src_field = match src.try_as_mplace() {
- Ok(mplace) => {
- let src_field = self.mplace_field(mplace, i as u64)?;
- src_field.into()
- }
- Err(..) => {
- let src_field_layout = src.layout.field(self, i)?;
- // this must be a field covering the entire thing
- assert_eq!(src.layout.fields.offset(i).bytes(), 0);
- assert_eq!(src_field_layout.size, src.layout.size);
- // just sawp out the layout
- OpTy::from(ImmTy { imm: src.to_immediate(), layout: src_field_layout })
- }
- };
+ let src_field = self.operand_field(src, i as u64)?;
if src_field.layout.ty == dst_field.layout.ty {
self.copy_op(src_field, dst_field)?;
} else {
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 => {
pub use self::validity::RefTracking;
-pub use self::intrinsics::type_name;
+pub(super) use self::intrinsics::type_name;
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.
use std::borrow::Cow;
use rustc::{mir, ty};
+use rustc::ty::Instance;
use rustc::ty::layout::{self, TyLayout, LayoutOf};
use syntax::source_map::Span;
use rustc_target::spec::abi::Abi;
let ty = place.layout.ty;
trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
- let instance = crate::monomorphize::resolve_drop_in_place(*self.tcx, ty);
+ let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
self.drop_in_place(
place,
instance,
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, Instance};
use rustc::ty::layout::{Size, Align, LayoutOf};
use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic};
// 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 = Instance::resolve_drop_in_place(*tcx, ty);
+ 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"]
providers.const_eval = const_eval::const_eval_provider;
providers.const_eval_raw = const_eval::const_eval_raw_provider;
providers.check_match = hair::pattern::check_match;
+ providers.const_field = |tcx, param_env_and_value| {
+ let (param_env, (value, field)) = param_env_and_value.into_parts();
+ const_eval::const_field(tcx, param_env, None, field, value)
+ };
+ providers.type_name = interpret::type_name;
}
__build_diagnostic_array! { librustc_mir, DIAGNOSTICS }
use rustc::mir::interpret::{AllocId, ConstValue};
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
use rustc::ty::subst::{InternalSubsts, SubstsRef};
-use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind};
+use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind, Instance};
+use rustc::ty::print::obsolete::DefPathBasedNames;
use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast};
use rustc::session::config::EntryFnType;
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::mono::{MonoItem, InstantiationMode};
+use rustc::mir::interpret::{Scalar, GlobalId, GlobalAlloc, ErrorHandled};
-use crate::monomorphize::{self, Instance};
+use crate::monomorphize;
use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
use rustc::util::common::time;
-use crate::monomorphize::item::{MonoItemExt, DefPathBasedNames, InstantiationMode};
-
use rustc_data_structures::bit_set::GrowableBitSet;
use rustc_data_structures::sync::{MTRef, MTLock, ParallelIterator, par_iter};
);
match source_ty.sty {
ty::Closure(def_id, substs) => {
- let instance = monomorphize::resolve_closure(
+ let instance = Instance::resolve_closure(
self.tcx, def_id, substs, ty::ClosureKind::FnOnce);
if should_monomorphize_locally(self.tcx, &instance) {
self.output.push(create_fn_mono_item(instance));
is_direct_call: bool,
output: &mut Vec<MonoItem<'tcx>>)
{
- let instance = monomorphize::resolve_drop_in_place(tcx, ty);
+ let instance = Instance::resolve_drop_in_place(tcx, ty);
visit_instance_use(tcx, instance, is_direct_call, output);
}
) {
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",
),
}
}
-use crate::monomorphize::Instance;
-use rustc::hir;
-use rustc::hir::def_id::{DefId, LOCAL_CRATE};
-use rustc::mir::interpret::ConstValue;
+use rustc::hir::def_id::LOCAL_CRATE;
+use rustc::mir::mono::MonoItem;
use rustc::session::config::OptLevel;
-use rustc::ty::{self, Ty, TyCtxt, Const, ClosureSubsts, GeneratorSubsts};
-use rustc::ty::subst::{SubstsRef, InternalSubsts};
-use syntax::ast;
+use rustc::ty::{self, TyCtxt, Instance};
+use rustc::ty::subst::InternalSubsts;
+use rustc::ty::print::obsolete::DefPathBasedNames;
use syntax::attr::InlineAttr;
-use std::fmt::{self, Write};
-use std::iter;
+use std::fmt;
use rustc::mir::mono::Linkage;
use syntax_pos::symbol::InternedString;
use syntax::source_map::Span;
-pub use rustc::mir::mono::MonoItem;
/// Describes how a monomorphization will be instantiated in object files.
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
self
}
}
-
-//=-----------------------------------------------------------------------------
-// MonoItem String Keys
-//=-----------------------------------------------------------------------------
-
-// The code below allows for producing a unique string key for a mono item.
-// These keys are used by the handwritten auto-tests, so they need to be
-// predictable and human-readable.
-//
-// Note: A lot of this could looks very similar to what's already in `ty::print`.
-// FIXME(eddyb) implement a custom `PrettyPrinter` for this.
-
-/// Same as `unique_type_name()` but with the result pushed onto the given
-/// `output` parameter.
-pub struct DefPathBasedNames<'a, 'tcx: 'a> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- omit_disambiguators: bool,
- omit_local_crate_name: bool,
-}
-
-impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- omit_disambiguators: bool,
- omit_local_crate_name: bool)
- -> Self {
- DefPathBasedNames {
- tcx,
- omit_disambiguators,
- omit_local_crate_name,
- }
- }
-
- // Pushes the type name of the specified type to the provided string.
- // If `debug` is true, printing normally unprintable types is allowed
- // (e.g. `ty::GeneratorWitness`). This parameter should only be set when
- // this method is being used for logging purposes (e.g. with `debug!` or `info!`)
- // When being used for codegen purposes, `debug` should be set to `false`
- // in order to catch unexpected types that should never end up in a type name.
- pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
- match t.sty {
- ty::Bool => output.push_str("bool"),
- ty::Char => output.push_str("char"),
- ty::Str => output.push_str("str"),
- ty::Never => output.push_str("!"),
- ty::Int(ast::IntTy::Isize) => output.push_str("isize"),
- ty::Int(ast::IntTy::I8) => output.push_str("i8"),
- ty::Int(ast::IntTy::I16) => output.push_str("i16"),
- ty::Int(ast::IntTy::I32) => output.push_str("i32"),
- ty::Int(ast::IntTy::I64) => output.push_str("i64"),
- ty::Int(ast::IntTy::I128) => output.push_str("i128"),
- ty::Uint(ast::UintTy::Usize) => output.push_str("usize"),
- ty::Uint(ast::UintTy::U8) => output.push_str("u8"),
- ty::Uint(ast::UintTy::U16) => output.push_str("u16"),
- ty::Uint(ast::UintTy::U32) => output.push_str("u32"),
- ty::Uint(ast::UintTy::U64) => output.push_str("u64"),
- ty::Uint(ast::UintTy::U128) => output.push_str("u128"),
- ty::Float(ast::FloatTy::F32) => output.push_str("f32"),
- ty::Float(ast::FloatTy::F64) => output.push_str("f64"),
- ty::Adt(adt_def, substs) => {
- self.push_def_path(adt_def.did, output);
- self.push_generic_params(substs, iter::empty(), output, debug);
- },
- ty::Tuple(component_types) => {
- output.push('(');
- for &component_type in component_types {
- self.push_type_name(component_type.expect_ty(), output, debug);
- output.push_str(", ");
- }
- if !component_types.is_empty() {
- output.pop();
- output.pop();
- }
- output.push(')');
- },
- ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
- output.push('*');
- match mutbl {
- hir::MutImmutable => output.push_str("const "),
- hir::MutMutable => output.push_str("mut "),
- }
-
- self.push_type_name(inner_type, output, debug);
- },
- ty::Ref(_, inner_type, mutbl) => {
- output.push('&');
- if mutbl == hir::MutMutable {
- output.push_str("mut ");
- }
-
- self.push_type_name(inner_type, output, debug);
- },
- ty::Array(inner_type, len) => {
- output.push('[');
- self.push_type_name(inner_type, output, debug);
- write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
- output.push(']');
- },
- ty::Slice(inner_type) => {
- output.push('[');
- self.push_type_name(inner_type, output, debug);
- output.push(']');
- },
- ty::Dynamic(ref trait_data, ..) => {
- if let Some(principal) = trait_data.principal() {
- self.push_def_path(principal.def_id(), output);
- self.push_generic_params(
- principal.skip_binder().substs,
- trait_data.projection_bounds(),
- output,
- debug
- );
- } else {
- output.push_str("dyn '_");
- }
- },
- ty::Foreign(did) => self.push_def_path(did, output),
- ty::FnDef(..) |
- ty::FnPtr(_) => {
- let sig = t.fn_sig(self.tcx);
- if sig.unsafety() == hir::Unsafety::Unsafe {
- output.push_str("unsafe ");
- }
-
- let abi = sig.abi();
- if abi != ::rustc_target::spec::abi::Abi::Rust {
- output.push_str("extern \"");
- output.push_str(abi.name());
- output.push_str("\" ");
- }
-
- output.push_str("fn(");
-
- let sig = self.tcx.normalize_erasing_late_bound_regions(
- ty::ParamEnv::reveal_all(),
- &sig,
- );
-
- if !sig.inputs().is_empty() {
- for ¶meter_type in sig.inputs() {
- self.push_type_name(parameter_type, output, debug);
- output.push_str(", ");
- }
- output.pop();
- output.pop();
- }
-
- if sig.c_variadic {
- if !sig.inputs().is_empty() {
- output.push_str(", ...");
- } else {
- output.push_str("...");
- }
- }
-
- output.push(')');
-
- if !sig.output().is_unit() {
- output.push_str(" -> ");
- self.push_type_name(sig.output(), output, debug);
- }
- },
- ty::Generator(def_id, GeneratorSubsts { ref substs }, _) |
- ty::Closure(def_id, ClosureSubsts { ref substs }) => {
- self.push_def_path(def_id, output);
- let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
- let substs = substs.truncate_to(self.tcx, generics);
- self.push_generic_params(substs, iter::empty(), output, debug);
- }
- ty::Error |
- ty::Bound(..) |
- ty::Infer(_) |
- ty::Placeholder(..) |
- ty::UnnormalizedProjection(..) |
- ty::Projection(..) |
- ty::Param(_) |
- ty::GeneratorWitness(_) |
- ty::Opaque(..) => {
- if debug {
- output.push_str(&format!("`{:?}`", t));
- } else {
- bug!(
- "DefPathBasedNames: trying to create type name for unexpected type: {:?}",
- t,
- );
- }
- }
- }
- }
-
- // Pushes the the name of the specified const to the provided string.
- // If `debug` is true, usually-unprintable consts (such as `Infer`) will be printed,
- // as well as the unprintable types of constants (see `push_type_name` for more details).
- pub fn push_const_name(&self, c: &Const<'tcx>, output: &mut String, debug: bool) {
- match c.val {
- ConstValue::Scalar(..) | ConstValue::Slice { .. } | ConstValue::ByRef(..) => {
- // FIXME(const_generics): we could probably do a better job here.
- write!(output, "{:?}", c).unwrap()
- }
- _ => {
- if debug {
- write!(output, "{:?}", c).unwrap()
- } else {
- bug!(
- "DefPathBasedNames: trying to create const name for unexpected const: {:?}",
- c,
- );
- }
- }
- }
- output.push_str(": ");
- self.push_type_name(c.ty, output, debug);
- }
-
- pub fn push_def_path(&self,
- def_id: DefId,
- output: &mut String) {
- let def_path = self.tcx.def_path(def_id);
-
- // some_crate::
- if !(self.omit_local_crate_name && def_id.is_local()) {
- output.push_str(&self.tcx.crate_name(def_path.krate).as_str());
- output.push_str("::");
- }
-
- // foo::bar::ItemName::
- for part in self.tcx.def_path(def_id).data {
- if self.omit_disambiguators {
- write!(output, "{}::", part.data.as_interned_str()).unwrap();
- } else {
- write!(output, "{}[{}]::",
- part.data.as_interned_str(),
- part.disambiguator).unwrap();
- }
- }
-
- // remove final "::"
- output.pop();
- output.pop();
- }
-
- fn push_generic_params<I>(
- &self,
- substs: SubstsRef<'tcx>,
- projections: I,
- output: &mut String,
- debug: bool,
- ) where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>> {
- let mut projections = projections.peekable();
- if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() {
- return;
- }
-
- output.push('<');
-
- for type_parameter in substs.types() {
- self.push_type_name(type_parameter, output, debug);
- output.push_str(", ");
- }
-
- for projection in projections {
- let projection = projection.skip_binder();
- let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str();
- output.push_str(name);
- output.push_str("=");
- self.push_type_name(projection.ty, output, debug);
- output.push_str(", ");
- }
-
- for const_parameter in substs.consts() {
- self.push_const_name(const_parameter, output, debug);
- output.push_str(", ");
- }
-
- output.pop();
- output.pop();
-
- output.push('>');
- }
-
- pub fn push_instance_as_string(&self,
- instance: Instance<'tcx>,
- output: &mut String,
- debug: bool) {
- self.push_def_path(instance.def_id(), output);
- self.push_generic_params(instance.substs, iter::empty(), output, debug);
- }
-}
-use rustc::hir::def_id::DefId;
-use rustc::middle::lang_items::DropInPlaceFnLangItem;
use rustc::traits;
use rustc::ty::adjustment::CustomCoerceUnsized;
use rustc::ty::{self, Ty, TyCtxt};
-pub use rustc::ty::Instance;
-pub use self::item::{MonoItem, MonoItemExt};
-
pub mod collector;
-pub mod item;
pub mod partitioning;
-#[inline(never)] // give this a place in the profiler
-pub fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mono_items: I)
- where I: Iterator<Item=&'a MonoItem<'tcx>>
-{
- let mut symbols: Vec<_> = mono_items.map(|mono_item| {
- (mono_item, mono_item.symbol_name(tcx))
- }).collect();
-
- symbols.sort_by_key(|sym| sym.1);
-
- for pair in symbols.windows(2) {
- let sym1 = &pair[0].1;
- let sym2 = &pair[1].1;
-
- if sym1 == sym2 {
- let mono_item1 = pair[0].0;
- let mono_item2 = pair[1].0;
-
- let span1 = mono_item1.local_span(tcx);
- let span2 = mono_item2.local_span(tcx);
-
- // Deterministically select one of the spans for error reporting
- let span = match (span1, span2) {
- (Some(span1), Some(span2)) => {
- Some(if span1.lo().0 > span2.lo().0 {
- span1
- } else {
- span2
- })
- }
- (span1, span2) => span1.or(span2),
- };
-
- let error_message = format!("symbol `{}` is already defined", sym1);
-
- if let Some(span) = span {
- tcx.sess.span_fatal(span, &error_message)
- } else {
- tcx.sess.fatal(&error_message)
- }
- }
- }
-}
-
-fn fn_once_adapter_instance<'a, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- closure_did: DefId,
- substs: ty::ClosureSubsts<'tcx>,
- ) -> Instance<'tcx> {
- debug!("fn_once_adapter_shim({:?}, {:?})",
- closure_did,
- substs);
- let fn_once = tcx.lang_items().fn_once_trait().unwrap();
- let call_once = tcx.associated_items(fn_once)
- .find(|it| it.kind == ty::AssocKind::Method)
- .unwrap().def_id;
- let def = ty::InstanceDef::ClosureOnceShim { call_once };
-
- let self_ty = tcx.mk_closure(closure_did, substs);
-
- let sig = substs.closure_sig(closure_did, tcx);
- let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
- assert_eq!(sig.inputs().len(), 1);
- let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
-
- debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
- Instance { def, substs }
-}
-
-fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind,
- trait_closure_kind: ty::ClosureKind)
- -> Result<bool, ()>
-{
- match (actual_closure_kind, trait_closure_kind) {
- (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
- (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
- (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
- // No adapter needed.
- Ok(false)
- }
- (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
- // The closure fn `llfn` is a `fn(&self, ...)`. We want a
- // `fn(&mut self, ...)`. In fact, at codegen time, these are
- // basically the same thing, so we can just return llfn.
- Ok(false)
- }
- (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
- (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
- // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
- // self, ...)`. We want a `fn(self, ...)`. We can produce
- // this by doing something like:
- //
- // fn call_once(self, ...) { call_mut(&self, ...) }
- // fn call_once(mut self, ...) { call_mut(&mut self, ...) }
- //
- // These are both the same at codegen time.
- Ok(true)
- }
- _ => Err(()),
- }
-}
-
-pub fn resolve_closure<'a, 'tcx> (
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- def_id: DefId,
- substs: ty::ClosureSubsts<'tcx>,
- requested_kind: ty::ClosureKind)
- -> Instance<'tcx>
-{
- let actual_kind = substs.closure_kind(def_id, tcx);
-
- match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
- Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
- _ => Instance::new(def_id, substs.substs)
- }
-}
-
-pub fn resolve_drop_in_place<'a, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ty: Ty<'tcx>)
- -> ty::Instance<'tcx>
-{
- let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
- let substs = tcx.intern_substs(&[ty.into()]);
- Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap()
-}
-
pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
source_ty: Ty<'tcx>,
target_ty: Ty<'tcx>)
use std::sync::Arc;
use syntax::symbol::InternedString;
-use rustc::dep_graph::{WorkProductId, WorkProduct, DepNode, DepConstructor};
-use rustc::hir::{CodegenFnAttrFlags, HirId};
+use rustc::hir::CodegenFnAttrFlags;
use rustc::hir::def::DefKind;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
-use rustc::mir::mono::{Linkage, Visibility, CodegenUnitNameBuilder};
+use rustc::mir::mono::{Linkage, Visibility, CodegenUnitNameBuilder, CodegenUnit};
use rustc::middle::exported_symbols::SymbolExportLevel;
use rustc::ty::{self, DefIdTree, TyCtxt, InstanceDef};
use rustc::ty::print::characteristic_def_id_of_type;
use rustc::ty::query::Providers;
use rustc::util::common::time;
use rustc::util::nodemap::{DefIdSet, FxHashMap, FxHashSet};
-use rustc::mir::mono::MonoItem;
+use rustc::mir::mono::{MonoItem, InstantiationMode};
use crate::monomorphize::collector::InliningMap;
use crate::monomorphize::collector::{self, MonoItemCollectionMode};
-use crate::monomorphize::item::{MonoItemExt, InstantiationMode};
-
-pub use rustc::mir::mono::CodegenUnit;
pub enum PartitioningStrategy {
/// Generates one codegen unit per source-level module.
FixedUnitCount(usize)
}
-pub trait CodegenUnitExt<'tcx> {
- fn as_codegen_unit(&self) -> &CodegenUnit<'tcx>;
-
- fn contains_item(&self, item: &MonoItem<'tcx>) -> bool {
- self.items().contains_key(item)
- }
-
- fn name<'a>(&'a self) -> &'a InternedString
- where 'tcx: 'a,
- {
- &self.as_codegen_unit().name()
- }
-
- fn items(&self) -> &FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)> {
- &self.as_codegen_unit().items()
- }
-
- fn work_product_id(&self) -> WorkProductId {
- WorkProductId::from_cgu_name(&self.name().as_str())
- }
-
- fn work_product(&self, tcx: TyCtxt<'_, '_, '_>) -> WorkProduct {
- let work_product_id = self.work_product_id();
- tcx.dep_graph
- .previous_work_product(&work_product_id)
- .unwrap_or_else(|| {
- panic!("Could not find work-product for CGU `{}`", self.name())
- })
- }
-
- fn items_in_deterministic_order<'a>(&self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>)
- -> Vec<(MonoItem<'tcx>,
- (Linkage, Visibility))> {
- // The codegen tests rely on items being process in the same order as
- // they appear in the file, so for local items, we sort by node_id first
- #[derive(PartialEq, Eq, PartialOrd, Ord)]
- pub struct ItemSortKey(Option<HirId>, ty::SymbolName);
-
- fn item_sort_key<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- item: MonoItem<'tcx>) -> ItemSortKey {
- ItemSortKey(match item {
- MonoItem::Fn(ref instance) => {
- match instance.def {
- // We only want to take HirIds of user-defined
- // instances into account. The others don't matter for
- // the codegen tests and can even make item order
- // unstable.
- InstanceDef::Item(def_id) => {
- tcx.hir().as_local_hir_id(def_id)
- }
- InstanceDef::VtableShim(..) |
- InstanceDef::Intrinsic(..) |
- InstanceDef::FnPtrShim(..) |
- InstanceDef::Virtual(..) |
- InstanceDef::ClosureOnceShim { .. } |
- InstanceDef::DropGlue(..) |
- InstanceDef::CloneShim(..) => {
- None
- }
- }
- }
- MonoItem::Static(def_id) => {
- tcx.hir().as_local_hir_id(def_id)
- }
- MonoItem::GlobalAsm(hir_id) => {
- Some(hir_id)
- }
- }, item.symbol_name(tcx))
- }
-
- let mut items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect();
- items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i));
- items
- }
-
- fn codegen_dep_node(&self, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> DepNode {
- DepNode::new(tcx, DepConstructor::CompileCodegenUnit(self.name().clone()))
- }
-}
-
-impl<'tcx> CodegenUnitExt<'tcx> for CodegenUnit<'tcx> {
- fn as_codegen_unit(&self) -> &CodegenUnit<'tcx> {
- self
- }
-}
-
// Anything we can't find a proper codegen unit for goes into this.
fn fallback_cgu_name(name_builder: &mut CodegenUnitNameBuilder<'_, '_, '_>) -> InternedString {
name_builder.build_cgu_name(LOCAL_CRATE, &["fallback"], Some("cgu"))
}
}
+#[inline(never)] // give this a place in the profiler
+fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mono_items: I)
+ where I: Iterator<Item=&'a MonoItem<'tcx>>
+{
+ let mut symbols: Vec<_> = mono_items.map(|mono_item| {
+ (mono_item, mono_item.symbol_name(tcx))
+ }).collect();
+
+ symbols.sort_by_key(|sym| sym.1);
+
+ for pair in symbols.windows(2) {
+ let sym1 = &pair[0].1;
+ let sym2 = &pair[1].1;
+
+ if sym1 == sym2 {
+ let mono_item1 = pair[0].0;
+ let mono_item2 = pair[1].0;
+
+ let span1 = mono_item1.local_span(tcx);
+ let span2 = mono_item2.local_span(tcx);
+
+ // Deterministically select one of the spans for error reporting
+ let span = match (span1, span2) {
+ (Some(span1), Some(span2)) => {
+ Some(if span1.lo().0 > span2.lo().0 {
+ span1
+ } else {
+ span2
+ })
+ }
+ (span1, span2) => span1.or(span2),
+ };
+
+ let error_message = format!("symbol `{}` is already defined", sym1);
+
+ if let Some(span) = span {
+ tcx.sess.span_fatal(span, &error_message)
+ } else {
+ tcx.sess.fatal(&error_message)
+ }
+ }
+ }
+}
+
fn collect_and_partition_mono_items<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cnum: CrateNum,
tcx.sess.abort_if_errors();
- crate::monomorphize::assert_symbols_are_distinct(tcx, items.iter());
+ assert_symbols_are_distinct(tcx, items.iter());
let strategy = if tcx.sess.opts.incremental.is_some() {
PartitioningStrategy::PerModule
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;
}
}
- fn check_trait_fn_not_async(&self, span: Span, asyncness: &IsAsync) {
+ fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
if asyncness.is_async() {
struct_span_err!(self.session, span, E0706,
"trait fns cannot be declared `async`").emit()
self.invalid_visibility(&impl_item.vis, None);
if let ImplItemKind::Method(ref sig, _) = impl_item.node {
self.check_trait_fn_not_const(sig.header.constness);
- self.check_trait_fn_not_async(impl_item.span, &sig.header.asyncness.node);
+ self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node);
}
}
}
self.no_questions_in_bounds(bounds, "supertraits", true);
for trait_item in trait_items {
if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
- self.check_trait_fn_not_async(trait_item.span, &sig.header.asyncness.node);
+ self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness.node);
self.check_trait_fn_not_const(sig.header.constness);
if block.is_none() {
self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
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;
intravisit::walk_pat(self, pat);
}
-
- fn visit_argument_source(&mut self, s: &'tcx hir::ArgSource) {
- match s {
- // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
- // a `NodeId` w/out a type, as it is only used for getting the name of the original
- // pattern for diagnostics where only an `hir::Arg` is present.
- hir::ArgSource::AsyncFn(..) => {},
- _ => intravisit::walk_argument_source(self, s),
- }
- }
}
////////////////////////////////////////////////////////////////////////////////////////////
intravisit::walk_pat(self, pattern);
}
- fn visit_argument_source(&mut self, s: &'tcx hir::ArgSource) {
- match s {
- // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
- // a `NodeId` w/out a type, as it is only used for getting the name of the original
- // pattern for diagnostics where only an `hir::Arg` is present.
- hir::ArgSource::AsyncFn(..) => {},
- _ => intravisit::walk_argument_source(self, s),
- }
- }
-
fn visit_local(&mut self, local: &'tcx hir::Local) {
if let Some(ref init) = local.init {
if self.check_expr_pat_type(init.hir_id, init.span) {
[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::ItemFn(_, ref header, ..) =>
- (FnItemRibKind, &header.asyncness.node),
- FnKind::Method(_, ref sig, _, _) =>
- (AssocItemRibKind, &sig.header.asyncness.node),
- FnKind::Closure(_) =>
- // Async closures aren't resolved through `visit_fn`-- they're
- // processed separately
- (ClosureRibKind(node_id), &IsAsync::NotAsync),
+ let rib_kind = match function_kind {
+ FnKind::ItemFn(..) => FnItemRibKind,
+ FnKind::Method(..) => AssocItemRibKind,
+ FnKind::Closure(_) => NormalRibKind,
};
// Create a value rib for the function.
// Add each argument to the rib.
let mut bindings_list = FxHashMap::default();
- let mut add_argument = |argument: &ast::Arg| {
+ for argument in &declaration.inputs {
self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
+
self.visit_ty(&argument.ty);
- debug!("(resolving function) recorded argument");
- };
- // Walk the generated async arguments if this is an `async fn`, otherwise walk the
- // normal arguments.
- if let IsAsync::Async { ref arguments, .. } = asyncness {
- for (i, a) in arguments.iter().enumerate() {
- if let Some(arg) = &a.arg {
- add_argument(&arg);
- } else {
- add_argument(&declaration.inputs[i]);
- }
- }
- } else {
- for a in &declaration.inputs { add_argument(a); }
+ debug!("(resolving function) recorded argument");
}
-
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 {
- let mut body = body.clone();
- // Insert the generated statements into the body before attempting to
- // resolve names.
- for a in arguments.iter().rev() {
- if let Some(pat_stmt) = a.pat_stmt.clone() {
- body.stmts.insert(0, pat_stmt);
- }
- body.stmts.insert(0, a.move_stmt.clone());
- }
- self.visit_block(&body);
- } else {
- self.visit_block(body);
- }
+ FnKind::ItemFn(.., body) |
+ FnKind::Method(.., body) => {
+ self.visit_block(body);
}
FnKind::Closure(body) => {
self.visit_expr(body);
}
};
- // 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.
let add_module_candidates = |module: Module<'_>, names: &mut Vec<TypoSuggestion>| {
for (&(ident, _), resolution) in module.resolutions.borrow().iter() {
if let Some(binding) = resolution.borrow().binding {
- if !ident.is_gensymed() && filter_fn(binding.res()) {
+ if filter_fn(binding.res()) {
names.push(TypoSuggestion {
candidate: ident.name,
article: binding.res().article(),
for rib in self.ribs[ns].iter().rev() {
// Locals and type parameters
for (ident, &res) in &rib.bindings {
- if !ident.is_gensymed() && filter_fn(res) {
+ if filter_fn(res) {
names.push(TypoSuggestion {
candidate: ident.name,
article: res.article(),
},
);
- if !ident.is_gensymed() && filter_fn(crate_mod) {
+ if filter_fn(crate_mod) {
Some(TypoSuggestion {
candidate: ident.name,
article: "a",
// Add primitive types to the mix
if filter_fn(Res::PrimTy(Bool)) {
names.extend(
- self.primitive_type_table.primitive_types
- .iter()
- .map(|(name, _)| {
- TypoSuggestion {
- candidate: *name,
- article: "a",
- kind: "primitive type",
- }
- })
+ self.primitive_type_table.primitive_types.iter().map(|(name, _)| {
+ TypoSuggestion {
+ candidate: *name,
+ article: "a",
+ kind: "primitive type",
+ }
+ })
)
}
} else {
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,
Ok(extend_sig(ty, text, defs, vec![]))
}
- ast::ItemKind::Fn(ref decl, ref header, ref generics, _) => {
+ ast::ItemKind::Fn(ref decl, header, ref generics, _) => {
let mut text = String::new();
if header.constness.node == ast::Constness::Const {
text.push_str("const ");
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();
}
"unchecked_shl" | "unchecked_shr" |
"rotate_left" | "rotate_right" =>
(1, vec![param(0), param(0)], param(0)),
-
+ "unchecked_add" | "unchecked_sub" | "unchecked_mul" =>
+ (1, vec![param(0), param(0)], param(0)),
"overflowing_add" | "overflowing_sub" | "overflowing_mul" =>
(1, vec![param(0), param(0)], param(0)),
"saturating_add" | "saturating_sub" =>
);
}
}
+ if let ty::RawPtr(_) = &actual.sty {
+ err.note("try using `<*const T>::as_ref()` to get a reference to the \
+ type behind the pointer: https://doc.rust-lang.org/std/\
+ primitive.pointer.html#method.as_ref");
+ }
err
}
} else {
// Don't descend into the bodies of nested closures
fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
_: hir::BodyId, _: Span, _: hir::HirId) { }
-
- fn visit_argument_source(&mut self, s: &'gcx hir::ArgSource) {
- match s {
- // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
- // a `NodeId` w/out a type, as it is only used for getting the name of the original
- // pattern for diagnostics where only an `hir::Arg` is present.
- hir::ArgSource::AsyncFn(..) => {},
- _ => intravisit::walk_argument_source(self, s),
- }
- }
}
/// When `check_fn` is invoked on a generator (i.e., a body that
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)
}
}
let ty = self.resolve(&ty, &hir_ty.span);
self.write_ty_to_tables(hir_ty.hir_id, ty);
}
-
- fn visit_argument_source(&mut self, s: &'gcx hir::ArgSource) {
- match s {
- // Don't visit the pattern in `ArgSource::AsyncFn`, it contains a pattern which has
- // a `NodeId` w/out a type, as it is only used for getting the name of the original
- // pattern for diagnostics where only an `hir::Arg` is present.
- hir::ArgSource::AsyncFn(..) => {},
- _ => intravisit::walk_argument_source(self, s),
- }
- }
}
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
}
}
- /// 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,
Node::Ty(&hir::Ty { node: hir::TyKind::Path(_), .. }) |
Node::Expr(&hir::Expr { node: ExprKind::Struct(..), .. }) |
- Node::Expr(&hir::Expr { node: ExprKind::Path(_), .. }) => {
+ Node::Expr(&hir::Expr { node: ExprKind::Path(_), .. }) |
+ Node::TraitRef(..) => {
let path = match parent_node {
- Node::Ty(&hir::Ty { node: hir::TyKind::Path(ref path), .. }) |
- Node::Expr(&hir::Expr { node: ExprKind::Path(ref path), .. }) => {
- path
+ Node::Ty(&hir::Ty {
+ node: hir::TyKind::Path(QPath::Resolved(_, ref path)),
+ ..
+ })
+ | Node::Expr(&hir::Expr {
+ node: ExprKind::Path(QPath::Resolved(_, ref path)),
+ ..
+ }) => {
+ Some(&**path)
}
Node::Expr(&hir::Expr { node: ExprKind::Struct(ref path, ..), .. }) => {
- &*path
+ if let QPath::Resolved(_, ref path) = **path {
+ Some(&**path)
+ } else {
+ None
+ }
}
- _ => unreachable!(),
+ Node::TraitRef(&hir::TraitRef { ref path, .. }) => Some(path),
+ _ => None,
};
- match path {
- QPath::Resolved(_, ref path) => {
- let arg_index = path.segments.iter()
- .filter_map(|seg| seg.args.as_ref())
- .map(|generic_args| generic_args.args.as_ref())
- .find_map(|args| {
- args.iter()
- .filter(|arg| arg.is_const())
- .enumerate()
- .filter(|(_, arg)| arg.id() == hir_id)
- .map(|(index, _)| index)
- .next()
- })
- .or_else(|| {
- if !fail {
- None
- } else {
- bug!("no arg matching AnonConst in path")
- }
- })?;
-
- // We've encountered an `AnonConst` in some path, so we need to
- // figure out which generic parameter it corresponds to and return
- // the relevant type.
- let generics = match path.res {
- Res::Def(DefKind::Ctor(..), def_id) =>
- tcx.generics_of(tcx.parent(def_id).unwrap()),
- Res::Def(_, def_id) =>
- tcx.generics_of(def_id),
- Res::Err =>
- return Some(tcx.types.err),
- _ if !fail =>
- return None,
- x => {
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!(
- "unexpected const parent path def {:?}", x
- ),
- );
- return Some(tcx.types.err);
+ if let Some(path) = path {
+ let arg_index = path.segments.iter()
+ .filter_map(|seg| seg.args.as_ref())
+ .map(|generic_args| generic_args.args.as_ref())
+ .find_map(|args| {
+ args.iter()
+ .filter(|arg| arg.is_const())
+ .enumerate()
+ .filter(|(_, arg)| arg.id() == hir_id)
+ .map(|(index, _)| index)
+ .next()
+ })
+ .or_else(|| {
+ if !fail {
+ None
+ } else {
+ bug!("no arg matching AnonConst in path")
}
- };
-
- generics.params.iter()
- .filter(|param| {
- if let ty::GenericParamDefKind::Const = param.kind {
- true
- } else {
- false
- }
- })
- .nth(arg_index)
- .map(|param| tcx.type_of(param.def_id))
- // This is no generic parameter associated with the arg. This is
- // probably from an extra arg where one is not needed.
- .unwrap_or(tcx.types.err)
- }
- x => {
- if !fail {
- return None;
+ })?;
+
+ // We've encountered an `AnonConst` in some path, so we need to
+ // figure out which generic parameter it corresponds to and return
+ // the relevant type.
+ let generics = match path.res {
+ Res::Def(DefKind::Ctor(..), def_id) => {
+ tcx.generics_of(tcx.parent(def_id).unwrap())
}
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!(
- "unexpected const parent path {:?}", x
- ),
- );
- tcx.types.err
+ Res::Def(_, def_id) => tcx.generics_of(def_id),
+ Res::Err => return Some(tcx.types.err),
+ _ if !fail => return None,
+ res => {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ &format!(
+ "unexpected const parent path def {:?}",
+ res,
+ ),
+ );
+ return Some(tcx.types.err);
+ }
+ };
+
+ generics.params.iter()
+ .filter(|param| {
+ if let ty::GenericParamDefKind::Const = param.kind {
+ true
+ } else {
+ false
+ }
+ })
+ .nth(arg_index)
+ .map(|param| tcx.type_of(param.def_id))
+ // This is no generic parameter associated with the arg. This is
+ // probably from an extra arg where one is not needed.
+ .unwrap_or(tcx.types.err)
+ } else {
+ if !fail {
+ return None;
}
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ &format!(
+ "unexpected const parent path {:?}",
+ parent_node,
+ ),
+ );
+ return Some(tcx.types.err);
}
}
```
"##,
+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! {
Arguments {
values: self.0.iter().enumerate().map(|(i, ty)| {
Argument {
- name: name_from_pat(&body.arguments[i].original_pat()),
+ name: name_from_pat(&body.arguments[i].pat),
type_: ty.clean(cx),
}
}).collect()
use std::fmt;
use rustc::hir::def_id::DefId;
+use rustc::util::nodemap::FxHashSet;
use rustc_target::spec::abi::Abi;
use rustc::hir;
impl<'a> fmt::Display for GenericBounds<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut bounds_dup = FxHashSet::default();
let &GenericBounds(bounds) = self;
- for (i, bound) in bounds.iter().enumerate() {
+
+ for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(b.to_string())).enumerate() {
if i > 0 {
f.write_str(" + ")?;
}
clause.push_str(&format!("{}: {}", ty, GenericBounds(bounds)));
}
}
- &clean::WherePredicate::RegionPredicate { ref lifetime,
- ref bounds } => {
- clause.push_str(&format!("{}: ", lifetime));
- for (i, lifetime) in bounds.iter().enumerate() {
- if i > 0 {
- clause.push_str(" + ");
- }
-
- clause.push_str(&lifetime.to_string());
- }
+ &clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => {
+ clause.push_str(&format!("{}: {}",
+ lifetime,
+ bounds.iter()
+ .map(|b| b.to_string())
+ .collect::<Vec<_>>()
+ .join(" + ")));
}
&clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => {
if f.alternate() {
}
}
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]
pub id: NodeId,
pub span: Span,
pub attrs: ThinVec<Attribute>,
- /// Origin of this local variable.
- pub source: LocalSource,
-}
-
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
-pub enum LocalSource {
- /// Local was parsed from source.
- Normal,
- /// Within `ast::IsAsync::Async`, a local is generated that will contain the moved arguments
- /// of an `async fn`.
- AsyncFn,
}
/// An arm of a 'match'.
pub ty: P<Ty>,
pub pat: P<Pat>,
pub id: NodeId,
- pub source: ArgSource,
-}
-
-/// The source of an argument in a function header.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum ArgSource {
- /// Argument as written by the user.
- Normal,
- /// Argument from `async fn` lowering, contains the original binding pattern.
- AsyncFn(P<Pat>),
}
/// Alternative representation for `Arg`s describing `self` parameter of methods.
}),
ty,
id: DUMMY_NODE_ID,
- source: ArgSource::Normal,
};
match eself.node {
SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty),
Normal,
}
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct AsyncArgument {
- /// `__arg0`
- pub ident: Ident,
- /// `__arg0: <ty>` argument to replace existing function argument `<pat>: <ty>`. Only if
- /// argument is not a simple binding.
- pub arg: Option<Arg>,
- /// `let __arg0 = __arg0;` statement to be inserted at the start of the block.
- pub move_stmt: Stmt,
- /// `let <pat> = __arg0;` statement to be inserted at the start of the block, after matching
- /// move statement. Only if argument is not a simple binding.
- pub pat_stmt: Option<Stmt>,
-}
-
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
pub enum IsAsync {
Async {
closure_id: NodeId,
return_impl_trait_id: NodeId,
- /// This field stores the arguments and statements that are used in HIR lowering to
- /// ensure that `async fn` arguments are dropped at the correct time.
- ///
- /// The argument and statements here are generated at parse time as they are required in
- /// both the hir lowering, def collection and name resolution and this stops them needing
- /// to be created in each place.
- arguments: Vec<AsyncArgument>,
},
NotAsync,
}
impl IsAsync {
- pub fn is_async(&self) -> bool {
- if let IsAsync::Async { .. } = *self {
+ pub fn is_async(self) -> bool {
+ if let IsAsync::Async { .. } = self {
true
} else {
false
}
/// In ths case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
- pub fn opt_return_id(&self) -> Option<NodeId> {
+ pub fn opt_return_id(self) -> Option<NodeId> {
match self {
IsAsync::Async {
return_impl_trait_id,
..
- } => Some(*return_impl_trait_id),
+ } => Some(return_impl_trait_id),
IsAsync::NotAsync => None,
}
}
///
/// All the information between the visibility and the name of the function is
/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
pub struct FnHeader {
pub unsafety: Unsafety,
pub asyncness: Spanned<IsAsync>,
}
/// 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,
id: ast::DUMMY_NODE_ID,
span: sp,
attrs: ThinVec::new(),
- source: ast::LocalSource::Normal,
});
ast::Stmt {
id: ast::DUMMY_NODE_ID,
id: ast::DUMMY_NODE_ID,
span: sp,
attrs: ThinVec::new(),
- source: ast::LocalSource::Normal,
});
ast::Stmt {
id: ast::DUMMY_NODE_ID,
id: ast::DUMMY_NODE_ID,
span,
attrs: ThinVec::new(),
- source: ast::LocalSource::Normal,
});
ast::Stmt {
id: ast::DUMMY_NODE_ID,
ast::Arg {
ty,
pat: arg_pat,
- id: ast::DUMMY_NODE_ID,
- source: ast::ArgSource::Normal,
+ id: ast::DUMMY_NODE_ID
}
}
fn remove(&mut self, id: ast::NodeId) -> AstFragment {
self.expanded_fragments.remove(&id).unwrap()
}
-
- fn next_id(&mut self, id: &mut ast::NodeId) {
- if self.monotonic {
- assert_eq!(*id, ast::DUMMY_NODE_ID);
- *id = self.cx.resolver.next_node_id()
- }
- }
}
impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
noop_visit_block(block, self);
for stmt in block.stmts.iter_mut() {
- self.next_id(&mut stmt.id);
- }
- }
-
- fn visit_asyncness(&mut self, a: &mut ast::IsAsync) {
- noop_visit_asyncness(a, self);
-
- if let ast::IsAsync::Async { ref mut arguments, .. } = a {
- for argument in arguments.iter_mut() {
- self.next_id(&mut argument.move_stmt.id);
- if let Some(ref mut pat_stmt) = &mut argument.pat_stmt {
- self.next_id(&mut pat_stmt.id);
- }
+ if self.monotonic {
+ assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
+ stmt.id = self.cx.resolver.next_node_id();
}
}
}
noop_visit_local(l, self);
}
- fn visit_local_source(&mut self, l: &mut LocalSource) {
- noop_visit_local_source(l, self);
- }
-
fn visit_mac(&mut self, _mac: &mut Mac) {
panic!("visit_mac disabled by default");
// N.B., see note about macros above. If you really want a visitor that
noop_visit_arg(a, self);
}
- fn visit_arg_source(&mut self, a: &mut ArgSource) {
- noop_visit_arg_source(a, self);
- }
-
fn visit_generics(&mut self, generics: &mut Generics) {
noop_visit_generics(generics, self);
}
}
pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
- let Local { id, pat, ty, init, span, attrs, source } = local.deref_mut();
+ let Local { id, pat, ty, init, span, attrs } = local.deref_mut();
vis.visit_id(id);
vis.visit_pat(pat);
visit_opt(ty, |ty| vis.visit_ty(ty));
visit_opt(init, |init| vis.visit_expr(init));
vis.visit_span(span);
visit_thin_attrs(attrs, vis);
- vis.visit_local_source(source);
-}
-
-pub fn noop_visit_local_source<T: MutVisitor>(_local_source: &mut LocalSource, _vis: &mut T) {
}
pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
vis.visit_span(span);
}
-pub fn noop_visit_arg<T: MutVisitor>(Arg { id, pat, ty, source }: &mut Arg, vis: &mut T) {
+pub fn noop_visit_arg<T: MutVisitor>(Arg { id, pat, ty }: &mut Arg, vis: &mut T) {
vis.visit_id(id);
vis.visit_pat(pat);
vis.visit_ty(ty);
- vis.visit_arg_source(source);
-}
-
-pub fn noop_visit_arg_source<T: MutVisitor>(source: &mut ArgSource, vis: &mut T) {
- match source {
- ArgSource::Normal => {},
- ArgSource::AsyncFn(pat) => vis.visit_pat(pat),
- }
}
pub fn noop_visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) {
pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T) {
match asyncness {
- IsAsync::Async { closure_id, return_impl_trait_id, ref mut arguments } => {
+ IsAsync::Async { closure_id, return_impl_trait_id } => {
vis.visit_id(closure_id);
vis.visit_id(return_impl_trait_id);
- for AsyncArgument { ident, arg, pat_stmt, move_stmt } in arguments.iter_mut() {
- vis.visit_ident(ident);
- if let Some(arg) = arg {
- vis.visit_arg(arg);
- }
- visit_clobber(move_stmt, |stmt| {
- vis.flat_map_stmt(stmt)
- .expect_one("expected visitor to produce exactly one item")
- });
- visit_opt(pat_stmt, |stmt| {
- visit_clobber(stmt, |stmt| {
- vis.flat_map_stmt(stmt)
- .expect_one("expected visitor to produce exactly one item")
- })
- });
- }
}
IsAsync::NotAsync => {}
}
-use crate::ast;
use crate::ast::{
- BlockCheckMode, BinOpKind, Expr, ExprKind, Item, ItemKind, Pat, PatKind, PathSegment, QSelf,
- Ty, TyKind, VariantData,
+ self, Arg, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind,
+ Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, VariantData,
};
use crate::parse::{SeqSep, token, PResult, Parser};
use crate::parse::parser::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType};
use crate::ThinVec;
use crate::util::parser::AssocOp;
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use rustc_data_structures::fx::FxHashSet;
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
use log::{debug, trace};
+/// Creates a placeholder argument.
+crate fn dummy_arg(ident: Ident) -> Arg {
+ let pat = P(Pat {
+ id: ast::DUMMY_NODE_ID,
+ node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None),
+ span: ident.span,
+ });
+ let ty = Ty {
+ node: TyKind::Err,
+ span: ident.span,
+ id: ast::DUMMY_NODE_ID
+ };
+ Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID }
+}
+
pub enum Error {
FileNotFoundForModule {
mod_name: String,
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",
pat: P<ast::Pat>,
require_name: bool,
is_trait_item: bool,
- ) {
+ ) -> Option<Ident> {
// If we find a pattern followed by an identifier, it could be an (incorrect)
// C-style parameter declaration.
if self.check_ident() && self.look_ahead(1, |t| {
*t == token::Comma || *t == token::CloseDelim(token::Paren)
- }) {
+ }) { // `fn foo(String s) {}`
let ident = self.parse_ident().unwrap();
let span = pat.span.with_hi(ident.span.hi());
String::from("<identifier>: <type>"),
Applicability::HasPlaceholders,
);
- } else if require_name && is_trait_item {
- if let PatKind::Ident(_, ident, _) = pat.node {
+ return Some(ident);
+ } else if let PatKind::Ident(_, ident, _) = pat.node {
+ if require_name && (
+ is_trait_item ||
+ self.token == token::Comma ||
+ self.token == token::CloseDelim(token::Paren)
+ ) { // `fn foo(a, b) {}` or `fn foo(usize, usize) {}`
err.span_suggestion(
pat.span,
- "explicitly ignore parameter",
+ "if this was a parameter name, give it a type",
+ format!("{}: TypeName", ident),
+ Applicability::HasPlaceholders,
+ );
+ err.span_suggestion(
+ pat.span,
+ "if this is a type, explicitly ignore the parameter name",
format!("_: {}", ident),
Applicability::MachineApplicable,
);
+ err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
+ return Some(ident);
}
-
- err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
}
+ None
}
crate fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
err.span_label(span, "expected expression");
err
}
+
+ /// Replace duplicated recovered arguments with `_` pattern to avoid unecessary errors.
+ ///
+ /// This is necessary because at this point we don't know whether we parsed a function with
+ /// anonymous arguments or a function with names but no types. In order to minimize
+ /// unecessary errors, we assume the arguments are in the shape of `fn foo(a, b, c)` where
+ /// the arguments are *names* (so we don't emit errors about not being able to find `b` in
+ /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`,
+ /// we deduplicate them to not complain about duplicated argument names.
+ crate fn deduplicate_recovered_arg_names(&self, fn_inputs: &mut Vec<Arg>) {
+ let mut seen_inputs = FxHashSet::default();
+ for input in fn_inputs.iter_mut() {
+ let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = (
+ &input.pat.node, &input.ty.node,
+ ) {
+ Some(*ident)
+ } else {
+ None
+ };
+ if let Some(ident) = opt_ident {
+ if seen_inputs.contains(&ident) {
+ input.pat.node = PatKind::Wild;
+ }
+ seen_inputs.insert(ident);
+ }
+ }
+ }
}
// ignore-tidy-filelength
-use crate::ast::{AngleBracketedArgs, AsyncArgument, ParenthesizedArgs, AttrStyle, BareFnTy};
+use crate::ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy};
use crate::ast::{GenericBound, TraitBoundModifier};
use crate::ast::Unsafety;
-use crate::ast::{Mod, AnonConst, Arg, ArgSource, Arm, Guard, Attribute, BindingMode, TraitItemKind};
+use crate::ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind};
use crate::ast::Block;
use crate::ast::{BlockCheckMode, CaptureBy, Movability};
use crate::ast::{Constness, Crate};
use crate::ast::GenericArg;
use crate::ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind};
use crate::ast::{Label, Lifetime};
-use crate::ast::{Local, LocalSource};
+use crate::ast::Local;
use crate::ast::MacStmtStyle;
use crate::ast::{Mac, Mac_, MacDelimiter};
use crate::ast::{MutTy, Mutability};
use crate::ThinVec;
use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
use crate::symbol::{kw, sym, Symbol};
-use crate::parse::diagnostics::Error;
+use crate::parse::diagnostics::{Error, dummy_arg};
use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError};
use rustc_target::spec::abi::{self, Abi};
-use syntax_pos::{Span, BytePos, DUMMY_SP, FileName, hygiene::CompilerDesugaringKind};
+use syntax_pos::{Span, BytePos, DUMMY_SP, FileName};
use log::debug;
use std::borrow::Cow;
}
}
-/// Creates a placeholder argument.
-fn dummy_arg(span: Span) -> Arg {
- let ident = Ident::new(kw::Invalid, span);
- let pat = P(Pat {
- id: ast::DUMMY_NODE_ID,
- node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None),
- span,
- });
- let ty = Ty {
- node: TyKind::Err,
- span,
- id: ast::DUMMY_NODE_ID
- };
- Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Normal }
-}
-
#[derive(Copy, Clone, Debug)]
crate enum TokenExpectType {
Expect,
IsAsync::Async {
closure_id: ast::DUMMY_NODE_ID,
return_impl_trait_id: ast::DUMMY_NODE_ID,
- arguments: Vec::new(),
}
} else {
IsAsync::NotAsync
// trait item macro.
(Ident::invalid(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
} else {
- let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?;
+ let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
- let mut decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| {
+ let decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| {
// This is somewhat dubious; We don't want to allow
// argument names to be left off if there is a
// definition...
p.parse_arg_general(p.span.rust_2018(), true, false)
})?;
generics.where_clause = self.parse_where_clause()?;
- self.construct_async_arguments(&mut asyncness, &mut decl);
let sig = ast::MethodSig {
header: FnHeader {
let pat = self.parse_pat(Some("argument name"))?;
if let Err(mut err) = self.expect(&token::Colon) {
- self.argument_without_type(&mut err, pat, require_name, is_trait_item);
- return Err(err);
+ if let Some(ident) = self.argument_without_type(
+ &mut err,
+ pat,
+ require_name,
+ is_trait_item,
+ ) {
+ err.emit();
+ return Ok(dummy_arg(ident));
+ } else {
+ return Err(err);
+ }
}
self.eat_incorrect_doc_comment("a method argument's type");
}
};
- Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Normal })
+ Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID })
}
/// Parses an argument in a lambda header (e.g., `|arg, arg|`).
Ok(Arg {
ty: t,
pat,
- id: ast::DUMMY_NODE_ID,
- source: ast::ArgSource::Normal,
+ id: ast::DUMMY_NODE_ID
})
}
id: ast::DUMMY_NODE_ID,
span: lo.to(hi),
attrs,
- source: LocalSource::Normal,
}))
}
/// 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.
// FIXME(const_generics): to distinguish between idents for types and consts,
// we should introduce a GenericArg::Ident in the AST and distinguish when
// lowering to the HIR. For now, idents for const args are not permitted.
- return Err(
- self.fatal("identifiers may currently not be used for const generics")
- );
+ if self.token.is_keyword(kw::True) || self.token.is_keyword(kw::False) {
+ self.parse_literal_maybe_minus()?
+ } else {
+ return Err(
+ self.fatal("identifiers may currently not be used for const generics")
+ );
+ }
} else {
self.parse_literal_maybe_minus()?
};
p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
// Create a placeholder argument for proper arg count (issue #34264).
let span = lo.to(p.prev_span);
- Ok(Some(dummy_arg(span)))
+ Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
}
}
}
// Parse the rest of the function parameter list.
let sep = SeqSep::trailing_allowed(token::Comma);
- let (fn_inputs, recovered) = if let Some(self_arg) = self_arg {
+ let (mut fn_inputs, recovered) = if let Some(self_arg) = self_arg {
if self.check(&token::CloseDelim(token::Paren)) {
(vec![self_arg], false)
} else if self.eat(&token::Comma) {
// Parse closing paren and return type.
self.expect(&token::CloseDelim(token::Paren))?;
}
+ // Replace duplicated recovered arguments with `_` pattern to avoid unecessary errors.
+ self.deduplicate_recovered_arg_names(&mut fn_inputs);
+
Ok(P(FnDecl {
inputs: fn_inputs,
output: self.parse_ret_ty(true)?,
/// Parses an item-position function declaration.
fn parse_item_fn(&mut self,
unsafety: Unsafety,
- mut asyncness: Spanned<IsAsync>,
+ asyncness: Spanned<IsAsync>,
constness: Spanned<Constness>,
abi: Abi)
-> PResult<'a, ItemInfo> {
let (ident, mut generics) = self.parse_fn_header()?;
let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe;
- let mut decl = self.parse_fn_decl(allow_c_variadic)?;
+ let decl = self.parse_fn_decl(allow_c_variadic)?;
generics.where_clause = self.parse_where_clause()?;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
- self.construct_async_arguments(&mut asyncness, &mut decl);
let header = FnHeader { unsafety, asyncness, constness, abi };
Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs)))
}
Ok((Ident::invalid(), vec![], ast::Generics::default(),
ast::ImplItemKind::Macro(mac)))
} else {
- let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?;
+ let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
- let mut decl = self.parse_fn_decl_with_self(|p| {
+ let decl = self.parse_fn_decl_with_self(|p| {
p.parse_arg_general(true, true, false)
})?;
generics.where_clause = self.parse_where_clause()?;
- self.construct_async_arguments(&mut asyncness, &mut decl);
*at_end = true;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
let header = ast::FnHeader { abi, unsafety, constness, asyncness };
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,
+ }),
+ 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])
Applicability::MaybeIncorrect,
).emit();
}
-
- /// When lowering a `async fn` to the HIR, we need to move all of the arguments of the function
- /// into the generated closure so that they are dropped when the future is polled and not when
- /// it is created.
- ///
- /// The arguments of the function are replaced in HIR lowering with the arguments created by
- /// this function and the statements created here are inserted at the top of the closure body.
- fn construct_async_arguments(&mut self, asyncness: &mut Spanned<IsAsync>, decl: &mut FnDecl) {
- // FIXME(davidtwco): This function should really live in the HIR lowering but because
- // the types constructed here need to be used in parts of resolve so that the correct
- // locals are considered upvars, it is currently easier for it to live here in the parser,
- // where it can be constructed once.
- if let IsAsync::Async { ref mut arguments, .. } = asyncness.node {
- for (index, input) in decl.inputs.iter_mut().enumerate() {
- let id = ast::DUMMY_NODE_ID;
- let span = input.pat.span;
- let desugared_span = self.sess.source_map()
- .mark_span_with_reason(CompilerDesugaringKind::Async, span, None);
-
- // Construct a name for our temporary argument.
- let name = format!("__arg{}", index);
- let ident = Ident::from_str(&name).gensym();
-
- // Check if this is a ident pattern, if so, we can optimize and avoid adding a
- // `let <pat> = __argN;` statement, instead just adding a `let <pat> = <pat>;`
- // statement.
- let (binding_mode, ident, is_simple_pattern) = match input.pat.node {
- PatKind::Ident(binding_mode @ BindingMode::ByValue(_), ident, _) => {
- // Simple patterns like this don't have a generated argument, but they are
- // moved into the closure with a statement, so any `mut` bindings on the
- // argument will be unused. This binding mode can't be removed, because
- // this would affect the input to procedural macros, but they can have
- // their span marked as being the result of a compiler desugaring so
- // that they aren't linted against.
- input.pat.span = desugared_span;
-
- (binding_mode, ident, true)
- }
- _ => (BindingMode::ByValue(Mutability::Mutable), ident, false),
- };
-
- // Construct an argument representing `__argN: <ty>` to replace the argument of the
- // async function if it isn't a simple pattern.
- let arg = if is_simple_pattern {
- None
- } else {
- Some(Arg {
- ty: input.ty.clone(),
- id,
- pat: P(Pat {
- id,
- node: PatKind::Ident(
- BindingMode::ByValue(Mutability::Immutable), ident, None,
- ),
- span: desugared_span,
- }),
- source: ArgSource::AsyncFn(input.pat.clone()),
- })
- };
-
- // Construct a `let __argN = __argN;` statement to insert at the top of the
- // async closure. This makes sure that the argument is captured by the closure and
- // that the drop order is correct.
- let move_local = Local {
- pat: P(Pat {
- id,
- node: PatKind::Ident(binding_mode, ident, None),
- span: desugared_span,
- }),
- // We explicitly do not specify the type for this statement. When the user's
- // argument type is `impl Trait` then this would require the
- // `impl_trait_in_bindings` feature to also be present for that same type to
- // be valid in this binding. At the time of writing (13 Mar 19),
- // `impl_trait_in_bindings` is not stable.
- ty: None,
- init: Some(P(Expr {
- id,
- node: ExprKind::Path(None, ast::Path {
- span,
- segments: vec![PathSegment { ident, id, args: None }],
- }),
- span,
- attrs: ThinVec::new(),
- })),
- id,
- span,
- attrs: ThinVec::new(),
- source: LocalSource::AsyncFn,
- };
-
- // Construct a `let <pat> = __argN;` statement to insert at the top of the
- // async closure if this isn't a simple pattern.
- let pat_stmt = if is_simple_pattern {
- None
- } else {
- Some(Stmt {
- id,
- node: StmtKind::Local(P(Local {
- pat: input.pat.clone(),
- ..move_local.clone()
- })),
- span,
- })
- };
-
- let move_stmt = Stmt { id, node: StmtKind::Local(P(move_local)), span };
- arguments.push(AsyncArgument { ident, arg, pat_stmt, move_stmt });
- }
- }
- }
}
pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, handler: &errors::Handler) {
}
pub fn fun_to_string(decl: &ast::FnDecl,
- header: &ast::FnHeader,
+ header: ast::FnHeader,
name: ast::Ident,
generics: &ast::Generics)
-> String {
match item.node {
ast::ForeignItemKind::Fn(ref decl, ref generics) => {
self.head("")?;
- self.print_fn(decl, &ast::FnHeader::default(),
+ self.print_fn(decl, ast::FnHeader::default(),
Some(item.ident),
generics, &item.vis)?;
self.end()?; // end head-ibox
self.s.word(";")?;
self.end()?; // end the outer cbox
}
- ast::ItemKind::Fn(ref decl, ref header, ref param_names, ref body) => {
+ ast::ItemKind::Fn(ref decl, header, ref param_names, ref body) => {
self.head("")?;
self.print_fn(
decl,
vis: &ast::Visibility)
-> io::Result<()> {
self.print_fn(&m.decl,
- &m.header,
+ m.header,
Some(ident),
&generics,
vis)
self.bclose_(expr.span, INDENT_UNIT)?;
}
ast::ExprKind::Closure(
- capture_clause, ref asyncness, movability, ref decl, ref body, _) => {
+ capture_clause, asyncness, movability, ref decl, ref body, _) => {
self.print_movability(movability)?;
self.print_asyncness(asyncness)?;
self.print_capture_clause(capture_clause)?;
pub fn print_fn(&mut self,
decl: &ast::FnDecl,
- header: &ast::FnHeader,
+ header: ast::FnHeader,
name: Option<ast::Ident>,
generics: &ast::Generics,
vis: &ast::Visibility) -> io::Result<()> {
}
}
- pub fn print_asyncness(&mut self, asyncness: &ast::IsAsync) -> io::Result<()> {
+ pub fn print_asyncness(&mut self, asyncness: ast::IsAsync)
+ -> io::Result<()> {
if asyncness.is_async() {
self.word_nbsp("async")?;
}
span: syntax_pos::DUMMY_SP,
};
self.print_fn(decl,
- &ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() },
+ ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() },
name,
&generics,
&source_map::dummy_spanned(ast::VisibilityKind::Inherited))?;
}
pub fn print_fn_header_info(&mut self,
- header: &ast::FnHeader,
+ header: ast::FnHeader,
vis: &ast::Visibility) -> io::Result<()> {
self.s.word(visibility_qualified(vis, ""))?;
ast::Constness::Const => self.word_nbsp("const")?
}
- self.print_asyncness(&header.asyncness.node)?;
+ self.print_asyncness(header.asyncness.node)?;
self.print_unsafety(header.unsafety)?;
if header.abi != Abi::Rust {
assert_eq!(
fun_to_string(
&decl,
- &ast::FnHeader {
+ ast::FnHeader {
unsafety: ast::Unsafety::Normal,
constness: source_map::dummy_spanned(ast::Constness::NotConst),
asyncness: source_map::dummy_spanned(ast::IsAsync::NotAsync),
None
}
-
- /// Reuses the span but adds information like the kind of the desugaring and features that are
- /// allowed inside this span.
- pub fn mark_span_with_reason(
- &self,
- reason: hygiene::CompilerDesugaringKind,
- span: Span,
- allow_internal_unstable: Option<Lrc<[symbol::Symbol]>>,
- ) -> Span {
- let mark = Mark::fresh(Mark::root());
- mark.set_expn_info(ExpnInfo {
- call_site: span,
- def_site: Some(span),
- format: CompilerDesugaring(reason),
- allow_internal_unstable,
- allow_internal_unsafe: false,
- local_inner_macros: false,
- edition: edition::Edition::from_session(),
- });
- span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
- }
}
impl SourceMapper for SourceMap {
pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) {
for argument in &function_declaration.inputs {
visitor.visit_pat(&argument.pat);
- if let ArgSource::AsyncFn(pat) = &argument.source {
- visitor.visit_pat(pat);
- }
visitor.visit_ty(&argument.ty)
}
visitor.visit_fn_ret_ty(&function_declaration.output)
id: ast::DUMMY_NODE_ID,
span: sp,
attrs: ThinVec::new(),
- source: ast::LocalSource::Normal,
});
ast::Stmt {
id: ast::DUMMY_NODE_ID,
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
--- /dev/null
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::*;
+
+// CHECK-LABEL: @unchecked_add_signed
+#[no_mangle]
+pub unsafe fn unchecked_add_signed(a: i32, b: i32) -> i32 {
+ // CHECK: add nsw
+ unchecked_add(a, b)
+}
+
+// CHECK-LABEL: @unchecked_add_unsigned
+#[no_mangle]
+pub unsafe fn unchecked_add_unsigned(a: u32, b: u32) -> u32 {
+ // CHECK: add nuw
+ unchecked_add(a, b)
+}
+
+// CHECK-LABEL: @unchecked_sub_signed
+#[no_mangle]
+pub unsafe fn unchecked_sub_signed(a: i32, b: i32) -> i32 {
+ // CHECK: sub nsw
+ unchecked_sub(a, b)
+}
+
+// CHECK-LABEL: @unchecked_sub_unsigned
+#[no_mangle]
+pub unsafe fn unchecked_sub_unsigned(a: u32, b: u32) -> u32 {
+ // CHECK: sub nuw
+ unchecked_sub(a, b)
+}
+
+// CHECK-LABEL: @unchecked_mul_signed
+#[no_mangle]
+pub unsafe fn unchecked_mul_signed(a: i32, b: i32) -> i32 {
+ // CHECK: mul nsw
+ unchecked_mul(a, b)
+}
+
+// CHECK-LABEL: @unchecked_mul_unsigned
+#[no_mangle]
+pub unsafe fn unchecked_mul_unsigned(a: u32, b: u32) -> u32 {
+ // CHECK: mul nuw
+ unchecked_mul(a, b)
+}
// 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() {}
}
fn foo(i32); //~ expected one of `:` or `@`, found `)`
fn bar_with_default_impl(String, String) {}
- //~^ ERROR expected one of `:` or `@`, found `,`
+ //~^ ERROR expected one of `:`
+ //~| ERROR expected one of `:`
+
+ // do not complain about missing `b`
+ fn baz(a:usize, b, c: usize) -> usize { //~ ERROR expected one of `:`
+ a + b + c
+ }
}
fn main() {}
--> $DIR/anon-params-denied-2018.rs:6:15
|
LL | fn foo(i32);
- | ---^ expected one of `:` or `@` here
- | |
- | help: explicitly ignore parameter: `_: i32`
+ | ^ expected one of `:` or `@` here
|
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn foo(i32: TypeName);
+ | ^^^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn foo(_: i32);
+ | ^^^^^^
error: expected one of `:` or `@`, found `,`
--> $DIR/anon-params-denied-2018.rs:8:36
|
LL | fn bar_with_default_impl(String, String) {}
- | ------^ expected one of `:` or `@` here
- | |
- | help: explicitly ignore parameter: `_: String`
+ | ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn bar_with_default_impl(String: TypeName, String) {}
+ | ^^^^^^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn bar_with_default_impl(_: String, String) {}
+ | ^^^^^^^^^
+
+error: expected one of `:` or `@`, found `)`
+ --> $DIR/anon-params-denied-2018.rs:8:44
+ |
+LL | fn bar_with_default_impl(String, String) {}
+ | ^ expected one of `:` or `@` here
|
= note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn bar_with_default_impl(String, String: TypeName) {}
+ | ^^^^^^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn bar_with_default_impl(String, _: String) {}
+ | ^^^^^^^^^
+
+error: expected one of `:` or `@`, found `,`
+ --> $DIR/anon-params-denied-2018.rs:13:22
+ |
+LL | fn baz(a:usize, b, c: usize) -> usize {
+ | ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn baz(a:usize, b: TypeName, c: usize) -> usize {
+ | ^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn baz(a:usize, _: b, c: usize) -> usize {
+ | ^^^^
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
}
}
-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
}
--- /dev/null
+// edition:2018
+#![feature(async_await)]
+
+fn main() {
+}
+
+async fn response(data: Vec<u8>) {
+ data.reverse(); //~ ERROR E0596
+}
--- /dev/null
+error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable
+ --> $DIR/issue-61187.rs:8:5
+ |
+LL | async fn response(data: Vec<u8>) {
+ | ---- help: consider changing this to be mutable: `mut data`
+LL | data.reverse();
+ | ^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
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
+
+trait IsZeroTrait<const IS_ZERO: bool>{}
+
+impl IsZeroTrait<{0u8 == 0u8}> for () {}
+
+impl IsZeroTrait<true> for ((),) {}
+
+fn main() {}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+ --> $DIR/condition-in-trait-const-arg.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
+
+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
--- /dev/null
+#![feature(core_intrinsics)]
+
+fn main() {
+ let (x, y) = (1u32, 2u32);
+ let add = std::intrinsics::unchecked_add(x, y); //~ ERROR call to unsafe function
+ let sub = std::intrinsics::unchecked_sub(x, y); //~ ERROR call to unsafe function
+ let mul = std::intrinsics::unchecked_mul(x, y); //~ ERROR call to unsafe function
+}
--- /dev/null
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/unchecked_math_unsafe.rs:5:15
+ |
+LL | let add = std::intrinsics::unchecked_add(x, y);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/unchecked_math_unsafe.rs:6:15
+ |
+LL | let sub = std::intrinsics::unchecked_sub(x, y);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/unchecked_math_unsafe.rs:7:15
+ |
+LL | let mul = std::intrinsics::unchecked_mul(x, y);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+fn main() {
+ let (x, y) = (1u32, 2u32);
+ unsafe {
+ let add = std::intrinsics::unchecked_add(x, y); //~ ERROR use of unstable library feature
+ let sub = std::intrinsics::unchecked_sub(x, y); //~ ERROR use of unstable library feature
+ let mul = std::intrinsics::unchecked_mul(x, y); //~ ERROR use of unstable library feature
+ }
+}
--- /dev/null
+error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library
+ --> $DIR/unchecked_math_unstable.rs:4:19
+ |
+LL | let add = std::intrinsics::unchecked_add(x, y);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(core_intrinsics)] to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library
+ --> $DIR/unchecked_math_unstable.rs:5:19
+ |
+LL | let sub = std::intrinsics::unchecked_sub(x, y);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(core_intrinsics)] to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'core_intrinsics': intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library
+ --> $DIR/unchecked_math_unstable.rs:6:19
+ |
+LL | let mul = std::intrinsics::unchecked_mul(x, y);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(core_intrinsics)] to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
| ----------- 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
fn main() {
let &v = new();
- //~^ ERROR type annotations needed [E0282]
+ //~^ ERROR type annotations needed
}
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `&T`
--> $DIR/issue-12187-1.rs:6:10
|
LL | let &v = new();
| -^
| ||
| |cannot infer type
- | consider giving the pattern a type
+ | consider giving this pattern the explicit type `&T`, with the type parameters specified
error: aborting due to previous error
fn main() {
let &v = new();
- //~^ ERROR type annotations needed [E0282]
+ //~^ ERROR type annotations needed
}
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `&T`
--> $DIR/issue-12187-2.rs:6:10
|
LL | let &v = new();
| -^
| ||
| |cannot infer type
- | consider giving the pattern a type
+ | consider giving this pattern the explicit type `&T`, with the type parameters specified
error: aborting due to previous error
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `B<T>`
--> $DIR/issue-17551.rs:6:15
|
LL | let foo = B(marker::PhantomData);
| --- ^ cannot infer type for `T`
| |
- | consider giving `foo` a type
+ | consider giving `foo` the explicit type `B<T>`, where the type parameter `T` is specified
error: aborting due to previous error
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `&(_,)`
--> $DIR/issue-20261.rs:4:11
|
LL | for (ref i,) in [].iter() {
--- /dev/null
+fn main() {
+ let x = 8u8;
+ let z: *const u8 = &x;
+ println!("{}", z.to_string()); //~ ERROR E0599
+}
--- /dev/null
+error[E0599]: no method named `to_string` found for type `*const u8` in the current scope
+ --> $DIR/issue-21596.rs:4:22
+ |
+LL | println!("{}", z.to_string());
+ | ^^^^^^^^^
+ |
+ = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref
+ = note: the method `to_string` exists but the following trait bounds were not satisfied:
+ `*const u8 : std::string::ToString`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
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
|
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `Expr<'_, VAR>`
--> $DIR/issue-23046.rs:17:15
|
LL | let ex = |x| {
- | ^ consider giving this closure parameter a type
+ | ^ consider giving this closure parameter the explicit type `Expr<'_, VAR>`, where the type parameter `VAR` is specified
error: aborting due to previous error
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `(std::sync::mpsc::Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`
--> $DIR/issue-25368.rs:11:17
|
LL | let (tx, rx) = channel();
- | -------- consider giving the pattern a type
+ | -------- consider giving this pattern the explicit type `(std::sync::mpsc::Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`, where the type parameter `T` is specified
...
LL | tx.send(Foo{ foo: PhantomData });
| ^^^ cannot infer type for `T`
-// 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
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `&[_; 0]`
--> $DIR/issue-7813.rs:2:13
|
LL | let v = &[];
| - ^^^ cannot infer type
| |
- | consider giving `v` a type
+ | consider giving `v` the explicit type `&[_; 0]`, with the type parameters specified
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
--- /dev/null
+#![deny(unused_must_use)]
+
+fn foo() -> (Result<(), ()>, ()) {
+ (Ok::<(), ()>(()), ())
+}
+
+fn main() {
+ (Ok::<(), ()>(()),); //~ ERROR unused `std::result::Result`
+
+ (Ok::<(), ()>(()), 0, Ok::<(), ()>(()), 5);
+ //~^ ERROR unused `std::result::Result`
+ //~^^ ERROR unused `std::result::Result`
+
+ foo(); //~ ERROR unused `std::result::Result`
+
+ ((Err::<(), ()>(()), ()), ()); //~ ERROR unused `std::result::Result`
+}
--- /dev/null
+error: unused `std::result::Result` in tuple element 0 that must be used
+ --> $DIR/must_use-tuple.rs:8:6
+ |
+LL | (Ok::<(), ()>(()),);
+ | ^^^^^^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/must_use-tuple.rs:1:9
+ |
+LL | #![deny(unused_must_use)]
+ | ^^^^^^^^^^^^^^^
+ = note: this `Result` may be an `Err` variant, which should be handled
+
+error: unused `std::result::Result` in tuple element 0 that must be used
+ --> $DIR/must_use-tuple.rs:10:6
+ |
+LL | (Ok::<(), ()>(()), 0, Ok::<(), ()>(()), 5);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: this `Result` may be an `Err` variant, which should be handled
+
+error: unused `std::result::Result` in tuple element 2 that must be used
+ --> $DIR/must_use-tuple.rs:10:27
+ |
+LL | (Ok::<(), ()>(()), 0, Ok::<(), ()>(()), 5);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: this `Result` may be an `Err` variant, which should be handled
+
+error: unused `std::result::Result` in tuple element 0 that must be used
+ --> $DIR/must_use-tuple.rs:14:5
+ |
+LL | foo();
+ | ^^^^^^
+ |
+ = note: this `Result` may be an `Err` variant, which should be handled
+
+error: unused `std::result::Result` in tuple element 0 that must be used
+ --> $DIR/must_use-tuple.rs:16:6
+ |
+LL | ((Err::<(), ()>(()), ()), ());
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this `Result` may be an `Err` variant, which should be handled
+
+error: aborting due to 5 previous errors
+
--> $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!
fn m1() {
// we couldn't infer the type of the vector just based on calling foo()...
let mut x = Vec::new();
- //~^ ERROR type annotations needed [E0282]
+ //~^ ERROR type annotations needed
x.foo();
}
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `std::vec::Vec<T>`
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17
|
LL | let mut x = Vec::new();
| ----- ^^^^^^^^ cannot infer type for `T`
| |
- | consider giving `x` a type
+ | consider giving `x` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
error[E0308]: mismatched types
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20
= 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!(),
}
}
--- /dev/null
+#![deny(unused_mut)]
+
+fn main() {
+ let mut x; //~ ERROR: variable does not need to be mutable
+ x = String::new();
+ dbg!(x);
+}
--- /dev/null
+error: variable does not need to be mutable
+ --> $DIR/issue-61424.rs:4:9
+ |
+LL | let mut x;
+ | ----^
+ | |
+ | help: remove this `mut`
+ |
+note: lint level defined here
+ --> $DIR/issue-61424.rs:1:9
+ |
+LL | #![deny(unused_mut)]
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
-// 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
| ^^^^^^^^^^^^
fn fizz(i32) {}
//~^ ERROR expected one of `:` or `@`
+//~| HELP if this was a parameter name, give it a type
+//~| HELP if this is a type, explicitly ignore the parameter name
fn missing_colon(quux S) {}
//~^ ERROR expected one of `:` or `@`
|
LL | fn fizz(i32) {}
| ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn fizz(i32: TypeName) {}
+ | ^^^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn fizz(_: i32) {}
+ | ^^^^^^
error: expected one of `:` or `@`, found `S`
- --> $DIR/inverted-parameters.rs:24:23
+ --> $DIR/inverted-parameters.rs:26:23
|
LL | fn missing_colon(quux S) {}
| -----^
-// 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
|
LL | fn foo(x) {
| ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn foo(x: TypeName) {
+ | ^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn foo(_: x) {
+ | ^^^^
error: aborting due to previous error
-// 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
|
LL | fn foo(Option<i32>, String) {}
| ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn foo(Option<i32>, String: TypeName) {}
+ | ^^^^^^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn foo(Option<i32>, _: String) {}
+ | ^^^^^^^^^
error: expected one of `:` or `@`, found `,`
--> $DIR/issue-34264.rs:3:9
|
LL | fn bar(x, y: usize) {}
| ^ expected one of `:` or `@` here
+ |
+ = note: anonymous parameters are removed in the 2018 edition (see RFC 1685)
+help: if this was a parameter name, give it a type
+ |
+LL | fn bar(x: TypeName, y: usize) {}
+ | ^^^^^^^^^^^
+help: if this is a type, explicitly ignore the parameter name
+ |
+LL | fn bar(_: x, y: usize) {}
+ | ^^^^
error[E0061]: this function takes 2 parameters but 3 parameters were supplied
--> $DIR/issue-34264.rs:7:5
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `std::option::Option<_>`
--> $DIR/issue-42234-unknown-receiver-type.rs:7:5
|
LL | let x: Option<_> = None;
- | - consider giving `x` a type
+ | - consider giving `x` the explicit type `std::option::Option<_>`, where the type parameter `T` is specified
LL | x.unwrap().method_that_could_exist_on_some_type();
| ^^^^^^^^^^ cannot infer type for `T`
|
-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
|
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `[_; 0]`
--> $DIR/cannot_infer_local_or_array.rs:2:13
|
LL | let x = [];
| - ^^ cannot infer type
| |
- | consider giving `x` a type
+ | consider giving `x` the explicit type `[_; 0]`, with the type parameters specified
error: aborting due to previous error
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `std::vec::Vec<T>`
--> $DIR/cannot_infer_local_or_vec.rs:2:13
|
LL | let x = vec![];
| - ^^^^^^ cannot infer type for `T`
| |
- | consider giving `x` a type
+ | consider giving `x` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `(std::vec::Vec<T>,)`
--> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18
|
LL | let (x, ) = (vec![], );
| ----- ^^^^^^ cannot infer type for `T`
| |
- | consider giving the pattern a type
+ | consider giving this pattern the explicit type `(std::vec::Vec<T>,)`, where the type parameter `T` is specified
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `std::option::Option<T>`
--> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32
|
LL | let mut closure0 = None;
- | ------------ consider giving `closure0` a type
+ | ------------ consider giving `closure0` the explicit type `std::option::Option<T>`, with the type parameters specified
...
LL | return c();
| ^^^ cannot infer type
LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y }
| ^^ expected lifetime parameter
|
- = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_` or `y`
+ = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or `y`
error: aborting due to 5 previous errors
fn main() {
let _foo = Vec::new();
- //~^ ERROR type annotations needed [E0282]
+ //~^ ERROR type annotations needed
}
-error[E0282]: type annotations needed
+error[E0282]: type annotations needed for `std::vec::Vec<T>`
--> $DIR/vector-no-ann.rs:2:16
|
LL | let _foo = Vec::new();
| ---- ^^^^^^^^ cannot infer type for `T`
| |
- | consider giving `_foo` a type
+ | consider giving `_foo` the explicit type `std::vec::Vec<T>`, where the type parameter `T` is specified
error: aborting due to previous error
-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"),
succeeds_non_ident && preceeds_whitespace_and_paren
});
- cfgs.map(|i| {
+ cfgs.flat_map(|i| {
let mut depth = 0;
let contents_from = &contents[i..];
for (j, byte) in contents_from.bytes().enumerate() {
b')' => {
depth -= 1;
if depth == 0 {
- return (i, &contents_from[..=j]);
+ return Some((i, &contents_from[..=j]));
}
}
_ => { }
}
}
- unreachable!()
+ // if the parentheses are unbalanced just ignore this cfg -- it'll be caught when attempting
+ // to run the compiler, and there's no real reason to lint it separately here
+ None
}).collect()
}